summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
Diffstat (limited to 'libhb')
-rw-r--r--libhb/decsub.c52
-rw-r--r--libhb/render.c51
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;
}