summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libvo/sub.c10
-rw-r--r--libvo/sub.h2
-rw-r--r--mplayer.c27
-rw-r--r--spudec.c408
-rw-r--r--spudec.h7
5 files changed, 349 insertions, 105 deletions
diff --git a/libvo/sub.c b/libvo/sub.c
index 72e2a836bc..77934a691b 100644
--- a/libvo/sub.c
+++ b/libvo/sub.c
@@ -272,6 +272,12 @@ inline static void vo_draw_text_sub(int dxs,int dys,void (*draw_alpha)(int x0,in
}
}
+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 @@ void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h,
vo_draw_text_progbar(dxs,dys,draw_alpha);
}
+ if(vo_spudec){
+ vo_draw_spudec(dxs,dys,draw_alpha);
+ }
+
}
diff --git a/libvo/sub.h b/libvo/sub.h
index 8ffecbcd15..acaf4a050c 100644
--- a/libvo/sub.h
+++ b/libvo/sub.h
@@ -21,6 +21,8 @@ extern int vo_osd_progbar_value; // 0..255
extern subtitle* vo_sub;
+extern void* vo_spudec;
+
#define OSD_PLAY 0x01
#define OSD_PAUSE 0x02
#define OSD_STOP 0x03
diff --git a/mplayer.c b/mplayer.c
index 7984e5a08f..00151e74da 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -249,11 +249,17 @@ static unsigned int inited_flags=0;
#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 @@ play_next_file:
}
/*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 @@ if(rel_seek_secs || abs_seek_pos){
#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)
diff --git a/spudec.c b/spudec.c
index f8f77ef86a..f455e9ea01 100644
--- a/spudec.c
+++ b/spudec.c
@@ -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;
+ }
+ }
+}
-void spudec_process_control(unsigned char *control, int size, int* d1, int* d2)
+static void spudec_process_control(spudec_handle_t *this)
{
- int off = 2;
int a,b; /* Temporary vars */
+ int date, type;
+ int off;
+ int start_off = 0;
+ int next_off;
- 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;
+ 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); */
}
+ }
+}
- /* printf("spudec: Processsed control type 0x%02x.\n",type); */
- } while(off < size);
+static void spudec_decode(spudec_handle_t *this)
+{
+ spudec_process_control(this);
+ spudec_process_data(this);
}
-// 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_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;
+
+void spudec_assemble(void *this, unsigned char *packet, int len, int pts100)
+{
+ 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;
+ }
+ 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;
+ }
}
- 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);
-// }
+ if (spu->packet_offset == spu->packet_size) {
+ spudec_decode(spu);
+ spu->packet_offset = 0;
+ }
+}
+
+void spudec_heartbeat(void *this, int pts100)
+{
+ ((spudec_handle_t *)this)->now_pts = 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))
+{
+ 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);
+ }
+}
diff --git a/spudec.h b/spudec.h
index c6f0b8b4fd..416ecc9479 100644
--- a/spudec.h
+++ b/spudec.h
@@ -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