Mercurial > mplayer.hg
changeset 3034:24d3dca4e813
DVD sub patch by Kim Minh Kaplan <kmkaplan@selfoffice.com>
author | arpi |
---|---|
date | Tue, 20 Nov 2001 18:36:50 +0000 |
parents | adcdd30d7e7d |
children | 82e3f5b0e860 |
files | libvo/sub.c libvo/sub.h mplayer.c spudec.c spudec.h |
diffstat | 5 files changed, 352 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- a/libvo/sub.c Tue Nov 20 18:34:40 2001 +0000 +++ b/libvo/sub.c Tue Nov 20 18:36:50 2001 +0000 @@ -272,6 +272,12 @@ } } +void *vo_spudec=NULL; + +inline static void vo_draw_spudec(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ + spudec_draw(vo_spudec, draw_alpha); +} + static int draw_alpha_init_flag=0; extern void vo_draw_alpha_init(); @@ -297,5 +303,9 @@ vo_draw_text_progbar(dxs,dys,draw_alpha); } + if(vo_spudec){ + vo_draw_spudec(dxs,dys,draw_alpha); + } + }
--- a/libvo/sub.h Tue Nov 20 18:34:40 2001 +0000 +++ b/libvo/sub.h Tue Nov 20 18:36:50 2001 +0000 @@ -21,6 +21,8 @@ extern subtitle* vo_sub; +extern void* vo_spudec; + #define OSD_PLAY 0x01 #define OSD_PAUSE 0x02 #define OSD_STOP 0x03
--- a/mplayer.c Tue Nov 20 18:34:40 2001 +0000 +++ b/mplayer.c Tue Nov 20 18:36:50 2001 +0000 @@ -249,11 +249,17 @@ #define INITED_GUI 4 #define INITED_GETCH2 8 #define INITED_LIRC 16 +#define INITED_SPUDEC 32 #define INITED_STREAM 64 #define INITED_ALL 0xFFFF void uninit_player(unsigned int mask){ mask=inited_flags&mask; + if (mask&INITED_SPUDEC){ + inited_flags&=~INITED_SPUDEC; + current_module="uninit_spudec"; + spudec_free(vo_spudec); + } if(mask&INITED_VO){ inited_flags&=~INITED_VO; current_module="uninit_vo"; @@ -753,6 +759,11 @@ } /*DSP!! if(dsp) audio_out->control(AOCONTROL_SET_DEVICE,(int)dsp);*/ + current_module="spudec"; + vo_spudec=spudec_new(); + if (vo_spudec!=NULL) + inited_flags|=INITED_SPUDEC; + current_module=NULL; current_module="open_stream"; stream=open_stream(filename,vcd_track,&file_format); @@ -1986,19 +1997,21 @@ #endif // DVD sub: - { unsigned char* packet=NULL; + if(vo_spudec){ + unsigned char* packet=NULL; int len=ds_get_packet_sub(d_dvdsub,&packet); + current_module="spudec"; if(len>=2){ int len2; len2=(packet[0]<<8)+packet[1]; mp_msg(MSGT_CPLAYER,MSGL_V,"\rDVD sub: %d / %d \n",len,len2); - if(len==len2) - spudec_decode(packet,len); - else - mp_msg(MSGT_CPLAYER,MSGL_V,"fragmented dvd-subs not yet supported!!!\n"); - } else if(len>=0) { - mp_msg(MSGT_CPLAYER,MSGL_V,"invalid dvd sub\n"); + spudec_assemble(vo_spudec,packet,len,100*d_video->pts); + } else { + spudec_heartbeat(vo_spudec,100*d_video->pts); + if(len>=0) + mp_msg(MSGT_CPLAYER,MSGL_V,"invalid dvd sub\n"); } + current_module=NULL; } } // while(!eof)
--- a/spudec.c Tue Nov 20 18:34:40 2001 +0000 +++ b/spudec.c Tue Nov 20 18:36:50 2001 +0000 @@ -1,117 +1,333 @@ /* SPUdec.c Skeleton of function spudec_process_controll() is from xine sources. Further works: - LGB,... (yeah, try to improve it and insert your name here! ;-) */ + LGB,... (yeah, try to improve it and insert your name here! ;-) + + Kim Minh Kaplan + implement fragments reassembly, RLE decoding. + image rendering needs to be corrected (see mkcolor & mkalpha). + For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/> + */ + +#include <errno.h> #include <stdio.h> +#include <stdlib.h> #include "spudec.h" +typedef struct { + unsigned char* packet; + size_t packet_reserve; /* size of the memory pointed to by packet */ + int packet_offset; /* end of the currently assembled fragment */ + int packet_size; /* size of the packet once all fragments are assembled */ + int control_start; /* index of start of control data */ + int palette[4]; + int alpha[4]; + int now_pts; + int start_pts, end_pts; + int start_col, end_col; + int start_row, end_row; + int width, height; + 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 */ +} spudec_handle_t; +static inline unsigned int get_be16(const unsigned char *p) +{ + return (p[0] << 8) + p[1]; +} + +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) +{ + if (this->current_nibble[this->deinterlace_oddness] % 2) + this->current_nibble[this->deinterlace_oddness]++; + this->deinterlace_oddness = (this->deinterlace_oddness + 1) % 2; +} + +static inline unsigned char get_nibble(spudec_handle_t *this) +{ + unsigned char nib; + int *nibblep = this->current_nibble + this->deinterlace_oddness; + if (*nibblep / 2 >= this->control_start) { + fprintf(stderr, "ERROR: get_nibble past end of packet\n"); + return 0; + } + nib = this->packet[*nibblep / 2]; + if (*nibblep % 2) + nib &= 0xf; + else + nib >>= 4; + ++*nibblep; + return nib; +} + +static inline int mkalpha(int i) +{ + /* for VO 0 is transparent + 127 is quite dark, but still... + 255 is transparent with color 0, and hum... funny with other colors... + + FIXME, I can't seem to get a good alpha value! + + i is the value read from SPU, from 0 to 15. The function should + return the corresponding alpha value suitable for libvo's + draw_alpha. */ +#if 0 + return (0xf - (i & 0xf)) << 4; +#else + return (i < 8) ? 127 : 0; +#endif +} + +static inline int mkcolor(int i) +{ + /* FIXME, have to get the colormap's RGB values from the IFO */ +#if 0 + switch (i) { + case 15: return 0; + default: return i << 4; + } +#else + return i << 4; +#endif +} + +static void spudec_process_data(spudec_handle_t *this) +{ + int alpha[4] = { + mkalpha(this->alpha[0]), + mkalpha(this->alpha[1]), + mkalpha(this->alpha[2]), + mkalpha(this->alpha[3]) + }; + int cmap[4] = { + mkcolor(this->palette[0]), + mkcolor(this->palette[1]), + mkcolor(this->palette[2]), + mkcolor(this->palette[3]) + }; + int y = 0, x = 0; + + if (this->image_size < this->width * this->height) { + if (this->image != NULL) + free(this->image); + this->image = malloc(2 * this->width * this->height); + if (this->image) { + this->image_size = this->width * this->height; + this->aimage = this->image + this->image_size; + } + } + if (this->image == NULL) + return; + while (this->current_nibble[0] / 2 < this->control_start + && this->current_nibble[1] / 2 < this->control_start + && y < this->height) { + int len, color; + unsigned int rle = 0; + rle = get_nibble(this); + if (rle < 0x04) { + rle = (rle << 4) | get_nibble(this); + if (rle < 0x10) { + rle = (rle << 4) | get_nibble(this); + if (rle < 0x040) { + rle = (rle << 4) | get_nibble(this); + if (rle < 0x0004) + rle |= ((this->width - x) << 2); + } + } + } + color = rle & 0x3; + len = rle >> 2; + if (len > this->width - x) + len = this->width - x; + /* FIXME have to use palette and alpha map*/ + memset(this->image + y * this->width + x, cmap[color], len); + memset(this->aimage + y * this->width + x, alpha[color], len); + x += len; + if (x >= this->width) { + next_line(this); + x = 0; + ++y; + } + } +} + +static void spudec_process_control(spudec_handle_t *this) +{ + int a,b; /* Temporary vars */ + int date, type; + int off; + int start_off = 0; + int next_off; + + this->control_start = get_be16(this->packet + 2); + next_off = this->control_start; + while (start_off != next_off) { + start_off = next_off; + date = get_be16(this->packet + start_off); + next_off = get_be16(this->packet + start_off + 2); + printf("date=%d\n", date); + off = start_off + 4; + for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) { + printf("cmd=%d ",type); + switch(type) { + case 0x00: + /* Menu ID, 1 byte */ + printf("Menu ID\n"); + break; + case 0x01: + /* Start display */ + printf("Start display!\n"); + this->start_pts = this->now_pts + date; + break; + case 0x02: + /* Stop display */ + printf("Stop display!\n"); + this->end_pts = this->now_pts + date; + break; + case 0x03: + /* Palette */ + 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; + printf("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] = 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; + printf("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(this->packet + off); + b = get_be24(this->packet + off + 3); + this->start_col = a >> 12; + this->end_col = a & 0xfff; + this->width = this->end_col - this->start_col + 1; + this->start_row = b >> 12; + this->end_row = b & 0xfff; + this->height = this->end_row - this->start_row + 1; + printf("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); + off+=6; + break; + case 0x06: + /* Graphic lines */ + this->current_nibble[0] = 2 * get_be16(this->packet + off); + this->current_nibble[1] = 2 * get_be16(this->packet + off + 2); + printf("Graphic offset 1: %d offset 2: %d\n", + this->current_nibble[0] / 2, this->current_nibble[1] / 2); + off+=4; + break; + case 0xff: + /* All done, bye-bye */ + printf("Done!\n"); + return; + break; + default: + printf("spudec: Error determining control type 0x%02x.\n",type); + return; + break; + } + + /* printf("spudec: Processsed control type 0x%02x.\n",type); */ + } + } +} + +static void spudec_decode(spudec_handle_t *this) +{ + spudec_process_control(this); + spudec_process_data(this); +} -void spudec_process_control(unsigned char *control, int size, int* d1, int* d2) +void spudec_assemble(void *this, unsigned char *packet, int len, int pts100) { - int off = 2; - int a,b; /* Temporary vars */ - - do { - int type = control[off]; - off++; - printf("cmd=%d ",type); - - switch(type) { - case 0x00: - /* Menu ID, 1 byte */ - printf("Menu ID\n"); - break; - case 0x01: - /* Start display */ - printf("Start display!\n"); -// gSpudec.geom.bIsVisible = 1; - break; - case 0x03: - /* Palette */ - printf("Palette\n"); -// palette[3] = &(gSpudec.clut[(control[off] >> 4)]); -// palette[2] = &(gSpudec.clut[control[off] & 0xf]); -// palette[1] = &(gSpudec.clut[(control[off+1] >> 4)]); -// palette[0] = &(gSpudec.clut[control[off+1] & 0xf]); - off+=2; - break; - case 0x04: - /* Alpha */ - printf("Alpha\n"); -// alpha[3] = control[off] & 0xf0; -// alpha[2] = (control[off] & 0xf) << 4; -// alpha[1] = control[off+1] & 0xf0; -// alpha[0] = (control[off+1] & 0xf) << 4; - off+=2; - break; - case 0x05: - /* Co-ords */ - a = (control[off] << 16) + (control[off+1] << 8) + control[off+2]; - b = (control[off+3] << 16) + (control[off+4] << 8) + control[off+5]; - - printf("Coords col: %d - %d row: %d - %d\n",a >> 12,a & 0xfff,b >> 12,b & 0xfff); - -// gSpudec.geom.start_col = a >> 12; -// gSpudec.geom.end_col = a & 0xfff; -// gSpudec.geom.start_row = b >> 12; -// gSpudec.geom.end_row = b & 0xfff; - - off+=6; - break; - case 0x06: - /* Graphic lines */ - *(d1) = (control[off] << 8) + control[off+1]; - *(d2) = (control[off+2] << 8) + control[off+3]; - printf("Graphic pos color: %d b/w: %d\n",*d1,*d2); - off+=4; - break; - case 0xff: - /* All done, bye-bye */ - printf("Done!\n"); - return; - break; - default: - printf("spudec: Error determining control type 0x%02x.\n",type); - return; - break; + spudec_handle_t *spu = (spudec_handle_t*)this; + spudec_heartbeat(this, pts100); + if (spu->packet_offset == 0) { + unsigned int len2 = get_be16(packet); + // Start new fragment + if (spu->packet_reserve < len2) { + if (spu->packet != NULL) + free(spu->packet); + spu->packet = malloc(len2); + spu->packet_reserve = spu->packet != NULL ? len2 : 0; } - - /* printf("spudec: Processsed control type 0x%02x.\n",type); */ - } while(off < size); + if (spu->packet != NULL) { + spu->deinterlace_oddness = 0; + spu->packet_size = len2; + memcpy(spu->packet, packet, len); + spu->packet_offset = len; + } + } else { + // Continue current fragment + if (spu->packet_size < spu->packet_offset + len) + fprintf(stderr,"invalid fragment\n"); + else { + memcpy(spu->packet + spu->packet_offset, packet, len); + spu->packet_offset += len; + } + } + if (spu->packet_offset == spu->packet_size) { + spudec_decode(spu); + spu->packet_offset = 0; + } } -// SPU packet format: (guess only, by A'rpi) -// 0 word whole packet size -// 2 word x0 sub-packet size -// 4 x0-2 pixel data -// x0+2 word x1 sub-packet size -// x0+4 x1-x0-2 process control data -// x1 word lifetime -// x1+2 word x1 sub-packet size again +void spudec_heartbeat(void *this, int pts100) +{ + ((spudec_handle_t *)this)->now_pts = pts100; +} -void spudec_decode(unsigned char *packet,int len){ - int x0, x1; - int d1, d2; - int lifetime; - x0 = (packet[2] << 8) + packet[3]; - x1 = (packet[x0+2] << 8) + packet[x0+3]; - - /* /Another/ sanity check. */ - if((packet[x1+2]<<8) + packet[x1+3] != x1) { - printf("spudec: Incorrect packet.\n"); - return; - } - lifetime= ((packet[x1]<<8) + packet[x1+1]); - printf("lifetime=%d\n",lifetime); - - d1 = d2 = -1; - spudec_process_control(packet + x0 + 2, x1-x0-2, &d1, &d2); -// if((d1 != -1) && (d2 != -1)) { -// spudec_process_data(packet, x0, d1, d2); -// } +void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)) +{ + spudec_handle_t *spu = (spudec_handle_t *)this; + if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image) + draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height, + spu->image, spu->aimage, spu->width); } +void *spudec_new() +{ + spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t)); + if (this) { + ; + } + else + perror("FATAL: spudec_init: calloc"); + return this; +} + +void spudec_free(void *this) +{ + spudec_handle_t *spu = (spudec_handle_t*)this; + if (spu) { + if (spu->packet) + free(spu->packet); + if (spu->image) + free(spu->image); + free(spu); + } +}
--- a/spudec.h Tue Nov 20 18:34:40 2001 +0000 +++ b/spudec.h Tue Nov 20 18:36:50 2001 +0000 @@ -1,7 +1,10 @@ #ifndef _MPLAYER_SPUDEC_H #define _MPLAYER_SPUDEC_H -void spudec_process_control(unsigned char *, int, int*, int*); -void spudec_decode(unsigned char *packet,int len); +void spudec_heartbeat(void *this, int pts100); +void spudec_assemble(void *this, unsigned char *packet, int len, int pts100); +void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +void *spudec_new(); +void spudec_free(void *this); #endif