From fbb78cf95796c11663bb7b787dc4d6220a85920f Mon Sep 17 00:00:00 2001 From: ranma Date: Sun, 16 Feb 2003 15:26:30 +0000 Subject: [PATCH] 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 --- spudec.c | 372 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 201 insertions(+), 171 deletions(-) diff --git a/spudec.c b/spudec.c index 9206695ba6..b11c3e7f96 100644 --- a/spudec.c +++ b/spudec.c @@ -42,22 +42,31 @@ extern int sub_pos; typedef struct packet_t packet_t; struct packet_t { - unsigned char *data; - unsigned int process_pts; /* When to process the packet */ - size_t reserve; /* size of the memory pointed to by packet */ - unsigned int offset; /* end of the currently assembled fragment */ - unsigned int size; /* size of the packet once all fragments are assembled */ - unsigned int fragment_pts; /* PTS of the last fragment for this packet */ - unsigned int control_start; /* index of start of control data */ + unsigned char *packet; + unsigned int palette[4]; + unsigned int alpha[4]; + unsigned int control_start; /* index of start of control data */ + 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 */ + 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; }; typedef struct { - packet_t *packets; /* Linked list of packets sorted by process_pts */ - packet_t *last_packet; /* Last packet in linked list */ - + packet_t *queue_head; + packet_t *queue_tail; unsigned int global_palette[16]; 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 alpha[4]; unsigned int cuspal[4]; @@ -67,10 +76,6 @@ typedef struct { unsigned int start_col, end_col; unsigned int start_row, end_row; 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 */ unsigned char *image; /* Grayscale value */ unsigned char *aimage; /* Alpha value */ @@ -86,46 +91,31 @@ typedef struct { int spu_changed; } spudec_handle_t; -/* Add packet to end of list */ -static void spudec_append_packet (spudec_handle_t *this, packet_t *packet) +static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet) { - packet->next = NULL; - if (this->last_packet == NULL) - this->packets = packet; + if (this->queue_head == NULL) + this->queue_head = packet; else - this->last_packet->next = packet; - - this->last_packet = packet; + this->queue_tail->next = packet; + this->queue_tail = packet; } -/* Add a new packet to end of the list */ -static void spudec_append_new_packet (spudec_handle_t *this) +static packet_t *spudec_dequeue_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 */ - new_packet->process_pts = -1L; + this->queue_head = retval->next; + 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_pop_packet (spudec_handle_t *this) +static void spudec_free_packet(packet_t *packet) { - packet_t *temp; - - if (this->packets != NULL) - { - 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; - } + if (packet->packet != NULL) + free(packet->packet); + free(packet); } 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]; } -static void next_line(spudec_handle_t *this) +static void next_line(packet_t *packet) { - if (this->current_nibble[this->deinterlace_oddness] % 2) - this->current_nibble[this->deinterlace_oddness]++; - this->deinterlace_oddness = (this->deinterlace_oddness + 1) % 2; + if (packet->current_nibble[packet->deinterlace_oddness] % 2) + packet->current_nibble[packet->deinterlace_oddness]++; + 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 int *nibblep = this->current_nibble + this->deinterlace_oddness; + unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness; if (*nibblep / 2 >= packet->control_start) { mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n"); return 0; } - nib = packet->data[*nibblep / 2]; + nib = packet->packet[*nibblep / 2]; if (*nibblep % 2) nib &= 0xf; else @@ -200,9 +190,11 @@ static inline void spudec_cut_image(spudec_handle_t *this) this->height = last_y - first_y +1; } else { 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); 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 i, x, y; - this->deinterlace_oddness = 0; this->scaled_frame_width = 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) { - alpha[i] = mkalpha(this->alpha[i]); + alpha[i] = mkalpha(packet->alpha[i]); if (alpha[i] == 0) cmap[i] = 0; 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]; } 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) 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); } - i = this->current_nibble[1]; + i = packet->current_nibble[1]; x = 0; y = 0; - while (this->current_nibble[0] < i - && this->current_nibble[1] / 2 < packet->control_start + while (packet->current_nibble[0] < i + && packet->current_nibble[1] / 2 < packet->control_start && y < this->height) { unsigned int len, color; unsigned int rle = 0; - rle = get_nibble(this, packet); + rle = get_nibble(packet); if (rle < 0x04) { - rle = (rle << 4) | get_nibble(this, packet); + rle = (rle << 4) | get_nibble(packet); if (rle < 0x10) { - rle = (rle << 4) | get_nibble(this, packet); + rle = (rle << 4) | get_nibble(packet); if (rle < 0x040) { - rle = (rle << 4) | get_nibble(this, packet); + rle = (rle << 4) | get_nibble(packet); if (rle < 0x0004) 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); x += len; if (x >= this->width) { - next_line(this); + next_line(packet); x = 0; ++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 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; memset(used, 0, sizeof(used)); for (i=0; i<4; i++) - if (this->alpha[i]) /* !Transparent? */ - used[this->palette[i]] = 1; + if (packet->alpha[i]) /* !Transparent? */ + used[packet->palette[i]] = 1; for (cused=0, i=0; i<16; i++) if (used[i]) cused++; if (!cused) return; @@ -329,8 +327,8 @@ static void compute_palette(spudec_handle_t *this) } memset(used, 0, sizeof(used)); for (i=0; i<4; i++) { - color = this->palette[i]; - if (this->alpha[i] && !used[color]) { /* not assigned? */ + color = packet->palette[i]; + if (packet->alpha[i] && !used[color]) { /* not assigned? */ used[color] = 1; this->global_palette[color] = start<<16; 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 */ unsigned int date, type; unsigned int off; unsigned int start_off = 0; 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); - next_off = packet->control_start; + control_start = get_be16(this->packet + 2); + next_off = control_start; while (start_off != next_off) { start_off = next_off; - date = get_be16(packet->data + start_off) * 1024; - next_off = get_be16(packet->data + start_off + 2); + date = get_be16(this->packet + start_off) * 1024; + next_off = get_be16(this->packet + start_off + 2); mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date); 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); switch(type) { case 0x00: @@ -368,60 +377,57 @@ static void spudec_process_control(spudec_handle_t *this, packet_t *packet) case 0x01: /* Start display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n"); - this->start_pts = pts100 + date; - this->end_pts = UINT_MAX; + start_pts = pts100 + date; + end_pts = UINT_MAX; + display = 1; break; case 0x02: /* Stop display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n"); - this->end_pts = pts100 + date; + end_pts = pts100 + date; break; case 0x03: /* Palette */ - this->palette[0] = packet->data[off] >> 4; - this->palette[1] = packet->data[off] & 0xf; - this->palette[2] = packet->data[off + 1] >> 4; - this->palette[3] = packet->data[off + 1] & 0xf; + this->palette[0] = this->packet[off] >> 4; + this->palette[1] = this->packet[off] & 0xf; + this->palette[2] = this->packet[off + 1] >> 4; + this->palette[3] = this->packet[off + 1] & 0xf; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n", this->palette[0], this->palette[1], this->palette[2], this->palette[3]); off+=2; break; case 0x04: /* Alpha */ - this->alpha[0] = packet->data[off] >> 4; - this->alpha[1] = packet->data[off] & 0xf; - this->alpha[2] = packet->data[off + 1] >> 4; - this->alpha[3] = packet->data[off + 1] & 0xf; - if (this->auto_palette) { - compute_palette(this); - this->auto_palette = 0; - } + this->alpha[0] = this->packet[off] >> 4; + this->alpha[1] = this->packet[off] & 0xf; + this->alpha[2] = this->packet[off + 1] >> 4; + this->alpha[3] = this->packet[off + 1] & 0xf; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n", this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]); off+=2; break; case 0x05: /* Co-ords */ - a = get_be24(packet->data + off); - b = get_be24(packet->data + off + 3); - this->start_col = a >> 12; - this->end_col = a & 0xfff; - this->width = (this->end_col < this->start_col) ? 0 : this->end_col - this->start_col + 1; - this->stride = (this->width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */ - this->start_row = b >> 12; - this->end_row = b & 0xfff; - this->height = (this->end_row < this->start_row) ? 0 : this->end_row - this->start_row /* + 1 */; + a = get_be24(this->packet + off); + b = get_be24(this->packet + off + 3); + start_col = a >> 12; + end_col = a & 0xfff; + width = (end_col < start_col) ? 0 : end_col - start_col + 1; + stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */ + start_row = b >> 12; + end_row = b & 0xfff; + 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", - this->start_col, this->end_col, this->start_row, this->end_row, - this->width, this->height); + start_col, end_col, start_row, end_row, + width, height); off+=6; break; case 0x06: /* Graphic lines */ - this->current_nibble[0] = 2 * get_be16(packet->data + off); - this->current_nibble[1] = 2 * get_be16(packet->data + off + 2); + current_nibble[0] = 2 * get_be16(this->packet + off); + current_nibble[1] = 2 * get_be16(this->packet + off + 2); 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; break; case 0xff: @@ -436,24 +442,46 @@ static void spudec_process_control(spudec_handle_t *this, packet_t *packet) } } 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) { static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 }; static vo_mpegpes_t *pkg=&packet; - packet.data = queued_packet->data; - packet.size = queued_packet->size; - packet.timestamp = queued_packet->process_pts; + packet.data = this->packet; + packet.size = this->packet_size; + packet.timestamp = pts100; this->hw_spu->draw_frame((uint8_t**)&pkg); - } else { - spudec_process_control(this, queued_packet); - spudec_process_data(this, queued_packet); - } - this->spu_changed = 1; + } else + spudec_process_control(this, pts100); } int spudec_changed(void * this) @@ -462,88 +490,80 @@ int spudec_changed(void * this) 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; - 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); if (len < 2) { mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n"); return; } - if ((last_packet->fragment_pts + 10000) < pts100) { + if ((spu->packet_pts + 10000) < pts100) { // [cb] too long since last fragment: force new packet - last_packet->offset = 0; + spu->packet_offset = 0; } - last_packet->fragment_pts = pts100; - if (last_packet->offset == 0) { - unsigned int len2 = get_be16(packet_bytes); + spu->packet_pts = pts100; + if (spu->packet_offset == 0) { + unsigned int len2 = get_be16(packet); // Start new fragment - if (last_packet->reserve < len2) { - if (last_packet->data != NULL) - free(last_packet->data); - last_packet->data = malloc(len2); - last_packet->reserve = last_packet->data != NULL ? len2 : 0; + if (spu->packet_reserve < len2) { + if (spu->packet != NULL) + free(spu->packet); + spu->packet = malloc(len2); + spu->packet_reserve = spu->packet != NULL ? len2 : 0; } - if (last_packet->data != NULL) { - last_packet->size = len2; + if (spu->packet != NULL) { + spu->packet_size = len2; if (len > len2) { mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2); return; } - memcpy(last_packet->data, packet_bytes, len); - last_packet->offset = len; + memcpy(spu->packet, packet, len); + spu->packet_offset = len; + spu->packet_pts = pts100; } } else { // 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"); - last_packet->size = last_packet->offset = 0; + spu->packet_size = spu->packet_offset = 0; return; } else { - memcpy(last_packet->data + last_packet->offset, packet_bytes, len); - last_packet->offset += len; + memcpy(spu->packet + spu->packet_offset, packet, len); + spu->packet_offset += len; } } #if 1 // check if we have a complete packet (unfortunatelly packet_size is bad // for some disks) // [cb] packet_size is padded to be even -> may be one byte too long - if ((last_packet->offset == last_packet->size) || - ((last_packet->offset + 1) == last_packet->size)){ + if ((spu->packet_offset == spu->packet_size) || + ((spu->packet_offset + 1) == spu->packet_size)){ unsigned int x=0,y; - while(x+4<=last_packet->offset) { - y=get_be16(last_packet->data+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); + while(x+4<=spu->packet_offset){ + 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,spu->packet_offset,spu->packet_size); if(x>=4 && x==y){ // if it points to self - we're done! // we got it! - mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",last_packet->offset,last_packet->size); - break; + mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size); + 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); - last_packet->size = last_packet->offset = 0; - return; + spu->packet_size = spu->packet_offset = 0; + break; } x=y; } - - /* Packet is done. Schedule time to process it and start a new one. */ - last_packet->process_pts = last_packet->fragment_pts; - spudec_append_new_packet (spu); + // [cb] packet is done; start new packet + spu->packet_offset = 0; } #else if (spu->packet_offset == spu->packet_size) { - /* Packet is done. Schedule time to process it and start a new one. */ - last_packet->process_pts = last_packet->fragment_pts; - spudec_append_new_packet (spu); + spudec_decode(spu, pts100); + spu->packet_offset = 0; } #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 { spudec_handle_t *spu = (spudec_handle_t*)this; + while (spu->queue_head) + spudec_free_packet(spudec_dequeue_packet(spu)); spu->now_pts = 0; - while (spu->packets != NULL) - spudec_pop_packet (spu); + spu->end_pts = 0; + spu->packet_size = spu->packet_offset = 0; } void spudec_heartbeat(void *this, unsigned int pts100) -{ +{ spudec_handle_t *spu = (spudec_handle_t*) this; spu->now_pts = pts100; - /* Process queued instructions for the current beat */ - while (spu->packets != NULL && pts100 >= spu->packets->process_pts) - { - spudec_decode (spu, spu->packets); - spudec_pop_packet (spu); - } + while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) { + packet_t *packet = spudec_dequeue_packet(spu); + spu->start_pts = packet->start_pts; + spu->end_pts = packet->end_pts; + 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){ 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); 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)); if (this){ //(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->scaled_image = NULL; /* 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; if (spu) { - while (spu->packets != NULL) - spudec_pop_packet (this); + while (spu->queue_head) + spudec_free_packet(spudec_dequeue_packet(spu)); + if (spu->packet) + free(spu->packet); if (spu->scaled_image) free(spu->scaled_image); if (spu->image)