qtmux: support muxing multiple codec_data for h264/h265
authorMatthew Waters <matthew@centricular.com>
Mon, 26 Oct 2020 01:40:49 +0000 (12:40 +1100)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 2 Nov 2020 03:32:50 +0000 (03:32 +0000)
Each codec_data is put into its own SampleTableEntry inside the stsd.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/787>

gst/isomp4/atoms.c
gst/isomp4/atoms.h
gst/isomp4/gstqtmux.c

index d01426f..e439c0b 100644 (file)
@@ -2334,11 +2334,15 @@ atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
 
   /* Last two entries might be the same size here as we only merge once the
    * next chunk is started */
-  if ((len = atom_array_get_len (&stsc->entries)) > 1 &&
-      ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
-          (atom_array_index (&stsc->entries, len - 2)).samples_per_chunk)) {
-    stsc->entries.len--;
-    last_entries_merged = TRUE;
+  if ((len = atom_array_get_len (&stsc->entries)) > 1) {
+    STSCEntry *prev_entry = &atom_array_index (&stsc->entries, len - 2);
+    STSCEntry *current_entry = &atom_array_index (&stsc->entries, len - 1);
+    if (prev_entry->samples_per_chunk == current_entry->samples_per_chunk &&
+        prev_entry->sample_description_index ==
+        current_entry->sample_description_index) {
+      stsc->entries.len--;
+      last_entries_merged = TRUE;
+    }
   }
 
   prop_copy_uint32 (atom_array_get_len (&stsc->entries), buffer, size, offset);
@@ -3076,7 +3080,8 @@ atom_wave_copy_data (AtomWAVE * wave, guint8 ** buffer,
 /* add samples to tables */
 
 void
-atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
+atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples,
+    guint32 sample_description_index)
 {
   gint len;
 
@@ -3089,13 +3094,13 @@ atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
     nentry = &atom_array_index (&stsc->entries, len - 1);
     nentry->first_chunk = first_chunk;
     nentry->samples_per_chunk = nsamples;
-    nentry->sample_description_index = 1;
+    nentry->sample_description_index = sample_description_index;
   } else {
     STSCEntry nentry;
 
     nentry.first_chunk = first_chunk;
     nentry.samples_per_chunk = nsamples;
-    nentry.sample_description_index = 1;
+    nentry.sample_description_index = sample_description_index;
     atom_array_append (&stsc->entries, nentry, 128);
   }
 }
@@ -3231,7 +3236,8 @@ atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta,
   atom_stsz_add_entry (&stbl->stsz, nsamples, size);
   if (atom_stco64_add_entry (&stbl->stco64, chunk_offset)) {
     atom_stsc_add_new_entry (&stbl->stsc,
-        atom_stco64_get_entry_count (&stbl->stco64), nsamples);
+        atom_stco64_get_entry_count (&stbl->stco64), nsamples,
+        stbl->stsd.n_entries);
   } else {
     atom_stsc_update_entry (&stbl->stsc,
         atom_stco64_get_entry_count (&stbl->stco64), nsamples);
@@ -4001,7 +4007,7 @@ atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
     mp4v->temporal_quality = 512;
   }
 
-  stsd->entries = g_list_prepend (stsd->entries, mp4v);
+  stsd->entries = g_list_append (stsd->entries, mp4v);
   stsd->n_entries++;
   return mp4v;
 }
@@ -4374,14 +4380,14 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
     dheight = entry->height;
   }
 
-  atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
-  atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
+  if (trak->mdia.minf.stbl.stsd.n_entries < 1) {
+    atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
+    trak->is_video = TRUE;
+    trak->is_h264 = (entry->fourcc == FOURCC_avc1
+        || entry->fourcc == FOURCC_avc3);
+  }
   ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
 
-  trak->is_video = TRUE;
-  trak->is_h264 = (entry->fourcc == FOURCC_avc1
-      || entry->fourcc == FOURCC_avc3);
-
   ste->version = entry->version;
   ste->width = entry->width;
   ste->height = entry->height;
index 7520473..8f34048 100644 (file)
@@ -952,7 +952,7 @@ void       atom_stbl_add_samples       (AtomSTBL * stbl, guint32 nsamples,
                                         guint64 chunk_offset, gboolean sync,
                                         gint64 pts_offset);
 void       atom_stsc_add_new_entry     (AtomSTSC * stsc,
-                                        guint32 first_chunk, guint32 nsamples);
+                                        guint32 first_chunk, guint32 nsamples, guint32 sample_description_index);
 
 AtomMOOV*  atom_moov_new               (AtomsContext *context);
 void       atom_moov_free              (AtomMOOV *moov);
index 8971a5e..264aebe 100644 (file)
@@ -4004,7 +4004,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
               if (qpad->sample_offset - nsamples > 0) {
                 stbl->stsc.entries.len = i;
                 atom_stsc_add_new_entry (&stbl->stsc, chunk_index,
-                    qpad->sample_offset - nsamples);
+                    qpad->sample_offset - nsamples, stbl->stsd.n_entries);
               } else {
                 stbl->stsc.entries.len = i;
                 stbl->stco64.entries.len--;
@@ -4013,7 +4013,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
               /* Everything in a single chunk */
               stbl->stsc.entries.len = 0;
               atom_stsc_add_new_entry (&stbl->stsc, chunk_index,
-                  qpad->sample_offset);
+                  qpad->sample_offset, stbl->stsd.n_entries);
             }
           } else {
             stbl->stco64.entries.len = 0;
@@ -5718,6 +5718,22 @@ check_field (GQuark field_id, const GValue * value, gpointer user_data)
 {
   GstStructure *structure = (GstStructure *) user_data;
   const GValue *other = gst_structure_id_get_value (structure, field_id);
+  const gchar *name = gst_structure_get_name (structure);
+
+  if (g_str_has_prefix (name, "video/")) {
+    /* ignore framerate with video caps */
+    if (g_strcmp0 (g_quark_to_string (field_id), "framerate") == 0)
+      return TRUE;
+  }
+
+  if (g_strcmp0 (name, "video/x-h264") == 0 ||
+      g_strcmp0 (name, "video/x-h265") == 0) {
+    /* we support muxing multiple codec_data structures */
+    if (g_strcmp0 (g_quark_to_string (field_id), "codec_data") == 0) {
+      return TRUE;
+    }
+  }
+
   if (other == NULL)
     return FALSE;
   return gst_value_compare (value, other) == GST_VALUE_EQUAL;
@@ -5730,6 +5746,9 @@ gst_qtmux_caps_is_subset_full (GstQTMux * qtmux, GstCaps * subset,
   GstStructure *sub_s = gst_caps_get_structure (subset, 0);
   GstStructure *sup_s = gst_caps_get_structure (superset, 0);
 
+  if (!gst_structure_has_name (sup_s, gst_structure_get_name (sub_s)))
+    return FALSE;
+
   return gst_structure_foreach (sub_s, check_field, sup_s);
 }