qtmux: add support for text/x-raw subtitles
authorThiago Santos <ts.santos@sisa.samsung.com>
Thu, 6 Feb 2014 15:15:22 +0000 (12:15 -0300)
committerThiago Santos <ts.santos@sisa.samsung.com>
Fri, 7 Feb 2014 16:10:24 +0000 (13:10 -0300)
Adds it to mp4mux, qtmux and gppmux.

Buffers need to be prefixed with 2 bytes for the text length before
being muxed.

https://bugzilla.gnome.org/show_bug.cgi?id=581295

gst/isomp4/gstqtmux.c
gst/isomp4/gstqtmuxmap.c

index 085542b..424f951 100644 (file)
@@ -550,6 +550,39 @@ gst_qt_mux_prepare_jpc_buffer (GstQTPad * qtpad, GstBuffer * buf,
   return newbuf;
 }
 
+static GstBuffer *
+gst_qt_mux_prepare_tx3g_buffer (GstQTPad * qtpad, GstBuffer * buf,
+    GstQTMux * qtmux)
+{
+  GstBuffer *newbuf;
+  GstMapInfo frommap;
+  GstMapInfo tomap;
+  gsize size;
+
+  GST_LOG_OBJECT (qtmux, "Preparing tx3g buffer %" GST_PTR_FORMAT, buf);
+
+  if (buf == NULL)
+    return NULL;
+
+  size = gst_buffer_get_size (buf);
+  newbuf = gst_buffer_new_and_alloc (size + 2);
+
+  gst_buffer_map (buf, &frommap, GST_MAP_READ);
+  gst_buffer_map (newbuf, &tomap, GST_MAP_WRITE);
+
+  GST_WRITE_UINT16_BE (tomap.data, size);
+  memcpy (tomap.data + 2, frommap.data, size);
+
+  gst_buffer_unmap (newbuf, &tomap);
+  gst_buffer_unmap (buf, &frommap);
+
+  gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size);
+
+  gst_buffer_unref (buf);
+
+  return newbuf;
+}
+
 static void
 gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list,
     const char *tag, const char *tag2, guint32 fourcc)
@@ -1806,6 +1839,10 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
   guint32 timescale;
   GstClockTime first_ts = GST_CLOCK_TIME_NONE;
 
+  /* for setting some subtitles fields */
+  guint max_width = 0;
+  guint max_height = 0;
+
   GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
 
   /* pushing last buffers for each pad */
@@ -1845,6 +1882,12 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
       first_ts = qtpad->last_dts;
     }
 
+    /* subtitles need to know the video width/height,
+     * it is stored shifted 16 bits to the left according to the
+     * spec */
+    max_width = MAX (max_width, (qtpad->trak->tkhd.width >> 16));
+    max_height = MAX (max_height, (qtpad->trak->tkhd.height >> 16));
+
     /* update average bitrate of streams if needed */
     {
       guint32 avgbitrate = 0;
@@ -1860,6 +1903,23 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
     }
   }
 
+  /* need to update values on subtitle traks now that we know the
+   * max width and height */
+  for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
+    GstCollectData *cdata = (GstCollectData *) walk->data;
+    GstQTPad *qtpad = (GstQTPad *) cdata;
+
+    if (!qtpad->fourcc) {
+      GST_DEBUG_OBJECT (qtmux, "Pad %s has never had buffers",
+          GST_PAD_NAME (qtpad->collect.pad));
+      continue;
+    }
+
+    if (qtpad->fourcc == FOURCC_tx3g) {
+      atom_trak_tx3g_update_dimension (qtpad->trak, max_width, max_height);
+    }
+  }
+
   if (qtmux->fragment_sequence) {
     GstSegment segment;
 
@@ -3142,6 +3202,8 @@ gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
 {
   GstPad *pad = qtpad->collect.pad;
   GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
+  GstStructure *structure;
+  SubtitleSampleEntry entry = { 0, };
 
   qtpad->prepare_buf_func = NULL;
 
@@ -3168,16 +3230,38 @@ gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
       GST_DEBUG_PAD_NAME (pad), caps);
 
   /* subtitles default */
+  subtitle_sample_entry_init (&entry);
   qtpad->is_out_of_order = FALSE;
   qtpad->sync = FALSE;
+  qtpad->prepare_buf_func = NULL;
 
-  /* TODO fill me */
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (gst_structure_has_name (structure, "text/x-raw")) {
+    const gchar *format = gst_structure_get_string (structure, "format");
+    if (format && strcmp (format, "utf8") == 0) {
+      entry.fourcc = FOURCC_tx3g;
+      qtpad->prepare_buf_func = gst_qt_mux_prepare_tx3g_buffer;
+    }
+  }
+
+  if (!entry.fourcc)
+    goto refuse_caps;
+
+  qtpad->fourcc = entry.fourcc;
+  atom_trak_set_subtitle_type (qtpad->trak, qtmux->context, &entry);
 
   gst_object_unref (qtmux);
-  /* not implemented */
-  return FALSE;
+  return TRUE;
 
   /* ERRORS */
+refuse_caps:
+  {
+    GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
+        GST_PAD_NAME (pad), caps);
+    gst_object_unref (qtmux);
+    return FALSE;
+  }
 refuse_renegotiation:
   {
     GST_WARNING_OBJECT (qtmux,
index 3cf8136..5b17f85 100644 (file)
   "audio/x-alac, " \
   COMMON_AUDIO_CAPS(2, MAX)
 
+#define TEXT_UTF8 \
+  "text/x-raw, " \
+  "format=(string)utf8"
+
 /* FIXME 0.11 - take a look at bugs #580005 and #340375 */
 GstQTMuxFormatProp gst_qt_mux_format_list[] = {
   /* original QuickTime format; see Apple site (e.g. qtff.pdf) */
@@ -167,7 +171,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
             "audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
             "audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
             AMR_CAPS " ; " ALAC_CAPS),
-      GST_STATIC_CAPS_NONE}
+      GST_STATIC_CAPS (TEXT_UTF8)}
   ,
   /* ISO 14496-14: mp42 as ISO base media extension
    * (supersedes original ISO 144996-1 mp41) */
@@ -181,7 +185,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
         GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";"
             "video/x-mp4-part," COMMON_VIDEO_CAPS),
         GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS " ; " ALAC_CAPS),
-      GST_STATIC_CAPS_NONE}
+      GST_STATIC_CAPS (TEXT_UTF8)}
   ,
   /* Microsoft Smooth Streaming fmp4/isml */
   /* TODO add WMV/WMA support */
@@ -207,7 +211,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
         GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"),
         GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
         GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS),
-      GST_STATIC_CAPS_NONE}
+      GST_STATIC_CAPS (TEXT_UTF8)}
   ,
   /* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */
   {