diff options
-rw-r--r-- | libhb/decsub.c | 52 | ||||
-rw-r--r-- | libhb/render.c | 51 |
2 files changed, 98 insertions, 5 deletions
diff --git a/libhb/decsub.c b/libhb/decsub.c index 3666ea3fe..da94ad180 100644 --- a/libhb/decsub.c +++ b/libhb/decsub.c @@ -24,6 +24,8 @@ struct hb_work_private_s int offsets[2]; uint8_t lum[4]; + uint8_t chromaU[4]; + uint8_t chromaV[4]; uint8_t alpha[4]; }; @@ -173,8 +175,29 @@ static void ParseControls( hb_work_object_t * w ) for( j = 0; j < 4; j++ ) { + /* + * Not sure what is happening here, in theory + * the palette is in YCbCr. And we want YUV. + * + * However it looks more like YCrCb (according + * to pgcedit). And the scalers for YCrCb don't + * work, but I get the right colours by doing + * no conversion. + */ uint32_t color = title->palette[colors[j]]; - pv->lum[3-j] = (color>>16) & 0xff; + uint8_t Cr, Cb, y; + y = (color>>16) & 0xff; + Cr = (color>>8) & 0xff; + Cb = (color) & 0xff; + pv->lum[3-j] = y; + pv->chromaU[3-j] = Cb; + pv->chromaV[3-j] = Cr; + /* hb_log("color[%d] y = %d, u = %d, v = %d", + 3-j, + pv->lum[3-j], + pv->chromaU[3-j], + pv->chromaV[3-j]); + */ } i += 2; break; @@ -262,6 +285,7 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) int realwidth, realheight; hb_buffer_t * buf; uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out; + uint8_t * u_in, * u_out, * v_in, * v_out; alpha = raw + pv->width * pv->height; @@ -314,7 +338,7 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) realwidth = crop[3] - crop[2] + 1; realheight = crop[1] - crop[0] + 1; - buf = hb_buffer_init( realwidth * realheight * 2 ); + buf = hb_buffer_init( realwidth * realheight * 4 ); buf->start = pv->pts_start; buf->stop = pv->pts_stop; buf->x = pv->x + crop[2]; @@ -324,17 +348,30 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) lum_in = raw + crop[0] * pv->width + crop[2]; alpha_in = lum_in + pv->width * pv->height; + u_in = alpha_in + pv->width * pv->height; + v_in = u_in + pv->width * pv->height; + lum_out = buf->data; alpha_out = lum_out + realwidth * realheight; + u_out = alpha_out + realwidth * realheight; + v_out = u_out + realwidth * realheight; for( i = 0; i < realheight; i++ ) { memcpy( lum_out, lum_in, realwidth ); memcpy( alpha_out, alpha_in, realwidth ); + memcpy( u_out, u_in, realwidth ); + memcpy( v_out, v_in, realwidth ); + lum_in += pv->width; alpha_in += pv->width; + u_in += pv->width; + v_in += pv->width; + lum_out += realwidth; alpha_out += realwidth; + u_out += realwidth; + v_out += realwidth; } return buf; @@ -353,7 +390,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) ParseControls( w ); /* Do the actual decoding now */ - buf_raw = malloc( pv->width * pv->height * 2 ); + 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 ) ) ); \ @@ -369,7 +406,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) for( col = 0; col < pv->width; col += code >> 2 ) { - uint8_t * lum, * alpha; + uint8_t * lum, * alpha, * chromaU, * chromaV; code = 0; GET_NEXT_NIBBLE; @@ -393,10 +430,17 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) lum = buf_raw; alpha = lum + pv->width * pv->height; + chromaU = alpha + pv->width * pv->height; + chromaV = chromaU + 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 ); + memset( chromaU + line * pv->width + col, + pv->chromaU[code & 3], code >> 2 ); + memset( chromaV + line * pv->width + col, + pv->chromaV[code & 3], code >> 2 ); } /* Byte-align */ diff --git a/libhb/render.c b/libhb/render.c index a49bdfada..a8abd0e75 100644 --- a/libhb/render.c +++ b/libhb/render.c @@ -34,13 +34,33 @@ hb_work_object_t hb_render = renderClose }; +/* + * getU() & getV() + * + * Utility function that finds where the U is in the YUV sub-picture + * + * The Y data is at the top, followed by U and V, but the U and V + * are half the width of the Y, i.e. each chroma element covers 2x2 + * of the Y's. + */ +static uint8_t *getU(uint8_t *data, int width, int height, int x, int y) +{ + return(&data[(((y/2) * (width/2)) + (x/2)) + (width*height)]); +} + +static uint8_t *getV(uint8_t *data, int width, int height, int x, int y) +{ + return(&data[(((y/2) * (width/2)) + (x/2)) + (width*height) + + (width*height)/4]); +} + static void ApplySub( hb_job_t * job, hb_buffer_t * buf, hb_buffer_t ** _sub ) { hb_buffer_t * sub = *_sub; hb_title_t * title = job->title; int i, j, offset_top, offset_left; - uint8_t * lum, * alpha, * out; + uint8_t * lum, * alpha, * out, * sub_chromaU, * sub_chromaV; if( !sub ) { @@ -73,6 +93,9 @@ static void ApplySub( hb_job_t * job, hb_buffer_t * buf, lum = sub->data; alpha = lum + sub->width * sub->height; + sub_chromaU = alpha + sub->width * sub->height; + sub_chromaV = sub_chromaU + sub->width * sub->height; + out = buf->data + offset_top * title->width + offset_left; for( i = 0; i < sub->height; i++ ) @@ -83,14 +106,40 @@ static void ApplySub( hb_job_t * job, hb_buffer_t * buf, { if( offset_left + j >= 0 && offset_left + j < title->width ) { + uint8_t *chromaU, *chromaV; + + /* + * Merge the luminance and alpha with the picture + */ out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) + (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4; + /* + * Set the chroma (colour) based on whether there is + * any alpha at all. Don't try to blend with the picture. + */ + chromaU = getU(buf->data, title->width, title->height, + offset_left+j, offset_top+i); + + chromaV = getV(buf->data, title->width, title->height, + offset_left+j, offset_top+i); + + if( alpha[j] > 0 ) + { + /* + * Add the chroma from the sub-picture, as this is + * not a transparent element. + */ + *chromaU = sub_chromaU[j]; + *chromaV = sub_chromaV[j]; + } } } } lum += sub->width; alpha += sub->width; + sub_chromaU += sub->width; + sub_chromaV += sub->width; out += title->width; } |