1
mirror of https://github.com/mpv-player/mpv synced 2025-01-01 04:36:24 +01:00

Improved subtitle queueing, parameters (start_pts, end_pts, palette, alpha)

are now also queued.


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9449 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
ranma 2003-02-16 15:26:30 +00:00
parent 33d9de542e
commit fbb78cf957

372
spudec.c
View File

@ -42,22 +42,31 @@ extern int sub_pos;
typedef struct packet_t packet_t; typedef struct packet_t packet_t;
struct packet_t { struct packet_t {
unsigned char *data; unsigned char *packet;
unsigned int process_pts; /* When to process the packet */ unsigned int palette[4];
size_t reserve; /* size of the memory pointed to by packet */ unsigned int alpha[4];
unsigned int offset; /* end of the currently assembled fragment */ unsigned int control_start; /* index of start of control data */
unsigned int size; /* size of the packet once all fragments are assembled */ unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
unsigned int fragment_pts; /* PTS of the last fragment for this packet */ processed (for RLE decoding) for
unsigned int control_start; /* index of start of control data */ even and odd lines */
int deinterlace_oddness; /* 0 or 1, index into current_nibble */
unsigned int start_col, end_col;
unsigned int start_row, end_row;
unsigned int width, height, stride;
unsigned int start_pts, end_pts;
packet_t *next; packet_t *next;
}; };
typedef struct { typedef struct {
packet_t *packets; /* Linked list of packets sorted by process_pts */ packet_t *queue_head;
packet_t *last_packet; /* Last packet in linked list */ packet_t *queue_tail;
unsigned int global_palette[16]; unsigned int global_palette[16];
unsigned int orig_frame_width, orig_frame_height; unsigned int orig_frame_width, orig_frame_height;
unsigned char* packet;
size_t packet_reserve; /* size of the memory pointed to by packet */
unsigned int packet_offset; /* end of the currently assembled fragment */
unsigned int packet_size; /* size of the packet once all fragments are assembled */
unsigned int packet_pts; /* PTS for this packet */
unsigned int palette[4]; unsigned int palette[4];
unsigned int alpha[4]; unsigned int alpha[4];
unsigned int cuspal[4]; unsigned int cuspal[4];
@ -67,10 +76,6 @@ typedef struct {
unsigned int start_col, end_col; unsigned int start_col, end_col;
unsigned int start_row, end_row; unsigned int start_row, end_row;
unsigned int width, height, stride; unsigned int width, height, stride;
unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
processed (for RLE decoding) for
even and odd lines */
int deinterlace_oddness; /* 0 or 1, index into current_nibble */
size_t image_size; /* Size of the image buffer */ size_t image_size; /* Size of the image buffer */
unsigned char *image; /* Grayscale value */ unsigned char *image; /* Grayscale value */
unsigned char *aimage; /* Alpha value */ unsigned char *aimage; /* Alpha value */
@ -86,46 +91,31 @@ typedef struct {
int spu_changed; int spu_changed;
} spudec_handle_t; } spudec_handle_t;
/* Add packet to end of list */ static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
static void spudec_append_packet (spudec_handle_t *this, packet_t *packet)
{ {
packet->next = NULL; if (this->queue_head == NULL)
if (this->last_packet == NULL) this->queue_head = packet;
this->packets = packet;
else else
this->last_packet->next = packet; this->queue_tail->next = packet;
this->queue_tail = packet;
this->last_packet = packet;
} }
/* Add a new packet to end of the list */ static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
static void spudec_append_new_packet (spudec_handle_t *this)
{ {
packet_t *new_packet = calloc (1, sizeof (packet_t)); packet_t *retval = this->queue_head;
/* Do not process packet yet, so set process time way into the future */ this->queue_head = retval->next;
new_packet->process_pts = -1L; if (this->queue_head == NULL)
this->queue_tail = NULL;
spudec_append_packet (this, new_packet); return retval;
} }
/* Remove top-most packet and free the memory it used */ static void spudec_free_packet(packet_t *packet)
static void spudec_pop_packet (spudec_handle_t *this)
{ {
packet_t *temp; if (packet->packet != NULL)
free(packet->packet);
if (this->packets != NULL) free(packet);
{
temp = this->packets;
this->packets = temp->next;
if (temp->data != NULL)
free (temp->data);
free (temp);
/* Null last packet pointer if there are no packets in the queue */
if (this->packets == NULL)
this->last_packet = NULL;
}
} }
static inline unsigned int get_be16(const unsigned char *p) static inline unsigned int get_be16(const unsigned char *p)
@ -138,22 +128,22 @@ static inline unsigned int get_be24(const unsigned char *p)
return (get_be16(p) << 8) + p[2]; return (get_be16(p) << 8) + p[2];
} }
static void next_line(spudec_handle_t *this) static void next_line(packet_t *packet)
{ {
if (this->current_nibble[this->deinterlace_oddness] % 2) if (packet->current_nibble[packet->deinterlace_oddness] % 2)
this->current_nibble[this->deinterlace_oddness]++; packet->current_nibble[packet->deinterlace_oddness]++;
this->deinterlace_oddness = (this->deinterlace_oddness + 1) % 2; packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
} }
static inline unsigned char get_nibble(spudec_handle_t *this, packet_t *packet) static inline unsigned char get_nibble(packet_t *packet)
{ {
unsigned char nib; unsigned char nib;
unsigned int *nibblep = this->current_nibble + this->deinterlace_oddness; unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
if (*nibblep / 2 >= packet->control_start) { if (*nibblep / 2 >= packet->control_start) {
mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n"); mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
return 0; return 0;
} }
nib = packet->data[*nibblep / 2]; nib = packet->packet[*nibblep / 2];
if (*nibblep % 2) if (*nibblep % 2)
nib &= 0xf; nib &= 0xf;
else else
@ -200,9 +190,11 @@ static inline void spudec_cut_image(spudec_handle_t *this)
this->height = last_y - first_y +1; this->height = last_y - first_y +1;
} else { } else {
this->height = 0; this->height = 0;
this->image_size = 0;
return;
} }
//printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride); // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
image = malloc(2 * this->stride * this->height); image = malloc(2 * this->stride * this->height);
if(image){ if(image){
@ -223,11 +215,17 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
unsigned int cmap[4], alpha[4]; unsigned int cmap[4], alpha[4];
unsigned int i, x, y; unsigned int i, x, y;
this->deinterlace_oddness = 0;
this->scaled_frame_width = 0; this->scaled_frame_width = 0;
this->scaled_frame_height = 0; this->scaled_frame_height = 0;
this->start_col = packet->start_col;
this->end_col = packet->end_col;
this->start_row = packet->start_row;
this->end_row = packet->end_row;
this->height = packet->height;
this->width = packet->width;
this->stride = packet->stride;
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
alpha[i] = mkalpha(this->alpha[i]); alpha[i] = mkalpha(packet->alpha[i]);
if (alpha[i] == 0) if (alpha[i] == 0)
cmap[i] = 0; cmap[i] = 0;
else if (this->custom){ else if (this->custom){
@ -236,7 +234,7 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
cmap[i] = 256 - alpha[i]; cmap[i] = 256 - alpha[i];
} }
else { else {
cmap[i] = ((this->global_palette[this->palette[i]] >> 16) & 0xff); cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
if (cmap[i] + alpha[i] > 255) if (cmap[i] + alpha[i] > 255)
cmap[i] = 256 - alpha[i]; cmap[i] = 256 - alpha[i];
} }
@ -264,21 +262,21 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
memset(this->image + y * this->stride + this->width, 0, this->stride - this->width); memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
} }
i = this->current_nibble[1]; i = packet->current_nibble[1];
x = 0; x = 0;
y = 0; y = 0;
while (this->current_nibble[0] < i while (packet->current_nibble[0] < i
&& this->current_nibble[1] / 2 < packet->control_start && packet->current_nibble[1] / 2 < packet->control_start
&& y < this->height) { && y < this->height) {
unsigned int len, color; unsigned int len, color;
unsigned int rle = 0; unsigned int rle = 0;
rle = get_nibble(this, packet); rle = get_nibble(packet);
if (rle < 0x04) { if (rle < 0x04) {
rle = (rle << 4) | get_nibble(this, packet); rle = (rle << 4) | get_nibble(packet);
if (rle < 0x10) { if (rle < 0x10) {
rle = (rle << 4) | get_nibble(this, packet); rle = (rle << 4) | get_nibble(packet);
if (rle < 0x040) { if (rle < 0x040) {
rle = (rle << 4) | get_nibble(this, packet); rle = (rle << 4) | get_nibble(packet);
if (rle < 0x0004) if (rle < 0x0004)
rle |= ((this->width - x) << 2); rle |= ((this->width - x) << 2);
} }
@ -293,7 +291,7 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
memset(this->aimage + y * this->stride + x, alpha[color], len); memset(this->aimage + y * this->stride + x, alpha[color], len);
x += len; x += len;
if (x >= this->width) { if (x >= this->width) {
next_line(this); next_line(packet);
x = 0; x = 0;
++y; ++y;
} }
@ -309,14 +307,14 @@ gray scale values to each color.
I tested it with four streams and even got something readable. Half of the I tested it with four streams and even got something readable. Half of the
times I got black characters with white around and half the reverse. times I got black characters with white around and half the reverse.
*/ */
static void compute_palette(spudec_handle_t *this) static void compute_palette(spudec_handle_t *this, packet_t *packet)
{ {
int used[16],i,cused,start,step,color; int used[16],i,cused,start,step,color;
memset(used, 0, sizeof(used)); memset(used, 0, sizeof(used));
for (i=0; i<4; i++) for (i=0; i<4; i++)
if (this->alpha[i]) /* !Transparent? */ if (packet->alpha[i]) /* !Transparent? */
used[this->palette[i]] = 1; used[packet->palette[i]] = 1;
for (cused=0, i=0; i<16; i++) for (cused=0, i=0; i<16; i++)
if (used[i]) cused++; if (used[i]) cused++;
if (!cused) return; if (!cused) return;
@ -329,8 +327,8 @@ static void compute_palette(spudec_handle_t *this)
} }
memset(used, 0, sizeof(used)); memset(used, 0, sizeof(used));
for (i=0; i<4; i++) { for (i=0; i<4; i++) {
color = this->palette[i]; color = packet->palette[i];
if (this->alpha[i] && !used[color]) { /* not assigned? */ if (packet->alpha[i] && !used[color]) { /* not assigned? */
used[color] = 1; used[color] = 1;
this->global_palette[color] = start<<16; this->global_palette[color] = start<<16;
start += step; start += step;
@ -338,24 +336,35 @@ static void compute_palette(spudec_handle_t *this)
} }
} }
static void spudec_process_control(spudec_handle_t *this, packet_t *packet) static void spudec_process_control(spudec_handle_t *this, unsigned int pts100)
{ {
int a,b; /* Temporary vars */ int a,b; /* Temporary vars */
unsigned int date, type; unsigned int date, type;
unsigned int off; unsigned int off;
unsigned int start_off = 0; unsigned int start_off = 0;
unsigned int next_off; unsigned int next_off;
unsigned int pts100 = packet->process_pts; unsigned int start_pts;
unsigned int end_pts;
unsigned int current_nibble[2];
unsigned int control_start;
unsigned int display = 0;
unsigned int start_col = 0;
unsigned int end_col = 0;
unsigned int start_row = 0;
unsigned int end_row = 0;
unsigned int width = 0;
unsigned int height = 0;
unsigned int stride = 0;
packet->control_start = get_be16(packet->data + 2); control_start = get_be16(this->packet + 2);
next_off = packet->control_start; next_off = control_start;
while (start_off != next_off) { while (start_off != next_off) {
start_off = next_off; start_off = next_off;
date = get_be16(packet->data + start_off) * 1024; date = get_be16(this->packet + start_off) * 1024;
next_off = get_be16(packet->data + start_off + 2); next_off = get_be16(this->packet + start_off + 2);
mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date); mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
off = start_off + 4; off = start_off + 4;
for (type = packet->data[off++]; type != 0xff; type = packet->data[off++]) { for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type); mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
switch(type) { switch(type) {
case 0x00: case 0x00:
@ -368,60 +377,57 @@ static void spudec_process_control(spudec_handle_t *this, packet_t *packet)
case 0x01: case 0x01:
/* Start display */ /* Start display */
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n"); mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
this->start_pts = pts100 + date; start_pts = pts100 + date;
this->end_pts = UINT_MAX; end_pts = UINT_MAX;
display = 1;
break; break;
case 0x02: case 0x02:
/* Stop display */ /* Stop display */
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n"); mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
this->end_pts = pts100 + date; end_pts = pts100 + date;
break; break;
case 0x03: case 0x03:
/* Palette */ /* Palette */
this->palette[0] = packet->data[off] >> 4; this->palette[0] = this->packet[off] >> 4;
this->palette[1] = packet->data[off] & 0xf; this->palette[1] = this->packet[off] & 0xf;
this->palette[2] = packet->data[off + 1] >> 4; this->palette[2] = this->packet[off + 1] >> 4;
this->palette[3] = packet->data[off + 1] & 0xf; this->palette[3] = this->packet[off + 1] & 0xf;
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n", mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
this->palette[0], this->palette[1], this->palette[2], this->palette[3]); this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
off+=2; off+=2;
break; break;
case 0x04: case 0x04:
/* Alpha */ /* Alpha */
this->alpha[0] = packet->data[off] >> 4; this->alpha[0] = this->packet[off] >> 4;
this->alpha[1] = packet->data[off] & 0xf; this->alpha[1] = this->packet[off] & 0xf;
this->alpha[2] = packet->data[off + 1] >> 4; this->alpha[2] = this->packet[off + 1] >> 4;
this->alpha[3] = packet->data[off + 1] & 0xf; this->alpha[3] = this->packet[off + 1] & 0xf;
if (this->auto_palette) {
compute_palette(this);
this->auto_palette = 0;
}
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n", mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]); this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
off+=2; off+=2;
break; break;
case 0x05: case 0x05:
/* Co-ords */ /* Co-ords */
a = get_be24(packet->data + off); a = get_be24(this->packet + off);
b = get_be24(packet->data + off + 3); b = get_be24(this->packet + off + 3);
this->start_col = a >> 12; start_col = a >> 12;
this->end_col = a & 0xfff; end_col = a & 0xfff;
this->width = (this->end_col < this->start_col) ? 0 : this->end_col - this->start_col + 1; width = (end_col < start_col) ? 0 : end_col - start_col + 1;
this->stride = (this->width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */ stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
this->start_row = b >> 12; start_row = b >> 12;
this->end_row = b & 0xfff; end_row = b & 0xfff;
this->height = (this->end_row < this->start_row) ? 0 : this->end_row - this->start_row /* + 1 */; height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n", mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
this->start_col, this->end_col, this->start_row, this->end_row, start_col, end_col, start_row, end_row,
this->width, this->height); width, height);
off+=6; off+=6;
break; break;
case 0x06: case 0x06:
/* Graphic lines */ /* Graphic lines */
this->current_nibble[0] = 2 * get_be16(packet->data + off); current_nibble[0] = 2 * get_be16(this->packet + off);
this->current_nibble[1] = 2 * get_be16(packet->data + off + 2); current_nibble[1] = 2 * get_be16(this->packet + off + 2);
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n", mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
this->current_nibble[0] / 2, this->current_nibble[1] / 2); current_nibble[0] / 2, current_nibble[1] / 2);
off+=4; off+=4;
break; break;
case 0xff: case 0xff:
@ -436,24 +442,46 @@ static void spudec_process_control(spudec_handle_t *this, packet_t *packet)
} }
} }
next_control: next_control:
; if (display) {
packet_t *packet = calloc(1, sizeof(packet_t));
int i;
packet->start_pts = start_pts;
if (end_pts == UINT_MAX && start_off != next_off) {
start_pts = pts100 + get_be16(this->packet + next_off) * 1024;
packet->end_pts = start_pts - 1;
} else packet->end_pts = end_pts;
packet->current_nibble[0] = current_nibble[0];
packet->current_nibble[1] = current_nibble[1];
packet->start_row = start_row;
packet->end_row = end_row;
packet->start_col = start_col;
packet->end_col = end_col;
packet->width = width;
packet->height = height;
packet->stride = stride;
packet->control_start = control_start;
for (i=0; i<4; i++) {
packet->alpha[i] = this->alpha[i];
packet->palette[i] = this->palette[i];
}
packet->packet = malloc(this->packet_size);
memcpy(packet->packet, this->packet, this->packet_size);
spudec_queue_packet(this, packet);
}
} }
} }
static void spudec_decode(spudec_handle_t *this, packet_t *queued_packet) static void spudec_decode(spudec_handle_t *this, unsigned int pts100)
{ {
if(this->hw_spu) { if(this->hw_spu) {
static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 }; static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
static vo_mpegpes_t *pkg=&packet; static vo_mpegpes_t *pkg=&packet;
packet.data = queued_packet->data; packet.data = this->packet;
packet.size = queued_packet->size; packet.size = this->packet_size;
packet.timestamp = queued_packet->process_pts; packet.timestamp = pts100;
this->hw_spu->draw_frame((uint8_t**)&pkg); this->hw_spu->draw_frame((uint8_t**)&pkg);
} else { } else
spudec_process_control(this, queued_packet); spudec_process_control(this, pts100);
spudec_process_data(this, queued_packet);
}
this->spu_changed = 1;
} }
int spudec_changed(void * this) int spudec_changed(void * this)
@ -462,88 +490,80 @@ int spudec_changed(void * this)
return (spu->spu_changed || spu->now_pts > spu->end_pts); return (spu->spu_changed || spu->now_pts > spu->end_pts);
} }
void spudec_assemble(void *this, unsigned char *packet_bytes, unsigned int len, unsigned int pts100) void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100)
{ {
spudec_handle_t *spu = (spudec_handle_t*)this; spudec_handle_t *spu = (spudec_handle_t*)this;
packet_t *last_packet;
/* Create a new packet if one doesn't exist in the queue */
if (spu->last_packet == NULL)
spudec_append_new_packet (spu);
last_packet = spu->last_packet;
// spudec_heartbeat(this, pts100); // spudec_heartbeat(this, pts100);
if (len < 2) { if (len < 2) {
mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n"); mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
return; return;
} }
if ((last_packet->fragment_pts + 10000) < pts100) { if ((spu->packet_pts + 10000) < pts100) {
// [cb] too long since last fragment: force new packet // [cb] too long since last fragment: force new packet
last_packet->offset = 0; spu->packet_offset = 0;
} }
last_packet->fragment_pts = pts100; spu->packet_pts = pts100;
if (last_packet->offset == 0) { if (spu->packet_offset == 0) {
unsigned int len2 = get_be16(packet_bytes); unsigned int len2 = get_be16(packet);
// Start new fragment // Start new fragment
if (last_packet->reserve < len2) { if (spu->packet_reserve < len2) {
if (last_packet->data != NULL) if (spu->packet != NULL)
free(last_packet->data); free(spu->packet);
last_packet->data = malloc(len2); spu->packet = malloc(len2);
last_packet->reserve = last_packet->data != NULL ? len2 : 0; spu->packet_reserve = spu->packet != NULL ? len2 : 0;
} }
if (last_packet->data != NULL) { if (spu->packet != NULL) {
last_packet->size = len2; spu->packet_size = len2;
if (len > len2) { if (len > len2) {
mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2); mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
return; return;
} }
memcpy(last_packet->data, packet_bytes, len); memcpy(spu->packet, packet, len);
last_packet->offset = len; spu->packet_offset = len;
spu->packet_pts = pts100;
} }
} else { } else {
// Continue current fragment // Continue current fragment
if (last_packet->size < last_packet->offset + len){ if (spu->packet_size < spu->packet_offset + len){
mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n"); mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
last_packet->size = last_packet->offset = 0; spu->packet_size = spu->packet_offset = 0;
return; return;
} else { } else {
memcpy(last_packet->data + last_packet->offset, packet_bytes, len); memcpy(spu->packet + spu->packet_offset, packet, len);
last_packet->offset += len; spu->packet_offset += len;
} }
} }
#if 1 #if 1
// check if we have a complete packet (unfortunatelly packet_size is bad // check if we have a complete packet (unfortunatelly packet_size is bad
// for some disks) // for some disks)
// [cb] packet_size is padded to be even -> may be one byte too long // [cb] packet_size is padded to be even -> may be one byte too long
if ((last_packet->offset == last_packet->size) || if ((spu->packet_offset == spu->packet_size) ||
((last_packet->offset + 1) == last_packet->size)){ ((spu->packet_offset + 1) == spu->packet_size)){
unsigned int x=0,y; unsigned int x=0,y;
while(x+4<=last_packet->offset) { while(x+4<=spu->packet_offset){
y=get_be16(last_packet->data+x+2); // next control pointer y=get_be16(spu->packet+x+2); // next control pointer
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,last_packet->offset,last_packet->size); mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
if(x>=4 && x==y){ // if it points to self - we're done! if(x>=4 && x==y){ // if it points to self - we're done!
// we got it! // we got it!
mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",last_packet->offset,last_packet->size); mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
break; spudec_decode(spu, pts100);
spu->packet_offset = 0;
break;
} }
if(y<=x || y>=last_packet->size){ // invalid? if(y<=x || y>=spu->packet_size){ // invalid?
mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x); mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
last_packet->size = last_packet->offset = 0; spu->packet_size = spu->packet_offset = 0;
return; break;
} }
x=y; x=y;
} }
// [cb] packet is done; start new packet
/* Packet is done. Schedule time to process it and start a new one. */ spu->packet_offset = 0;
last_packet->process_pts = last_packet->fragment_pts;
spudec_append_new_packet (spu);
} }
#else #else
if (spu->packet_offset == spu->packet_size) { if (spu->packet_offset == spu->packet_size) {
/* Packet is done. Schedule time to process it and start a new one. */ spudec_decode(spu, pts100);
last_packet->process_pts = last_packet->fragment_pts; spu->packet_offset = 0;
spudec_append_new_packet (spu);
} }
#endif #endif
} }
@ -551,27 +571,35 @@ void spudec_assemble(void *this, unsigned char *packet_bytes, unsigned int len,
void spudec_reset(void *this) // called after seek void spudec_reset(void *this) // called after seek
{ {
spudec_handle_t *spu = (spudec_handle_t*)this; spudec_handle_t *spu = (spudec_handle_t*)this;
while (spu->queue_head)
spudec_free_packet(spudec_dequeue_packet(spu));
spu->now_pts = 0; spu->now_pts = 0;
while (spu->packets != NULL) spu->end_pts = 0;
spudec_pop_packet (spu); spu->packet_size = spu->packet_offset = 0;
} }
void spudec_heartbeat(void *this, unsigned int pts100) void spudec_heartbeat(void *this, unsigned int pts100)
{ {
spudec_handle_t *spu = (spudec_handle_t*) this; spudec_handle_t *spu = (spudec_handle_t*) this;
spu->now_pts = pts100; spu->now_pts = pts100;
/* Process queued instructions for the current beat */ while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
while (spu->packets != NULL && pts100 >= spu->packets->process_pts) packet_t *packet = spudec_dequeue_packet(spu);
{ spu->start_pts = packet->start_pts;
spudec_decode (spu, spu->packets); spu->end_pts = packet->end_pts;
spudec_pop_packet (spu); if (spu->auto_palette)
} compute_palette(spu, packet);
spudec_process_data(spu, packet);
spudec_free_packet(packet);
spu->spu_changed = 1;
}
} }
int spudec_visible(void *this){ int spudec_visible(void *this){
spudec_handle_t *spu = (spudec_handle_t *)this; spudec_handle_t *spu = (spudec_handle_t *)this;
int ret=(spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts); int ret=(spu->start_pts <= spu->now_pts &&
spu->now_pts < spu->end_pts &&
spu->height > 0);
// printf("spu visible: %d \n",ret); // printf("spu visible: %d \n",ret);
return ret; return ret;
} }
@ -1078,7 +1106,7 @@ void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsi
spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t)); spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
if (this){ if (this){
//(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]); //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
this->packets = NULL; this->packet = NULL;
this->image = NULL; this->image = NULL;
this->scaled_image = NULL; this->scaled_image = NULL;
/* XXX Although the video frame is some size, the SPU frame is /* XXX Although the video frame is some size, the SPU frame is
@ -1112,8 +1140,10 @@ void spudec_free(void *this)
{ {
spudec_handle_t *spu = (spudec_handle_t*)this; spudec_handle_t *spu = (spudec_handle_t*)this;
if (spu) { if (spu) {
while (spu->packets != NULL) while (spu->queue_head)
spudec_pop_packet (this); spudec_free_packet(spudec_dequeue_packet(spu));
if (spu->packet)
free(spu->packet);
if (spu->scaled_image) if (spu->scaled_image)
free(spu->scaled_image); free(spu->scaled_image);
if (spu->image) if (spu->image)