diff options
Diffstat (limited to 'libhb/decsub.c')
-rw-r--r-- | libhb/decsub.c | 336 |
1 files changed, 161 insertions, 175 deletions
diff --git a/libhb/decsub.c b/libhb/decsub.c index de844a1c1..3666ea3fe 100644 --- a/libhb/decsub.c +++ b/libhb/decsub.c @@ -6,10 +6,8 @@ #include "hb.h" -struct hb_work_object_s +struct hb_work_private_s { - HB_WORK_COMMON; - hb_job_t * job; uint8_t buf[0xFFFF]; @@ -29,57 +27,25 @@ struct hb_work_object_s uint8_t alpha[4]; }; +static hb_buffer_t * Decode( hb_work_object_t * ); -/*********************************************************************** - * Local prototypes - **********************************************************************/ -static void Close( hb_work_object_t ** _w ); -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ); -static hb_buffer_t * Decode( hb_work_object_t * w ); -static void ParseControls( hb_work_object_t * w ); -static hb_buffer_t * CropSubtitle( hb_work_object_t * w, - uint8_t * raw ); - -/*********************************************************************** - * hb_work_decsub_init - *********************************************************************** - * - **********************************************************************/ -hb_work_object_t * hb_work_decsub_init( hb_job_t * job ) +int decsubInit( hb_work_object_t * w, hb_job_t * job ) { - hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); - w->name = strdup( "Subtitle decoder" ); - w->work = Work; - w->close = Close; - - w->job = job; - w->pts = -1; + hb_work_private_t * pv; + + pv = calloc( 1, sizeof( hb_work_private_t ) ); + w->private_data = pv; - return w; -} + pv->job = job; + pv->pts = -1; -/*********************************************************************** - * Close - *********************************************************************** - * Free memory - **********************************************************************/ -static void Close( hb_work_object_t ** _w ) -{ - hb_work_object_t * w = *_w; - free( w->name ); - free( w ); - *_w = NULL; + return 0; } -/*********************************************************************** - * Work - *********************************************************************** - * - **********************************************************************/ -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ) +int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) { + hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in; int size_sub, size_rle; @@ -87,124 +53,66 @@ static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, size_sub = ( in->data[0] << 8 ) | in->data[1]; size_rle = ( in->data[2] << 8 ) | in->data[3]; - if( !w->size_sub ) + if( !pv->size_sub ) { /* We are looking for the start of a new subtitle */ if( size_sub && size_rle && size_sub > size_rle && in->size <= size_sub ) { /* Looks all right so far */ - w->size_sub = size_sub; - w->size_rle = size_rle; + pv->size_sub = size_sub; + pv->size_rle = size_rle; - memcpy( w->buf, in->data, in->size ); - w->size_got = in->size; - w->pts = in->start; + memcpy( pv->buf, in->data, in->size ); + pv->size_got = in->size; + pv->pts = in->start; } } else { /* We are waiting for the end of the current subtitle */ - if( in->size <= w->size_sub - w->size_got ) + if( in->size <= pv->size_sub - pv->size_got ) { - memcpy( w->buf + w->size_got, in->data, in->size ); - w->size_got += in->size; + memcpy( pv->buf + pv->size_got, in->data, in->size ); + pv->size_got += in->size; if( in->start >= 0 ) { - w->pts = in->start; + pv->pts = in->start; } } } *buf_out = NULL; - if( w->size_sub && w->size_sub == w->size_got ) + if( pv->size_sub && pv->size_sub == pv->size_got ) { /* We got a complete subtitle, decode it */ *buf_out = Decode( w ); /* Wait for the next one */ - w->size_sub = 0; - w->size_got = 0; - w->size_rle = 0; - w->pts = -1; + pv->size_sub = 0; + pv->size_got = 0; + pv->size_rle = 0; + pv->pts = -1; } return HB_WORK_OK; } -static hb_buffer_t * Decode( hb_work_object_t * w ) +void decsubClose( hb_work_object_t * w ) { - int code, line, col; - int offsets[2]; - int * offset; - hb_buffer_t * buf; - uint8_t * buf_raw = NULL; - - /* Get infos about the subtitle */ - ParseControls( w ); - - /* Do the actual decoding now */ - buf_raw = malloc( w->width * w->height * 2 ); - -#define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \ -( w->buf[((*offset)>>1)] & 0xF ) : ( w->buf[((*offset)>>1)] >> 4 ) ) ); \ -(*offset)++ - - offsets[0] = w->offsets[0] * 2; - offsets[1] = w->offsets[1] * 2; - - for( line = 0; line < w->height; line++ ) - { - /* Select even or odd field */ - offset = ( line & 1 ) ? &offsets[1] : &offsets[0]; - - for( col = 0; col < w->width; col += code >> 2 ) - { - uint8_t * lum, * alpha; - - code = 0; - GET_NEXT_NIBBLE; - if( code < 0x4 ) - { - GET_NEXT_NIBBLE; - if( code < 0x10 ) - { - GET_NEXT_NIBBLE; - if( code < 0x40 ) - { - GET_NEXT_NIBBLE; - if( code < 0x100 ) - { - /* End of line */ - code |= ( w->width - col ) << 2; - } - } - } - } - - lum = buf_raw; - alpha = lum + w->width * w->height; - memset( lum + line * w->width + col, - w->lum[code & 3], code >> 2 ); - memset( alpha + line * w->width + col, - w->alpha[code & 3], code >> 2 ); - } - - /* Byte-align */ - if( *offset & 1 ) - { - (*offset)++; - } - } - - /* Crop subtitle (remove transparent borders) */ - buf = CropSubtitle( w, buf_raw ); + free( w->private_data ); +} - free( buf_raw ); +hb_work_object_t hb_decsub = +{ + WORK_DECSUB, + "Subtitle decoder", + decsubInit, + decsubWork, + decsubClose +}; - return buf; -} /*********************************************************************** * ParseControls @@ -215,24 +123,25 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) **********************************************************************/ static void ParseControls( hb_work_object_t * w ) { - hb_job_t * job = w->job; + hb_work_private_t * pv = w->private_data; + hb_job_t * job = pv->job; hb_title_t * title = job->title; int i; int command; int date, next; - w->pts_start = 0; - w->pts_stop = 0; + pv->pts_start = 0; + pv->pts_stop = 0; - for( i = w->size_rle; ; ) + for( i = pv->size_rle; ; ) { - date = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; - next = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; + next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; for( ;; ) { - command = w->buf[i++]; + command = pv->buf[i++]; if( command == 0xFF ) { @@ -245,11 +154,11 @@ static void ParseControls( hb_work_object_t * w ) break; case 0x01: - w->pts_start = w->pts + date * 900; + pv->pts_start = pv->pts + date * 900; break; case 0x02: - w->pts_stop = w->pts + date * 900; + pv->pts_stop = pv->pts + date * 900; break; case 0x03: @@ -257,41 +166,41 @@ static void ParseControls( hb_work_object_t * w ) int colors[4]; int j; - colors[0] = (w->buf[i+0]>>4)&0x0f; - colors[1] = (w->buf[i+0])&0x0f; - colors[2] = (w->buf[i+1]>>4)&0x0f; - colors[3] = (w->buf[i+1])&0x0f; + 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; for( j = 0; j < 4; j++ ) { uint32_t color = title->palette[colors[j]]; - w->lum[3-j] = (color>>16) & 0xff; + pv->lum[3-j] = (color>>16) & 0xff; } i += 2; break; } case 0x04: { - w->alpha[3] = (w->buf[i+0]>>4)&0x0f; - w->alpha[2] = (w->buf[i+0])&0x0f; - w->alpha[1] = (w->buf[i+1]>>4)&0x0f; - w->alpha[0] = (w->buf[i+1])&0x0f; + pv->alpha[3] = (pv->buf[i+0]>>4)&0x0f; + pv->alpha[2] = (pv->buf[i+0])&0x0f; + pv->alpha[1] = (pv->buf[i+1]>>4)&0x0f; + pv->alpha[0] = (pv->buf[i+1])&0x0f; i += 2; break; } case 0x05: { - w->x = (w->buf[i+0]<<4) | ((w->buf[i+1]>>4)&0x0f); - w->width = (((w->buf[i+1]&0x0f)<<8)| w->buf[i+2]) - w->x + 1; - w->y = (w->buf[i+3]<<4)| ((w->buf[i+4]>>4)&0x0f); - w->height = (((w->buf[i+4]&0x0f)<<8)| w->buf[i+5]) - w->y + 1; + 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; i += 6; break; } case 0x06: { - w->offsets[0] = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; - w->offsets[1] = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + 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; break; } } @@ -304,10 +213,10 @@ static void ParseControls( hb_work_object_t * w ) i = next; } - if( !w->pts_stop ) + if( !pv->pts_stop ) { /* Show it for 3 seconds */ - w->pts_stop = w->pts_start + 3 * 90000; + pv->pts_stop = pv->pts_start + 3 * 90000; } } @@ -320,8 +229,9 @@ static void ParseControls( hb_work_object_t * w ) **********************************************************************/ static int LineIsTransparent( hb_work_object_t * w, uint8_t * p ) { + hb_work_private_t * pv = w->private_data; int i; - for( i = 0; i < w->width; i++ ) + for( i = 0; i < pv->width; i++ ) { if( p[i] ) { @@ -332,10 +242,11 @@ static int LineIsTransparent( hb_work_object_t * w, uint8_t * p ) } static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p ) { + hb_work_private_t * pv = w->private_data; int i; - for( i = 0; i < w->height; i++ ) + for( i = 0; i < pv->height; i++ ) { - if( p[i*w->width] ) + if( p[i*pv->width] ) { return 0; } @@ -344,6 +255,7 @@ static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p ) } static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) { + hb_work_private_t * pv = w->private_data; int i; int crop[4] = { -1,-1,-1,-1 }; uint8_t * alpha; @@ -351,12 +263,12 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) hb_buffer_t * buf; uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out; - alpha = raw + w->width * w->height; + alpha = raw + pv->width * pv->height; /* Top */ - for( i = 0; i < w->height; i++ ) + for( i = 0; i < pv->height; i++ ) { - if( !LineIsTransparent( w, &alpha[i*w->width] ) ) + if( !LineIsTransparent( w, &alpha[i*pv->width] ) ) { crop[0] = i; break; @@ -370,9 +282,9 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) } /* Bottom */ - for( i = w->height - 1; i >= 0; i-- ) + for( i = pv->height - 1; i >= 0; i-- ) { - if( !LineIsTransparent( w, &alpha[i*w->width] ) ) + if( !LineIsTransparent( w, &alpha[i*pv->width] ) ) { crop[1] = i; break; @@ -380,7 +292,7 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) } /* Left */ - for( i = 0; i < w->width; i++ ) + for( i = 0; i < pv->width; i++ ) { if( !ColumnIsTransparent( w, &alpha[i] ) ) { @@ -390,7 +302,7 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) } /* Right */ - for( i = w->width - 1; i >= 0; i-- ) + for( i = pv->width - 1; i >= 0; i-- ) { if( !ColumnIsTransparent( w, &alpha[i] ) ) { @@ -403,15 +315,15 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) realheight = crop[1] - crop[0] + 1; buf = hb_buffer_init( realwidth * realheight * 2 ); - buf->start = w->pts_start; - buf->stop = w->pts_stop; - buf->x = w->x + crop[2]; - buf->y = w->y + crop[0]; + buf->start = pv->pts_start; + buf->stop = pv->pts_stop; + buf->x = pv->x + crop[2]; + buf->y = pv->y + crop[0]; buf->width = realwidth; buf->height = realheight; - lum_in = raw + crop[0] * w->width + crop[2]; - alpha_in = lum_in + w->width * w->height; + lum_in = raw + crop[0] * pv->width + crop[2]; + alpha_in = lum_in + pv->width * pv->height; lum_out = buf->data; alpha_out = lum_out + realwidth * realheight; @@ -419,11 +331,85 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) { memcpy( lum_out, lum_in, realwidth ); memcpy( alpha_out, alpha_in, realwidth ); - lum_in += w->width; - alpha_in += w->width; + lum_in += pv->width; + alpha_in += pv->width; lum_out += realwidth; alpha_out += realwidth; } return buf; } + +static hb_buffer_t * Decode( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + int code, line, col; + int offsets[2]; + int * offset; + hb_buffer_t * buf; + uint8_t * buf_raw = NULL; + + /* Get infos about the subtitle */ + ParseControls( w ); + + /* Do the actual decoding now */ + buf_raw = malloc( pv->width * pv->height * 2 ); + +#define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \ +( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \ +(*offset)++ + + offsets[0] = pv->offsets[0] * 2; + offsets[1] = pv->offsets[1] * 2; + + for( line = 0; line < pv->height; line++ ) + { + /* Select even or odd field */ + offset = ( line & 1 ) ? &offsets[1] : &offsets[0]; + + for( col = 0; col < pv->width; col += code >> 2 ) + { + uint8_t * lum, * alpha; + + code = 0; + GET_NEXT_NIBBLE; + if( code < 0x4 ) + { + GET_NEXT_NIBBLE; + if( code < 0x10 ) + { + GET_NEXT_NIBBLE; + if( code < 0x40 ) + { + GET_NEXT_NIBBLE; + if( code < 0x100 ) + { + /* End of line */ + code |= ( pv->width - col ) << 2; + } + } + } + } + + lum = buf_raw; + alpha = lum + pv->width * pv->height; + memset( lum + line * pv->width + col, + pv->lum[code & 3], code >> 2 ); + memset( alpha + line * pv->width + col, + pv->alpha[code & 3], code >> 2 ); + } + + /* Byte-align */ + if( *offset & 1 ) + { + (*offset)++; + } + } + + /* Crop subtitle (remove transparent borders) */ + buf = CropSubtitle( w, buf_raw ); + + free( buf_raw ); + + return buf; +} |