mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +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 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_setcaps (GstPad * pad, GstCaps * caps);
|
||||
|
||||
static GstFlowReturn gst_send_subtitle_frame (GstDvdSubDec * dec,
|
||||
GstClockTime end_ts);
|
||||
|
@ -48,7 +49,12 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
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",
|
||||
|
@ -131,13 +137,14 @@ gst_dvd_sub_dec_init (GstDvdSubDec * dec, GstDvdSubDecClass * klass)
|
|||
gst_pad_set_event_function (dec->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_sink_event));
|
||||
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);
|
||||
dec->srcpad = gst_pad_new_from_template (tmpl, "src");
|
||||
gst_pad_set_event_function (dec->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_src_event));
|
||||
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_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->buf_dirty = TRUE;
|
||||
dec->use_ARGB = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -414,21 +422,49 @@ gst_setup_palette (GstDvdSubDec * dec)
|
|||
{
|
||||
gint i;
|
||||
guint32 col;
|
||||
YUVA_val *target = dec->palette_cache;
|
||||
YUVA_val *target2 = dec->hl_palette_cache;
|
||||
Color_val *target_yuv = dec->palette_cache_yuv;
|
||||
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]];
|
||||
target->Y = (col >> 16) & 0xff;
|
||||
target->V = (col >> 8) & 0xff;
|
||||
target->U = col & 0xff;
|
||||
target->A = dec->subtitle_alpha[i] * 0xff / 0xf;
|
||||
target_yuv->Y_R = (col >> 16) & 0xff;
|
||||
target_yuv->V_B = (col >> 8) & 0xff;
|
||||
target_yuv->U_G = col & 0xff;
|
||||
target_yuv->A = dec->subtitle_alpha[i] * 0xff / 0xf;
|
||||
|
||||
col = dec->current_clut[dec->menu_index[i]];
|
||||
target2->Y = (col >> 16) & 0xff;
|
||||
target2->V = (col >> 8) & 0xff;
|
||||
target2->U = col & 0xff;
|
||||
target2->A = dec->menu_alpha[i] * 0xff / 0xf;
|
||||
target2_yuv->Y_R = (col >> 16) & 0xff;
|
||||
target2_yuv->V_B = (col >> 8) & 0xff;
|
||||
target2_yuv->U_G = col & 0xff;
|
||||
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) \
|
||||
G_STMT_START { \
|
||||
gint i = 0; \
|
||||
if ((c)->A) { \
|
||||
gint i; \
|
||||
for (i = 0; i < (len); i++) { \
|
||||
*(target)++ = (c)->A; \
|
||||
*(target)++ = (c)->Y; \
|
||||
*(target)++ = (c)->U; \
|
||||
*(target)++ = (c)->V; \
|
||||
*(target)++ = (c)->Y_R; \
|
||||
*(target)++ = (c)->U_G; \
|
||||
*(target)++ = (c)->V_B; \
|
||||
} \
|
||||
} else { \
|
||||
(target) += 4 * (len); \
|
||||
|
@ -467,7 +503,7 @@ G_STMT_START { \
|
|||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
static void
|
||||
|
@ -485,12 +521,15 @@ gst_draw_rle_line (GstDvdSubDec * dec, guchar * buffer, RLE_state * state)
|
|||
|
||||
while (x < right) {
|
||||
gboolean in_hl;
|
||||
const YUVA_val *colour_entry;
|
||||
const Color_val *colour_entry;
|
||||
|
||||
code = gst_get_rle_code (buffer, state);
|
||||
length = code >> 2;
|
||||
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 */
|
||||
/* 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 */
|
||||
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);
|
||||
|
||||
|
@ -635,9 +678,15 @@ gst_send_subtitle_frame (GstDvdSubDec * dec, GstClockTime end_ts)
|
|||
|
||||
for (x = 0; x < dec->in_width; x++) {
|
||||
line[0] = 0; /* A */
|
||||
line[1] = 16; /* Y */
|
||||
line[2] = 128; /* U */
|
||||
line[3] = 128; /* V */
|
||||
if (!dec->use_ARGB) {
|
||||
line[1] = 16; /* Y */
|
||||
line[2] = 128; /* U */
|
||||
line[3] = 128; /* V */
|
||||
} else {
|
||||
line[1] = 0; /* R */
|
||||
line[2] = 0; /* G */
|
||||
line[3] = 0; /* B */
|
||||
}
|
||||
|
||||
line += 4;
|
||||
}
|
||||
|
@ -789,6 +838,78 @@ gst_dvd_sub_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||
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
|
||||
gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
|
|
@ -30,13 +30,14 @@ typedef struct _GstDvdSubDec GstDvdSubDec;
|
|||
typedef struct _GstDvdSubDecClass GstDvdSubDecClass;
|
||||
|
||||
/* Hold premultimplied colour values */
|
||||
typedef struct YUVA_val
|
||||
typedef struct Color_val
|
||||
{
|
||||
guchar Y;
|
||||
guchar U;
|
||||
guchar V;
|
||||
guchar Y_R;
|
||||
guchar U_G;
|
||||
guchar V_B;
|
||||
guchar A;
|
||||
} YUVA_val;
|
||||
|
||||
} Color_val;
|
||||
|
||||
struct _GstDvdSubDec
|
||||
{
|
||||
|
@ -57,9 +58,14 @@ struct _GstDvdSubDec
|
|||
guchar menu_alpha[4];
|
||||
|
||||
guint32 current_clut[16];
|
||||
YUVA_val palette_cache[4];
|
||||
YUVA_val hl_palette_cache[4];
|
||||
Color_val palette_cache_yuv[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;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue