summaryrefslogtreecommitdiff
path: root/gst/isomp4/gstqtmux.c
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2018-03-08 14:35:28 +0100
committerEdward Hervey <bilboed@bilboed.com>2018-03-09 12:11:23 +0100
commitd5a5dc29c79765d7bce7d1cd06cb14450d6ec5de (patch)
tree8796f64f828f6c8f49c9acec8202933b5d8d56af /gst/isomp4/gstqtmux.c
parenta891137583db6adab820e3c6c1e38fe8c56d5f44 (diff)
qtmux: WIP CC support
Diffstat (limited to 'gst/isomp4/gstqtmux.c')
-rw-r--r--gst/isomp4/gstqtmux.c139
1 files changed, 121 insertions, 18 deletions
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;