diff options
author | Edward Hervey <edward@centricular.com> | 2018-03-08 14:35:28 +0100 |
---|---|---|
committer | Edward Hervey <bilboed@bilboed.com> | 2018-03-09 12:11:23 +0100 |
commit | d5a5dc29c79765d7bce7d1cd06cb14450d6ec5de (patch) | |
tree | 8796f64f828f6c8f49c9acec8202933b5d8d56af | |
parent | a891137583db6adab820e3c6c1e38fe8c56d5f44 (diff) |
qtmux: WIP CC support
-rw-r--r-- | gst/isomp4/atoms.c | 4 | ||||
-rw-r--r-- | gst/isomp4/atoms.h | 3 | ||||
-rw-r--r-- | gst/isomp4/gstqtmux.c | 139 | ||||
-rw-r--r-- | gst/isomp4/gstqtmuxmap.c | 4 |
4 files changed, 127 insertions, 23 deletions
diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index fa40947c2..01d07c895 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -4104,7 +4104,7 @@ atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context, SampleTableEntry * atom_trak_set_caption_type (AtomTRAK * trak, AtomsContext * context, - guint32 caption_type) + guint32 trak_timescale, guint32 caption_type) { SampleTableEntry *ste; AtomGMHD *gmhd = trak->mdia.minf.gmhd; @@ -4115,7 +4115,7 @@ atom_trak_set_caption_type (AtomTRAK * trak, AtomsContext * context, } /* FIXME : Set the timescale to the same timescale as the video trak ! */ - trak->mdia.mdhd.time_info.timescale = 30000; + trak->mdia.mdhd.time_info.timescale = trak_timescale; trak->mdia.hdlr.component_type = FOURCC_mhlr; trak->mdia.hdlr.handler_type = FOURCC_clcp; g_free (trak->mdia.hdlr.name); diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index eb54a69d9..de93e22fd 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -1056,7 +1056,8 @@ SampleTableEntryTX3G * atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContex SampleTableEntryTMCD * atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context, guint trak_timescale, GstVideoTimeCode * tc); -SampleTableEntry * atom_trak_set_caption_type (AtomTRAK *trak, AtomsContext *context, guint32 caption_type); +SampleTableEntry * atom_trak_set_caption_type (AtomTRAK *trak, AtomsContext *context, + guint32 trak_timescale, guint32 caption_type); void atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate, guint32 max_bitrate); diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 9c2609c09..81eee0d9b 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -133,6 +133,7 @@ #include <gst/base/gstbitreader.h> #include <gst/audio/audio.h> #include <gst/video/video.h> +#include <gst/video/video-anc.h> #include <gst/tag/tag.h> #include <gst/pbutils/pbutils.h> @@ -873,34 +874,128 @@ gst_qt_mux_prepare_jpc_buffer (GstQTPad * qtpad, GstBuffer * buf, return newbuf; } +static gsize +extract_608_field_from_cc_data (const guint8 * ccdata, gsize ccdata_size, + guint field, guint8 ** res) +{ + guint8 *storage; + gsize storage_size = 128; + gsize i, res_size = 0; + + storage = g_malloc0 (storage_size); + + /* Iterate over the ccdata and put the corresponding tuples for the given field + * in the storage */ + for (i = 0; i < ccdata_size; i += 3) { + if ((field == 1 && ccdata[i * 3] == 0xfc) || + (field == 2 && ccdata[i * 3] == 0xfd)) { + GST_DEBUG ("Storing matching cc for field %d : 0x%02x 0x%02x", field, + ccdata[i * 3 + 1], ccdata[i * 3 + 2]); + if (res_size >= storage_size) { + storage_size += 128; + storage = g_realloc (storage, storage_size); + } + storage[res_size] = ccdata[i * 3 + 1]; + storage[res_size + 1] = ccdata[i * 3 + 2]; + res_size += 2; + } + } + + if (res_size == 0) { + g_free (storage); + *res = NULL; + return 0; + } + + *res = storage; + return res_size; +} + + static GstBuffer * -gst_qt_mux_prepare_cdat_buffer (GstQTPad * qtpad, GstBuffer * buf, +gst_qt_mux_prepare_caption_buffer (GstQTPad * qtpad, GstBuffer * buf, GstQTMux * qtmux) { - GstBuffer *newbuf; + GstBuffer *newbuf = NULL; GstMapInfo map, inmap; gsize size; - GST_LOG_OBJECT (qtmux, "Preparing cdat buffer"); - if (buf == NULL) return NULL; size = gst_buffer_get_size (buf); - GST_LOG_OBJECT (qtmux, "Preparing buffer of size %" G_GSIZE_FORMAT, size + 8); - newbuf = gst_buffer_new_and_alloc (size + 8); + gst_buffer_map (buf, &inmap, GST_MAP_READ); - /* Let's copy over all metadata and not the memory */ - gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size); + GST_LOG_OBJECT (qtmux, + "Preparing caption buffer %" GST_FOURCC_FORMAT " size:%" G_GSIZE_FORMAT, + GST_FOURCC_ARGS (qtpad->fourcc), size); - gst_buffer_map (newbuf, &map, GST_MAP_WRITE); - gst_buffer_map (buf, &inmap, GST_MAP_READ); + switch (qtpad->fourcc) { + case FOURCC_c608: + { + guint8 *cdat, *cdt2; + gsize cdat_size, cdt2_size, total_size = 0; + gsize write_offs = 0; + + cdat_size = extract_608_field_from_cc_data (map.data, map.size, 1, &cdat); + cdt2_size = extract_608_field_from_cc_data (map.data, map.size, 2, &cdt2); + + if (cdat_size) + total_size += cdat_size + 8; + if (cdt2_size) + total_size += cdt2_size + 8; + if (total_size == 0) { + GST_DEBUG_OBJECT (qtmux, "No 608 data ?"); + /* FIXME : We might want to *always* store something, even if + * it's "empty" CC (i.e. 0x80 0x80) */ + break; + } - GST_WRITE_UINT32_BE (map.data, map.size); - GST_WRITE_UINT32_LE (map.data + 4, FOURCC_cdat); - memcpy (map.data + 8, inmap.data, inmap.size); + newbuf = gst_buffer_new_and_alloc (total_size); + /* Let's copy over all metadata and not the memory */ + gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size); + + gst_buffer_map (newbuf, &map, GST_MAP_WRITE); + if (cdat_size) { + GST_WRITE_UINT32_BE (map.data, cdat_size + 8); + GST_WRITE_UINT32_LE (map.data + 4, FOURCC_cdat); + memcpy (map.data + 8, cdat, cdat_size); + write_offs = cdat_size + 8; + g_free (cdat); + } + if (cdt2_size) { + GST_WRITE_UINT32_BE (map.data + write_offs, cdt2_size + 8); + GST_WRITE_UINT32_LE (map.data + write_offs + 4, FOURCC_cdt2); + memcpy (map.data + write_offs + 8, cdt2, cdt2_size); + g_free (cdt2); + } + gst_buffer_unmap (newbuf, &map); + break; + } + break; + case FOURCC_c708: + { + /* Take the whole CDP */ + newbuf = gst_buffer_new_and_alloc (size + 8); + + /* Let's copy over all metadata and not the memory */ + gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size); + + gst_buffer_map (newbuf, &map, GST_MAP_WRITE); + + GST_WRITE_UINT32_BE (map.data, map.size + 8); + GST_WRITE_UINT32_LE (map.data + 4, FOURCC_ccdp); + memcpy (map.data + 8, inmap.data, inmap.size); + + gst_buffer_unmap (newbuf, &map); + break; + } + default: + /* theoretically this should never happen, but let's keep this here in case */ + GST_WARNING_OBJECT (qtmux, "Unknown caption format"); + break; + } - gst_buffer_unmap (newbuf, &map); gst_buffer_unmap (buf, &inmap); gst_buffer_unref (buf); @@ -5829,6 +5924,7 @@ gst_qt_mux_caption_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad)); GstStructure *structure; guint32 fourcc_entry; + guint32 timescale; if (qtpad->fourcc) return gst_qt_mux_can_renegotiate (qtmux, pad, caps); @@ -5840,12 +5936,12 @@ gst_qt_mux_caption_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) qtpad->is_out_of_order = FALSE; qtpad->sync = FALSE; qtpad->sparse = TRUE; - /* Closed caption data is within a cdat atom */ - qtpad->prepare_buf_func = gst_qt_mux_prepare_cdat_buffer; + /* Closed caption data are within atoms */ + qtpad->prepare_buf_func = gst_qt_mux_prepare_caption_buffer; structure = gst_caps_get_structure (caps, 0); - + /* We know we only handle 608,format=cc_data and 708,format=cdp */ if (gst_structure_has_name (structure, "closedcaption/x-cea-608")) { fourcc_entry = FOURCC_c608; } else if (gst_structure_has_name (structure, "closedcaption/x-cea-708")) { @@ -5853,10 +5949,17 @@ gst_qt_mux_caption_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) } else goto refuse_caps; + /* FIXME: Get the timescale from the video track ? */ + timescale = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad)); + if (!timescale && qtmux->trak_timescale) + timescale = qtmux->trak_timescale; + else if (!timescale) + timescale = 30000; + qtpad->fourcc = fourcc_entry; qtpad->trak_ste = (SampleTableEntry *) atom_trak_set_caption_type (qtpad->trak, - qtmux->context, fourcc_entry); + qtmux->context, timescale, fourcc_entry); gst_object_unref (qtmux); return TRUE; diff --git a/gst/isomp4/gstqtmuxmap.c b/gst/isomp4/gstqtmuxmap.c index 5a19ea9cf..fc59ed21b 100644 --- a/gst/isomp4/gstqtmuxmap.c +++ b/gst/isomp4/gstqtmuxmap.c @@ -167,9 +167,9 @@ "format=(string)utf8" #define CEA608_CAPS \ - "closedcaption/x-cea-608" + "closedcaption/x-cea-608, format=(string)cc_data" #define CEA708_CAPS \ - "closedcaption/x-cea-708" + "closedcaption/x-cea-708, format=(string)cdp" /* FIXME 0.11 - take a look at bugs #580005 and #340375 */ GstQTMuxFormatProp gst_qt_mux_format_list[] = { |