From 9d74a608108bdfbc491858bca7af7c8c1b5c549a Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 26 Oct 2020 12:40:49 +1100 Subject: [PATCH] qtmux: support muxing multiple codec_data for h264/h265 Each codec_data is put into its own SampleTableEntry inside the stsd. Part-of: --- gst/isomp4/atoms.c | 38 ++++++++++++++++++++++---------------- gst/isomp4/atoms.h | 2 +- gst/isomp4/gstqtmux.c | 23 +++++++++++++++++++++-- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index d01426f..e439c0b 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -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; diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index 7520473..8f34048 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -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); diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 8971a5e..264aebe 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -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); } -- 2.7.4