Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
+/*
+ * Decoder for DVD bitmap subtitles, also known as "VOB subtitles" within the HandBrake source code.
+ *
+ * Input format of the subtitle packets is described here:
+ * http://sam.zoy.org/writings/dvd/subtitles/
+ *
+ * An auxiliary input is the color palette lookup table, in 'subtitle->palette'.
+ * The demuxer implementation must fill out this table appropriately.
+ * - In the case of a true DVD input, the palette is read from the IFO file.
+ * - In the case of an MKV file input, the palette is read from the codec private data of the subtitle track.
+ *
+ * Output format of this decoder is PICTURESUB, which is:
+ * struct PictureSubPacket {
+ * uint8_t lum[pixelCount];
+ * uint8_t alpha[pixelCount];
+ * uint8_t chromaU[pixelCount];
+ * uint8_t chromaV[pixelCount];
+ * }
+ */
+
#include "hb.h"
struct hb_work_private_s
{
- hb_job_t * job;
-
- uint8_t buf[0xFFFF];
- int size_sub;
- int size_got;
- int size_rle;
- int64_t pts;
- int64_t pts_start;
- int64_t pts_stop;
- int pts_forced;
- int x;
- int y;
- int width;
- int height;
- int stream_id;
-
- int offsets[2];
- uint8_t lum[4];
- uint8_t chromaU[4];
- uint8_t chromaV[4];
- uint8_t alpha[4];
+ hb_job_t * job;
+
+ hb_buffer_t * buf;
+ int size_sub;
+ int size_got;
+ int size_rle;
+ int64_t pts;
+ int64_t pts_start;
+ int64_t pts_stop;
+ int pts_forced;
+ int x;
+ int y;
+ int width;
+ int height;
+ int stream_id;
+
+ int offsets[2];
+ uint8_t lum[4];
+ uint8_t chromaU[4];
+ uint8_t chromaV[4];
+ uint8_t alpha[4];
};
static hb_buffer_t * Decode( hb_work_object_t * );
pv->job = job;
pv->pts = -1;
+
+ // Warn if the input color palette is empty
+ int paletteEmpty = 1;
+ int i;
+ for (i=0; i<16; i++)
+ {
+ if (w->subtitle->palette[i])
+ {
+ paletteEmpty = 0;
+ break;
+ }
+ }
+ if (paletteEmpty) {
+ hb_log( "decvobsub: input color palette is empty; not demuxed properly?" );
+ }
return 0;
}
pv->size_sub = size_sub;
pv->size_rle = size_rle;
- memcpy( pv->buf, in->data, in->size );
+ pv->buf = hb_buffer_init( 0xFFFF );
+ memcpy( pv->buf->data, in->data, in->size );
+ pv->buf->id = in->id;
+ pv->buf->sequence = in->sequence;
pv->size_got = in->size;
pv->pts = in->start;
}
/* We are waiting for the end of the current subtitle */
if( in->size <= pv->size_sub - pv->size_got )
{
- memcpy( pv->buf + pv->size_got, in->data, in->size );
+ memcpy( pv->buf->data + pv->size_got, in->data, in->size );
+ pv->buf->id = in->id;
+ pv->buf->sequence = in->sequence;
pv->size_got += in->size;
if( in->start >= 0 )
{
pv->pts = in->start;
}
}
+ else
+ {
+ // bad size, must have lost sync
+ // force re-sync
+ if ( pv->buf != NULL )
+ hb_buffer_close( &pv->buf );
+ pv->size_sub = 0;
+ }
+
}
*buf_out = NULL;
if( pv->size_sub && pv->size_sub == pv->size_got )
{
+ pv->buf->size = pv->size_sub;
+
/* We got a complete subtitle, decode it */
*buf_out = Decode( w );
if( buf_out && *buf_out )
{
+ (*buf_out)->id = in->id;
(*buf_out)->sequence = in->sequence;
}
void decsubClose( hb_work_object_t * w )
{
+ hb_work_private_t * pv = w->private_data;
+
+ if ( pv->buf )
+ hb_buffer_close( &pv->buf );
free( w->private_data );
}
-hb_work_object_t hb_decsub =
+hb_work_object_t hb_decvobsub =
{
- WORK_DECSUB,
+ WORK_DECVOBSUB,
"VOBSUB decoder",
decsubInit,
decsubWork,
hb_job_t * job = pv->job;
hb_title_t * title = job->title;
hb_subtitle_t * subtitle;
+ uint8_t * buf = pv->buf->data;
int i, n;
int command;
for( i = pv->size_rle; ; )
{
- date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
- next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
+ date = ( buf[i] << 8 ) | buf[i+1]; i += 2;
+ next = ( buf[i] << 8 ) | buf[i+1]; i += 2;
for( ;; )
{
- command = pv->buf[i++];
+ command = buf[i++];
/*
* There are eight commands available for
int colors[4];
int j;
- colors[0] = (pv->buf[i+0]>>4)&0x0f;
- colors[1] = (pv->buf[i+0])&0x0f;
- colors[2] = (pv->buf[i+1]>>4)&0x0f;
- colors[3] = (pv->buf[i+1])&0x0f;
+ colors[0] = (buf[i+0]>>4)&0x0f;
+ colors[1] = (buf[i+0])&0x0f;
+ colors[2] = (buf[i+1]>>4)&0x0f;
+ colors[3] = (buf[i+1])&0x0f;
for( j = 0; j < 4; j++ )
{
* work, but I get the right colours by doing
* no conversion.
*/
- uint32_t color = title->palette[colors[j]];
+ uint32_t color = w->subtitle->palette[colors[j]];
uint8_t Cr, Cb, y;
y = (color>>16) & 0xff;
Cr = (color>>8) & 0xff;
*/
uint8_t alpha[4];
- alpha[3] = (pv->buf[i+0]>>4)&0x0f;
- alpha[2] = (pv->buf[i+0])&0x0f;
- alpha[1] = (pv->buf[i+1]>>4)&0x0f;
- alpha[0] = (pv->buf[i+1])&0x0f;
+ alpha[3] = (buf[i+0]>>4)&0x0f;
+ alpha[2] = (buf[i+0])&0x0f;
+ alpha[1] = (buf[i+1]>>4)&0x0f;
+ alpha[0] = (buf[i+1])&0x0f;
int lastAlpha = pv->alpha[3] + pv->alpha[2] + pv->alpha[1] + pv->alpha[0];
}
case 0x05: // 0x05 - SET_DAREA - defines the display area
{
- pv->x = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
- pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
- pv->y = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
- pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
+ pv->x = (buf[i+0]<<4) | ((buf[i+1]>>4)&0x0f);
+ pv->width = (((buf[i+1]&0x0f)<<8)| buf[i+2]) - pv->x + 1;
+ pv->y = (buf[i+3]<<4)| ((buf[i+4]>>4)&0x0f);
+ pv->height = (((buf[i+4]&0x0f)<<8)| buf[i+5]) - pv->y + 1;
i += 6;
break;
}
case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
{
- pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
- pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
+ pv->offsets[0] = ( buf[i] << 8 ) | buf[i+1]; i += 2;
+ pv->offsets[1] = ( buf[i] << 8 ) | buf[i+1]; i += 2;
break;
}
}
/* Get infos about the subtitle */
ParseControls( w );
- if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
+ if( job->indepth_scan || ( w->subtitle->config.force && pv->pts_forced == 0 ) )
{
/*
* Don't encode subtitles when doing a scan.
* When forcing subtitles, ignore all those that don't
* have the forced flag set.
*/
+ hb_buffer_close( &pv->buf );
return NULL;
}
+ if (w->subtitle->config.dest == PASSTHRUSUB)
+ {
+ pv->buf->start = pv->pts_start;
+ pv->buf->stop = pv->pts_stop;
+ buf = pv->buf;
+ pv->buf = NULL;
+ return buf;
+ }
+
/* Do the actual decoding now */
buf_raw = malloc( ( pv->width * pv->height ) * 4 );
#define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
-( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
+( pv->buf->data[((*offset)>>1)] & 0xF ) : ( pv->buf->data[((*offset)>>1)] >> 4 ) ) ); \
(*offset)++
offsets[0] = pv->offsets[0] * 2;
}
}
+ hb_buffer_close( &pv->buf );
+
/* Crop subtitle (remove transparent borders) */
buf = CropSubtitle( w, buf_raw );