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