mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 04:46:13 +00:00
dvdsubdec: Support ARGB output
Negotiate to and render into ARGB buffers directly if the peer supports it. Fixes: #580869
This commit is contained in:
parent
dc7f71fb53
commit
59bd88e4bd
2 changed files with 158 additions and 31 deletions
|
@ -40,6 +40,7 @@ static void gst_setup_palette (GstDvdSubDec * dec);
|
||||||
static void gst_dvd_sub_dec_merge_title (GstDvdSubDec * dec, GstBuffer * buf);
|
static void gst_dvd_sub_dec_merge_title (GstDvdSubDec * dec, GstBuffer * buf);
|
||||||
static GstClockTime gst_dvd_sub_dec_get_event_delay (GstDvdSubDec * dec);
|
static GstClockTime gst_dvd_sub_dec_get_event_delay (GstDvdSubDec * dec);
|
||||||
static gboolean gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event);
|
||||||
|
static gboolean gst_dvd_sub_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||||
|
|
||||||
static GstFlowReturn gst_send_subtitle_frame (GstDvdSubDec * dec,
|
static GstFlowReturn gst_send_subtitle_frame (GstDvdSubDec * dec,
|
||||||
GstClockTime end_ts);
|
GstClockTime end_ts);
|
||||||
|
@ -48,7 +49,12 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("video/x-raw-yuv, format = (fourcc) AYUV, "
|
GST_STATIC_CAPS ("video/x-raw-yuv, format = (fourcc) AYUV, "
|
||||||
"width = (int) 720, height = (int) 576, framerate = (fraction) 0/1")
|
"width = (int) 720, height = (int) 576, framerate = (fraction) 0/1; "
|
||||||
|
"video/x-raw-rgb, "
|
||||||
|
"width = (int) 720, height = (int) 576, framerate = (fraction) 0/1, "
|
||||||
|
"bpp = (int) 32, endianness = (int) 4321, red_mask = (int) 16711680, "
|
||||||
|
"green_mask = (int) 65280, blue_mask = (int) 255, "
|
||||||
|
" alpha_mask = (int) -16777216, depth = (int) 32")
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate subtitle_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate subtitle_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
@ -131,13 +137,14 @@ gst_dvd_sub_dec_init (GstDvdSubDec * dec, GstDvdSubDecClass * klass)
|
||||||
gst_pad_set_event_function (dec->sinkpad,
|
gst_pad_set_event_function (dec->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_sink_event));
|
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_sink_event));
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
||||||
|
gst_pad_set_setcaps_function (dec->sinkpad, gst_dvd_sub_dec_sink_setcaps);
|
||||||
|
|
||||||
tmpl = gst_static_pad_template_get (&src_template);
|
tmpl = gst_static_pad_template_get (&src_template);
|
||||||
dec->srcpad = gst_pad_new_from_template (tmpl, "src");
|
dec->srcpad = gst_pad_new_from_template (tmpl, "src");
|
||||||
gst_pad_set_event_function (dec->srcpad,
|
gst_pad_set_event_function (dec->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_src_event));
|
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_src_event));
|
||||||
gst_pad_use_fixed_caps (dec->srcpad);
|
gst_pad_use_fixed_caps (dec->srcpad);
|
||||||
gst_pad_set_caps (dec->srcpad, gst_pad_template_get_caps (tmpl));
|
// gst_pad_set_caps (dec->srcpad, gst_pad_template_get_caps (tmpl));
|
||||||
gst_object_unref (tmpl);
|
gst_object_unref (tmpl);
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||||
|
|
||||||
|
@ -164,6 +171,7 @@ gst_dvd_sub_dec_init (GstDvdSubDec * dec, GstDvdSubDecClass * klass)
|
||||||
|
|
||||||
dec->out_buffer = NULL;
|
dec->out_buffer = NULL;
|
||||||
dec->buf_dirty = TRUE;
|
dec->buf_dirty = TRUE;
|
||||||
|
dec->use_ARGB = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -414,21 +422,49 @@ gst_setup_palette (GstDvdSubDec * dec)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
guint32 col;
|
guint32 col;
|
||||||
YUVA_val *target = dec->palette_cache;
|
Color_val *target_yuv = dec->palette_cache_yuv;
|
||||||
YUVA_val *target2 = dec->hl_palette_cache;
|
Color_val *target2_yuv = dec->hl_palette_cache_yuv;
|
||||||
|
Color_val *target_rgb = dec->palette_cache_rgb;
|
||||||
|
Color_val *target2_rgb = dec->hl_palette_cache_rgb;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++, target2++, target++) {
|
for (i = 0; i < 4; i++, target2_yuv++, target_yuv++) {
|
||||||
col = dec->current_clut[dec->subtitle_index[i]];
|
col = dec->current_clut[dec->subtitle_index[i]];
|
||||||
target->Y = (col >> 16) & 0xff;
|
target_yuv->Y_R = (col >> 16) & 0xff;
|
||||||
target->V = (col >> 8) & 0xff;
|
target_yuv->V_B = (col >> 8) & 0xff;
|
||||||
target->U = col & 0xff;
|
target_yuv->U_G = col & 0xff;
|
||||||
target->A = dec->subtitle_alpha[i] * 0xff / 0xf;
|
target_yuv->A = dec->subtitle_alpha[i] * 0xff / 0xf;
|
||||||
|
|
||||||
col = dec->current_clut[dec->menu_index[i]];
|
col = dec->current_clut[dec->menu_index[i]];
|
||||||
target2->Y = (col >> 16) & 0xff;
|
target2_yuv->Y_R = (col >> 16) & 0xff;
|
||||||
target2->V = (col >> 8) & 0xff;
|
target2_yuv->V_B = (col >> 8) & 0xff;
|
||||||
target2->U = col & 0xff;
|
target2_yuv->U_G = col & 0xff;
|
||||||
target2->A = dec->menu_alpha[i] * 0xff / 0xf;
|
target2_yuv->A = dec->menu_alpha[i] * 0xff / 0xf;
|
||||||
|
|
||||||
|
/* If ARGB flag set, then convert YUV palette to RGB */
|
||||||
|
/* Using integer aritmetic */
|
||||||
|
if (dec->use_ARGB) {
|
||||||
|
guchar C = target_yuv->Y_R - 16;
|
||||||
|
guchar D = target_yuv->U_G - 128;
|
||||||
|
guchar E = target_yuv->V_B - 128;
|
||||||
|
|
||||||
|
target_rgb->Y_R = CLAMP (((298 * C + 409 * E + 128) >> 8), 0, 255);
|
||||||
|
target_rgb->U_G =
|
||||||
|
CLAMP (((298 * C - 100 * D - 128 * E + 128) >> 8), 0, 255);
|
||||||
|
target_rgb->V_B = CLAMP (((298 * C + 516 * D + 128) >> 8), 0, 255);
|
||||||
|
target_rgb->A = target_yuv->A;
|
||||||
|
|
||||||
|
C = target2_yuv->Y_R - 16;
|
||||||
|
D = target2_yuv->U_G - 128;
|
||||||
|
E = target2_yuv->V_B - 128;
|
||||||
|
|
||||||
|
target2_rgb->Y_R = CLAMP (((298 * C + 409 * E + 128) >> 8), 0, 255);
|
||||||
|
target2_rgb->U_G =
|
||||||
|
CLAMP (((298 * C - 100 * D - 128 * E + 128) >> 8), 0, 255);
|
||||||
|
target2_rgb->V_B = CLAMP (((298 * C + 516 * D + 128) >> 8), 0, 255);
|
||||||
|
target2_rgb->A = target2_yuv->A;
|
||||||
|
}
|
||||||
|
target_rgb++;
|
||||||
|
target2_rgb++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,13 +488,13 @@ gst_get_rle_code (guchar * buffer, RLE_state * state)
|
||||||
|
|
||||||
#define DRAW_RUN(target,len,c) \
|
#define DRAW_RUN(target,len,c) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
|
gint i = 0; \
|
||||||
if ((c)->A) { \
|
if ((c)->A) { \
|
||||||
gint i; \
|
|
||||||
for (i = 0; i < (len); i++) { \
|
for (i = 0; i < (len); i++) { \
|
||||||
*(target)++ = (c)->A; \
|
*(target)++ = (c)->A; \
|
||||||
*(target)++ = (c)->Y; \
|
*(target)++ = (c)->Y_R; \
|
||||||
*(target)++ = (c)->U; \
|
*(target)++ = (c)->U_G; \
|
||||||
*(target)++ = (c)->V; \
|
*(target)++ = (c)->V_B; \
|
||||||
} \
|
} \
|
||||||
} else { \
|
} else { \
|
||||||
(target) += 4 * (len); \
|
(target) += 4 * (len); \
|
||||||
|
@ -467,7 +503,7 @@ G_STMT_START { \
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function steps over each run-length segment, drawing
|
* This function steps over each run-length segment, drawing
|
||||||
* into the YUVA buffers as it goes. UV are composited and then output
|
* into the YUVA/ARGB buffers as it goes. UV are composited and then output
|
||||||
* at half width/height
|
* at half width/height
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
@ -485,12 +521,15 @@ gst_draw_rle_line (GstDvdSubDec * dec, guchar * buffer, RLE_state * state)
|
||||||
|
|
||||||
while (x < right) {
|
while (x < right) {
|
||||||
gboolean in_hl;
|
gboolean in_hl;
|
||||||
const YUVA_val *colour_entry;
|
const Color_val *colour_entry;
|
||||||
|
|
||||||
code = gst_get_rle_code (buffer, state);
|
code = gst_get_rle_code (buffer, state);
|
||||||
length = code >> 2;
|
length = code >> 2;
|
||||||
colourid = code & 3;
|
colourid = code & 3;
|
||||||
colour_entry = dec->palette_cache + colourid;
|
if (dec->use_ARGB)
|
||||||
|
colour_entry = dec->palette_cache_rgb + colourid;
|
||||||
|
else
|
||||||
|
colour_entry = dec->palette_cache_yuv + colourid;
|
||||||
|
|
||||||
/* Length = 0 implies fill to the end of the line */
|
/* Length = 0 implies fill to the end of the line */
|
||||||
/* Restrict the colour run to the end of the line */
|
/* Restrict the colour run to the end of the line */
|
||||||
|
@ -513,7 +552,11 @@ gst_draw_rle_line (GstDvdSubDec * dec, guchar * buffer, RLE_state * state)
|
||||||
|
|
||||||
/* Draw across the highlight region */
|
/* Draw across the highlight region */
|
||||||
if (x <= state->hl_right) {
|
if (x <= state->hl_right) {
|
||||||
const YUVA_val *hl_colour = dec->hl_palette_cache + colourid;
|
const Color_val *hl_colour;
|
||||||
|
if (dec->use_ARGB)
|
||||||
|
hl_colour = dec->hl_palette_cache_rgb + colourid;
|
||||||
|
else
|
||||||
|
hl_colour = dec->hl_palette_cache_yuv + colourid;
|
||||||
|
|
||||||
run = MIN (length, state->hl_right - x + 1);
|
run = MIN (length, state->hl_right - x + 1);
|
||||||
|
|
||||||
|
@ -635,9 +678,15 @@ gst_send_subtitle_frame (GstDvdSubDec * dec, GstClockTime end_ts)
|
||||||
|
|
||||||
for (x = 0; x < dec->in_width; x++) {
|
for (x = 0; x < dec->in_width; x++) {
|
||||||
line[0] = 0; /* A */
|
line[0] = 0; /* A */
|
||||||
line[1] = 16; /* Y */
|
if (!dec->use_ARGB) {
|
||||||
line[2] = 128; /* U */
|
line[1] = 16; /* Y */
|
||||||
line[3] = 128; /* V */
|
line[2] = 128; /* U */
|
||||||
|
line[3] = 128; /* V */
|
||||||
|
} else {
|
||||||
|
line[1] = 0; /* R */
|
||||||
|
line[2] = 0; /* G */
|
||||||
|
line[3] = 0; /* B */
|
||||||
|
}
|
||||||
|
|
||||||
line += 4;
|
line += 4;
|
||||||
}
|
}
|
||||||
|
@ -789,6 +838,78 @@ gst_dvd_sub_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_dvd_sub_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstDvdSubDec *dec = GST_DVD_SUB_DEC (gst_pad_get_parent (pad));
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
guint32 fourcc = GST_MAKE_FOURCC ('A', 'Y', 'U', 'V');
|
||||||
|
GstCaps *out_caps = NULL, *peer_caps = NULL;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "setcaps called with %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
dec->out_fourcc = fourcc;
|
||||||
|
out_caps = gst_caps_new_simple ("video/x-raw-yuv",
|
||||||
|
"width", G_TYPE_INT, dec->in_width,
|
||||||
|
"height", G_TYPE_INT, dec->in_height,
|
||||||
|
"format", GST_TYPE_FOURCC, dec->out_fourcc,
|
||||||
|
"framerate", GST_TYPE_FRACTION, 0, 1, NULL);
|
||||||
|
|
||||||
|
peer_caps = gst_pad_get_allowed_caps (dec->srcpad);
|
||||||
|
if (G_LIKELY (peer_caps)) {
|
||||||
|
guint i = 0, n = 0;
|
||||||
|
n = gst_caps_get_size (peer_caps);
|
||||||
|
GST_DEBUG_OBJECT (dec, "peer allowed caps (%u structure(s)) are %"
|
||||||
|
GST_PTR_FORMAT, n, peer_caps);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
GstStructure *s = gst_caps_get_structure (peer_caps, i);
|
||||||
|
/* Check if the peer pad support ARGB format, if yes change caps */
|
||||||
|
if (gst_structure_has_name (s, "video/x-raw-rgb") &&
|
||||||
|
gst_structure_has_field (s, "alpha_mask")) {
|
||||||
|
gst_caps_unref (out_caps);
|
||||||
|
GST_DEBUG_OBJECT (dec, "trying with fourcc %" GST_FOURCC_FORMAT,
|
||||||
|
GST_FOURCC_ARGS (fourcc));
|
||||||
|
out_caps = gst_caps_new_simple ("video/x-raw-rgb",
|
||||||
|
"width", G_TYPE_INT, dec->in_width,
|
||||||
|
"height", G_TYPE_INT, dec->in_height,
|
||||||
|
"framerate", GST_TYPE_FRACTION, 0, 1,
|
||||||
|
"bpp", G_TYPE_INT, 32,
|
||||||
|
"depth", G_TYPE_INT, 32,
|
||||||
|
"red_mask", G_TYPE_INT, 16711680,
|
||||||
|
"green_mask", G_TYPE_INT, 65280,
|
||||||
|
"blue_mask", G_TYPE_INT, 255,
|
||||||
|
"alpha_mask", G_TYPE_INT, -16777216,
|
||||||
|
"endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
|
||||||
|
if (gst_pad_peer_accept_caps (dec->srcpad, out_caps)) {
|
||||||
|
GST_DEBUG_OBJECT (dec, "peer accepted format %" GST_FOURCC_FORMAT,
|
||||||
|
GST_FOURCC_ARGS (fourcc));
|
||||||
|
/* If ARGB format then set the flag */
|
||||||
|
dec->use_ARGB = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_caps_unref (peer_caps);
|
||||||
|
}
|
||||||
|
GST_DEBUG_OBJECT (dec, "setting caps downstream to %" GST_PTR_FORMAT,
|
||||||
|
out_caps);
|
||||||
|
if (gst_pad_set_caps (dec->srcpad, out_caps)) {
|
||||||
|
dec->out_fourcc = fourcc;
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (dec, "failed setting downstream caps");
|
||||||
|
gst_caps_unref (out_caps);
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_unref (out_caps);
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
beach:
|
||||||
|
gst_object_unref (dec);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event)
|
gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,13 +30,14 @@ typedef struct _GstDvdSubDec GstDvdSubDec;
|
||||||
typedef struct _GstDvdSubDecClass GstDvdSubDecClass;
|
typedef struct _GstDvdSubDecClass GstDvdSubDecClass;
|
||||||
|
|
||||||
/* Hold premultimplied colour values */
|
/* Hold premultimplied colour values */
|
||||||
typedef struct YUVA_val
|
typedef struct Color_val
|
||||||
{
|
{
|
||||||
guchar Y;
|
guchar Y_R;
|
||||||
guchar U;
|
guchar U_G;
|
||||||
guchar V;
|
guchar V_B;
|
||||||
guchar A;
|
guchar A;
|
||||||
} YUVA_val;
|
|
||||||
|
} Color_val;
|
||||||
|
|
||||||
struct _GstDvdSubDec
|
struct _GstDvdSubDec
|
||||||
{
|
{
|
||||||
|
@ -57,9 +58,14 @@ struct _GstDvdSubDec
|
||||||
guchar menu_alpha[4];
|
guchar menu_alpha[4];
|
||||||
|
|
||||||
guint32 current_clut[16];
|
guint32 current_clut[16];
|
||||||
YUVA_val palette_cache[4];
|
Color_val palette_cache_yuv[4];
|
||||||
YUVA_val hl_palette_cache[4];
|
Color_val hl_palette_cache_yuv[4];
|
||||||
|
|
||||||
|
Color_val palette_cache_rgb[4];
|
||||||
|
Color_val hl_palette_cache_rgb[4];
|
||||||
|
|
||||||
|
gboolean use_ARGB;
|
||||||
|
guint32 out_fourcc;
|
||||||
GstClockTime next_ts;
|
GstClockTime next_ts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue