mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-09 17:05:52 +00:00
qtdemux: Detect and expose CEA 608/708 Closed Caption tracks
https://bugzilla.gnome.org/show_bug.cgi?id=606643
This commit is contained in:
parent
8270cbacb4
commit
2869edeea2
3 changed files with 156 additions and 2 deletions
|
@ -95,6 +95,12 @@ G_BEGIN_DECLS
|
|||
#define FOURCC_avc1 GST_MAKE_FOURCC('a','v','c','1')
|
||||
#define FOURCC_avc3 GST_MAKE_FOURCC('a','v','c','3')
|
||||
#define FOURCC_avcC GST_MAKE_FOURCC('a','v','c','C')
|
||||
#define FOURCC_c608 GST_MAKE_FOURCC('c','6','0','8')
|
||||
#define FOURCC_c708 GST_MAKE_FOURCC('c','7','0','8')
|
||||
#define FOURCC_ccdp GST_MAKE_FOURCC('c','c','d','p')
|
||||
#define FOURCC_cdat GST_MAKE_FOURCC('c','d','a','t')
|
||||
#define FOURCC_cdt2 GST_MAKE_FOURCC('c','d','t','2')
|
||||
#define FOURCC_clcp GST_MAKE_FOURCC('c','l','c','p')
|
||||
#define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p')
|
||||
#define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v')
|
||||
#define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d')
|
||||
|
|
|
@ -5370,6 +5370,120 @@ gst_qtdemux_align_buffer (GstQTDemux * demux,
|
|||
return buffer;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
|
||||
gsize * res)
|
||||
{
|
||||
guint8 *storage;
|
||||
gsize i;
|
||||
|
||||
/* We are converting from pairs to triplets */
|
||||
*res = ccpair_size / 2 * 3;
|
||||
storage = g_malloc (*res);
|
||||
for (i = 0; i * 2 < ccpair_size; i += 1) {
|
||||
if (field == 1)
|
||||
storage[i * 3] = 0xfc;
|
||||
else
|
||||
storage[i * 3] = 0xfd;
|
||||
storage[i * 3 + 1] = ccpair[i * 2];
|
||||
storage[i * 3 + 2] = ccpair[i * 2 + 1];
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
|
||||
gsize * cclen)
|
||||
{
|
||||
guint8 *res = NULL;
|
||||
guint32 atom_length, fourcc;
|
||||
QtDemuxStreamStsdEntry *stsd_entry;
|
||||
|
||||
GST_MEMDUMP ("caption atom", data, size);
|
||||
|
||||
/* There might be multiple atoms */
|
||||
|
||||
*cclen = 0;
|
||||
if (size < 8)
|
||||
goto invalid_cdat;
|
||||
atom_length = QT_UINT32 (data);
|
||||
fourcc = QT_FOURCC (data + 4);
|
||||
if (G_UNLIKELY (atom_length > size || atom_length == 8))
|
||||
goto invalid_cdat;
|
||||
|
||||
GST_DEBUG_OBJECT (stream->pad, "here");
|
||||
|
||||
/* Check if we have somethig compatible */
|
||||
stsd_entry = CUR_STREAM (stream);
|
||||
switch (stsd_entry->fourcc) {
|
||||
case FOURCC_c608:{
|
||||
guint8 *cdat = NULL, *cdt2 = NULL;
|
||||
gsize cdat_size = 0, cdt2_size = 0;
|
||||
/* Should be cdat or cdt2 */
|
||||
if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
|
||||
GST_WARNING_OBJECT (stream->pad,
|
||||
"Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
|
||||
GST_FOURCC_ARGS (fourcc));
|
||||
goto invalid_cdat;
|
||||
}
|
||||
/* Convert to cc_data triplet */
|
||||
if (fourcc == FOURCC_cdat)
|
||||
cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
|
||||
else
|
||||
cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
|
||||
GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
|
||||
size, atom_length);
|
||||
/* Check for another atom ? */
|
||||
if (size > atom_length + 8) {
|
||||
guint32 new_atom_length = QT_UINT32 (data + atom_length);
|
||||
if (size <= atom_length + new_atom_length) {
|
||||
fourcc = QT_FOURCC (data + atom_length + 4);
|
||||
if (fourcc == FOURCC_cdat)
|
||||
cdat =
|
||||
convert_to_ccdata (data + atom_length + 8, new_atom_length - 8,
|
||||
1, &cdat_size);
|
||||
else
|
||||
cdt2 =
|
||||
convert_to_ccdata (data + atom_length + 8, new_atom_length - 8,
|
||||
2, &cdt2_size);
|
||||
}
|
||||
}
|
||||
*cclen = cdat_size + cdt2_size;
|
||||
res = g_malloc (*cclen);
|
||||
if (cdat_size)
|
||||
memcpy (res, cdat, cdat_size);
|
||||
if (cdt2_size)
|
||||
memcpy (res + cdat_size, cdt2, cdt2_size);
|
||||
g_free (cdat);
|
||||
g_free (cdt2);
|
||||
}
|
||||
break;
|
||||
case FOURCC_c708:
|
||||
if (fourcc != FOURCC_ccdp) {
|
||||
GST_WARNING_OBJECT (stream->pad,
|
||||
"Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
|
||||
GST_FOURCC_ARGS (fourcc));
|
||||
goto invalid_cdat;
|
||||
}
|
||||
*cclen = atom_length - 8;
|
||||
res = g_memdup (data + 8, *cclen);
|
||||
break;
|
||||
default:
|
||||
/* Keep this here in case other closed caption formats are added */
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
GST_MEMDUMP ("Output", res, *cclen);
|
||||
return res;
|
||||
|
||||
/* Errors */
|
||||
invalid_cdat:
|
||||
GST_WARNING ("[cdat] atom is too small or invalid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the input buffer metadata must be writable,
|
||||
* but time/duration etc not yet set and need not be preserved */
|
||||
static GstBuffer *
|
||||
|
@ -5390,7 +5504,7 @@ gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
|
||||
if (G_UNLIKELY (stream->subtype != FOURCC_text
|
||||
&& stream->subtype != FOURCC_sbtl &&
|
||||
stream->subtype != FOURCC_subp)) {
|
||||
stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -5408,6 +5522,23 @@ gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
return buf;
|
||||
}
|
||||
|
||||
if (stream->subtype == FOURCC_clcp) {
|
||||
guint8 *cc;
|
||||
gsize cclen = 0;
|
||||
/* For closed caption, we need to extract the information from the
|
||||
* [cdat],[cdt2] or [ccdp] atom */
|
||||
cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
|
||||
gst_buffer_unmap (buf, &map);
|
||||
gst_buffer_unref (buf);
|
||||
if (cc) {
|
||||
buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
|
||||
} else {
|
||||
/* Conversion failed or there's nothing */
|
||||
buf = NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
nsize = GST_READ_UINT16_BE (map.data);
|
||||
nsize = MIN (nsize, map.size - 2);
|
||||
|
||||
|
@ -11557,7 +11688,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
|||
}
|
||||
entry->sampled = TRUE;
|
||||
} else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
|
||||
|| stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
|
||||
|| stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
|
||||
|| stream->subtype == FOURCC_clcp) {
|
||||
|
||||
entry->sampled = TRUE;
|
||||
entry->sparse = TRUE;
|
||||
|
@ -14548,6 +14680,21 @@ qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
_codec ("XML subtitles");
|
||||
caps = gst_caps_new_empty_simple ("application/ttml+xml");
|
||||
break;
|
||||
case FOURCC_c608:
|
||||
_codec ("CEA 608 Closed Caption");
|
||||
caps =
|
||||
gst_caps_new_simple ("closedcaption/x-cea-608", "format",
|
||||
G_TYPE_STRING, "cc_data", NULL);
|
||||
stream->need_process = TRUE;
|
||||
break;
|
||||
case FOURCC_c708:
|
||||
_codec ("CEA 708 Closed Caption");
|
||||
caps =
|
||||
gst_caps_new_simple ("closedcaption/x-cea-708", "format",
|
||||
G_TYPE_STRING, "cdp", NULL);
|
||||
stream->need_process = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
caps = _get_unknown_codec_name ("text", fourcc);
|
||||
|
|
|
@ -213,6 +213,7 @@ static const QtNodeType qt_node_types[] = {
|
|||
{FOURCC_pssh, "protection system specific header", 0},
|
||||
{FOURCC_tenc, "track encryption", 0},
|
||||
{FOURCC_stpp, "XML subtitle sample entry", 0},
|
||||
{FOURCC_clcp, "Closed Caption", 0},
|
||||
{0, "unknown", 0,},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue