summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2021-07-15 10:59:39 +0200
committerEdward Hervey <bilboed@bilboed.com>2021-07-21 14:33:19 +0000
commit726ea62d25a55d0e964157358fcfefa8d84a94a6 (patch)
tree1aa87feefeab5f6f8d44746a475a80a93c2c3a6d /gst
parent38ec61c58647e5185bcc01c888e711b05326a1a0 (diff)
downloadgstreamer-plugins-bad-726ea62d25a55d0e964157358fcfefa8d84a94a6.tar.gz
mxfdemux: Handle non-frame wrapping
* If we have an index table for non-framed essence, we can handle it * The demuxer has a state which indicates whether it will next fetch a KLV or data contained *within* a KLV. * The position on Essence Tracks always correspond to the next entry to fetch, demuxer offset will be skipped accordingly whenever we switch between partitions (in case of resyncs). A copy of the main clip/custom KLV for that partition is kept to track the position within the essence of that partition. * For clip/custom-wrapped raw audio, if the edit rate is too small (and would cause plenty of tiny buffers to be outputted), specify a minimum number of edit units per buffer. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2371>
Diffstat (limited to 'gst')
-rw-r--r--gst/mxf/mxfdemux.c418
-rw-r--r--gst/mxf/mxfdemux.h26
2 files changed, 332 insertions, 112 deletions
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index 0d0b9f102..3bf56320e 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -34,7 +34,6 @@
* - Handle timecode tracks correctly (where is this documented?)
* - Handle drop-frame field of timecode tracks
* - Handle Generic container system items
- * - Implement correct support for clip-wrapped essence elements.
* - Post structural metadata and descriptive metadata trees as a message on the bus
* and send them downstream as event.
* - Multichannel audio needs channel layouts, define them (SMPTE S320M?).
@@ -89,6 +88,9 @@ static GstFlowReturn
gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv);
static void collect_index_table_segments (GstMXFDemux * demux);
+static gboolean find_entry_for_offset (GstMXFDemux * demux,
+ GstMXFDemuxEssenceTrack * etrack, guint64 offset,
+ GstMXFDemuxIndex * retentry);
GType gst_mxf_demux_pad_get_type (void);
G_DEFINE_TYPE (GstMXFDemuxPad, gst_mxf_demux_pad, GST_TYPE_PAD);
@@ -256,6 +258,8 @@ gst_mxf_demux_reset (GstMXFDemux * demux)
demux->flushing = FALSE;
+ demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
+
demux->footer_partition_pack_offset = 0;
demux->offset = 0;
@@ -397,6 +401,66 @@ gst_mxf_demux_partition_compare (GstMXFDemuxPartition * a,
return 0;
}
+/* Final checks and variable calculation for tracks and partition. This function
+ * can be called repeatedly without any side-effect.
+ */
+static void
+gst_mxf_demux_partition_postcheck (GstMXFDemux * demux,
+ GstMXFDemuxPartition * partition)
+{
+ guint i;
+ GstMXFDemuxPartition *old_partition = demux->current_partition;
+
+ /* If we already handled this partition or it doesn't contain any essence, skip */
+ if (partition->single_track || !partition->partition.body_sid)
+ return;
+
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *cand =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+
+ if (cand->body_sid != partition->partition.body_sid)
+ continue;
+
+ if (!cand->source_package->is_interleaved) {
+ GST_DEBUG_OBJECT (demux,
+ "Assigning single track %d (0x%08x) to partition at offset %"
+ G_GUINT64_FORMAT, cand->track_id, cand->track_number,
+ partition->partition.this_partition);
+
+ partition->single_track = cand;
+
+ if (partition->essence_container_offset != 0
+ && cand->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ GstMXFKLV essence_klv;
+ GstMXFDemuxIndex entry;
+ /* Update the essence container offset for the fact that the index
+ * stream offset is relative to the essence position and not to the
+ * KLV position */
+ if (gst_mxf_demux_peek_klv_packet (demux,
+ partition->partition.this_partition +
+ partition->essence_container_offset,
+ &essence_klv) == GST_FLOW_OK) {
+ partition->essence_container_offset += essence_klv.data_offset;
+ /* And keep a copy of the clip/custom klv for this partition */
+ partition->clip_klv = essence_klv;
+ GST_DEBUG_OBJECT (demux,
+ "Non-frame wrapping, updated essence_container_offset to %"
+ G_GUINT64_FORMAT, partition->essence_container_offset);
+
+ /* And match it against index table, this will also update the track delta_id (if needed) */
+ demux->current_partition = partition;
+ find_entry_for_offset (demux, cand,
+ essence_klv.offset + essence_klv.data_offset, &entry);
+ demux->current_partition = old_partition;
+ }
+ }
+
+ break;
+ }
+ }
+}
+
static GstFlowReturn
gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, GstMXFKLV * klv)
{
@@ -465,6 +529,8 @@ gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, GstMXFKLV * klv)
(GCompareFunc) gst_mxf_demux_partition_compare);
}
+ gst_mxf_demux_partition_postcheck (demux, p);
+
for (l = demux->partitions; l; l = l->next) {
GstMXFDemuxPartition *a, *b;
@@ -746,12 +812,22 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
gboolean new = FALSE;
if (!package->parent.tracks[j]
- || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j]))
+ || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j])) {
+ GST_DEBUG_OBJECT (demux,
+ "Skipping non-timeline track (id:%d number:0x%08x)",
+ package->parent.tracks[j]->track_id,
+ package->parent.tracks[j]->track_number);
continue;
+ }
track = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[j]);
- if ((track->parent.type & 0xf0) != 0x30)
+ if ((track->parent.type & 0xf0) != 0x30) {
+ GST_DEBUG_OBJECT (demux,
+ "Skipping track of type 0x%02x (id:%d number:0x%08x)",
+ track->parent.type, track->parent.track_id,
+ track->parent.track_number);
continue;
+ }
if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0) {
GST_WARNING_OBJECT (demux, "Invalid edit rate");
@@ -931,18 +1007,18 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
caps = NULL;
}
- if (etrack->handler != NULL) {
- MXFEssenceWrapping track_wrapping;
-
- track_wrapping = etrack->handler->get_track_wrapping (track);
- if (track_wrapping == MXF_ESSENCE_WRAPPING_CLIP_WRAPPING) {
- GST_ELEMENT_ERROR (demux, STREAM, NOT_IMPLEMENTED, (NULL),
- ("Clip essence wrapping is not implemented yet."));
- return GST_FLOW_ERROR;
- } else if (track_wrapping == MXF_ESSENCE_WRAPPING_CUSTOM_WRAPPING) {
- GST_ELEMENT_ERROR (demux, STREAM, NOT_IMPLEMENTED, (NULL),
- ("Custom essence wrappings are not supported."));
- return GST_FLOW_ERROR;
+ etrack->min_edit_units = 1;
+ /* Ensure we don't output one buffer per sample for audio */
+ if (gst_util_uint64_scale (GST_SECOND, track->edit_rate.d,
+ track->edit_rate.n) < 10 * GST_MSECOND) {
+ GstStructure *s = gst_caps_get_structure (etrack->caps, 0);
+ const gchar *name = gst_structure_get_name (s);
+ if (g_str_has_prefix (name, "audio/x-raw")) {
+ etrack->min_edit_units =
+ gst_util_uint64_scale (25 * GST_MSECOND, track->edit_rate.n,
+ track->edit_rate.d * GST_SECOND);
+ GST_DEBUG_OBJECT (demux, "Seting miminum number of edit units to %u",
+ etrack->min_edit_units);
}
}
@@ -1199,7 +1275,7 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
}
if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
- GST_DEBUG_OBJECT (demux, "No timeline track");
+ GST_DEBUG_OBJECT (demux, "Skipping Non-timeline track");
continue;
}
@@ -1334,7 +1410,10 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
}
if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
- GST_DEBUG_OBJECT (demux, "No essence track");
+ GST_DEBUG_OBJECT (demux,
+ "No essence track. type:0x%02x track_id:%d track_number:0x%08x",
+ track->parent.type, track->parent.track_id,
+ track->parent.track_number);
if (!pad) {
continue;
} else {
@@ -1572,6 +1651,11 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
if (first_run)
gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+ /* Re-check all existing partitions for source package linking in case the
+ * header partition contains data (allowed in early MXF versions) */
+ for (l = demux->partitions; l; l = l->next)
+ gst_mxf_demux_partition_postcheck (demux, (GstMXFDemuxPartition *) l->data);
+
return GST_FLOW_OK;
error:
@@ -1955,6 +2039,11 @@ get_partition_for_stream_offset (GstMXFDemux * demux,
&& stream_offset < offset_partition->partition.body_offset)
return NULL;
+ GST_DEBUG_OBJECT (demux,
+ "Found this_partition:%" G_GUINT64_FORMAT " body_offset:%"
+ G_GUINT64_FORMAT, offset_partition->partition.this_partition,
+ offset_partition->partition.body_offset);
+
/* Are we overriding into the next partition ? */
if (next_partition) {
guint64 partition_essence_size =
@@ -1963,6 +2052,11 @@ get_partition_for_stream_offset (GstMXFDemux * demux,
offset_partition->essence_container_offset;
guint64 in_partition =
stream_offset - offset_partition->partition.body_offset;
+ GST_DEBUG_OBJECT (demux,
+ "Followed by this_partition:%" G_GUINT64_FORMAT " body_offset:%"
+ G_GUINT64_FORMAT, next_partition->partition.this_partition,
+ next_partition->partition.body_offset);
+
if (in_partition >= partition_essence_size) {
GST_WARNING_OBJECT (demux,
"stream_offset %" G_GUINT64_FORMAT
@@ -2218,6 +2312,14 @@ search_in_segment:
etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
delta_entry->element_delta);
stream_offset += delta_entry->element_delta;
+ } else if (etrack->min_edit_units != 1) {
+ GST_LOG_OBJECT (demux, "Handling minimum edit unit %u",
+ etrack->min_edit_units);
+ entry->duration =
+ MIN (etrack->min_edit_units,
+ (segment->index_start_position + segment->index_duration) - position);
+ entry->size = segment->edit_unit_byte_count * entry->duration;
+ } else {
entry->size = segment->edit_unit_byte_count;
}
} else if (segment->n_index_entries) {
@@ -2285,6 +2387,9 @@ search_in_segment:
"Couldn't find matching partition for stream offset %" G_GUINT64_FORMAT,
stream_offset);
return FALSE;
+ } else {
+ GST_DEBUG_OBJECT (demux, "Entry is in partition %" G_GUINT64_FORMAT,
+ offset_partition->partition.this_partition);
}
/* Convert stream offset to absolute offset using matching partition */
@@ -2424,7 +2529,14 @@ find_entry_for_offset (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
"Invalid offset, exceeds table segment limits");
return FALSE;
}
+ if (etrack->min_edit_units != 1) {
+ retentry->duration = MIN (etrack->min_edit_units,
+ (index_segment->index_start_position +
+ index_segment->index_duration) - position);
+ retentry->size = index_segment->edit_unit_byte_count * retentry->duration;
+ } else {
retentry->size = index_segment->edit_unit_byte_count;
+ }
} else {
/* Find the content package entry containing this offset */
guint cpidx;
@@ -2559,10 +2671,22 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
GST_DEBUG_OBJECT (demux, " essence element type = 0x%02x", klv->key.u[14]);
GST_DEBUG_OBJECT (demux, " essence element number = 0x%02x", klv->key.u[15]);
- if (demux->current_partition->essence_container_offset == 0)
+ if (demux->current_partition->essence_container_offset == 0) {
demux->current_partition->essence_container_offset =
demux->offset - demux->current_partition->partition.this_partition -
demux->run_in;
+ if (demux->current_partition->single_track
+ && demux->current_partition->single_track->wrapping !=
+ MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ demux->current_partition->essence_container_offset += klv->data_offset;
+ demux->current_partition->clip_klv = *klv;
+ /* "consume" the initial bytes of the KLV */
+ klv->consumed = klv->data_offset;
+ GST_DEBUG_OBJECT (demux,
+ "Non-frame wrapping, updated essence_container_offset to %"
+ G_GUINT64_FORMAT, demux->current_partition->essence_container_offset);
+ }
+ }
if (!demux->current_package) {
GST_ERROR_OBJECT (demux, "No package selected yet");
@@ -2582,26 +2706,31 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
/* Identify and fetch the essence track */
track_number = GST_READ_UINT32_BE (&klv->key.u[12]);
- for (i = 0; i < demux->essence_tracks->len; i++) {
- GstMXFDemuxEssenceTrack *tmp =
- &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+ etrack = demux->current_partition->single_track;
+ if (!etrack) {
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *tmp =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
- if (tmp->body_sid == demux->current_partition->partition.body_sid &&
- (tmp->track_number == track_number || tmp->track_number == 0)) {
- etrack = tmp;
- break;
+ if (tmp->body_sid == demux->current_partition->partition.body_sid &&
+ (tmp->track_number == track_number || tmp->track_number == 0)) {
+ etrack = tmp;
+ break;
+ }
}
- }
- if (!etrack) {
- GST_WARNING_OBJECT (demux,
- "No essence track for this essence element found");
- return GST_FLOW_OK;
+ if (!etrack) {
+ GST_WARNING_OBJECT (demux,
+ "No essence track for this essence element found");
+ return GST_FLOW_OK;
+ }
}
GST_DEBUG_OBJECT (demux,
- "Handling generic container essence (track %d , number: 0x%08x)",
- etrack->track_id, track_number);
+ "Handling generic container essence (track %d , position:%"
+ G_GINT64_FORMAT ", number: 0x%08x , frame-wrapped:%d)", etrack->track_id,
+ etrack->position, track_number,
+ etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
/* Fetch the current entry.
*
@@ -2641,18 +2770,67 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
return GST_FLOW_ERROR;
}
} else {
- if (!find_edit_entry (demux, etrack, etrack->position, FALSE, &index_entry,
- FALSE)) {
- /* FIXME : Error out if using non-frame-wrapping */
+ if (!find_edit_entry (demux, etrack, etrack->position, FALSE, &index_entry)) {
GST_DEBUG_OBJECT (demux, "Couldn't find entry");
- } else if (index_entry.offset != demux->offset) {
+ } else if (etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ if (etrack->delta_id != MXF_INDEX_DELTA_ID_IGNORE
+ && index_entry.offset != offset) {
+ GST_ERROR_OBJECT (demux,
+ "demux offset doesn't match %" G_GINT64_FORMAT " entry offset %"
+ G_GUINT64_FORMAT, offset, index_entry.offset);
+ return GST_FLOW_ERROR;
+ }
+ } else if (index_entry.offset != klv->offset + klv->consumed &&
+ index_entry.offset != klv->offset + klv->data_offset) {
GST_ERROR_OBJECT (demux,
- "demux offset doesn't match %" G_GINT64_FORMAT " entry offset %"
- G_GUINT64_FORMAT, demux->offset, index_entry.offset);
+ "KLV offset doesn't match %" G_GINT64_FORMAT " entry offset %"
+ G_GUINT64_FORMAT, klv->offset + klv->consumed, index_entry.offset);
return GST_FLOW_ERROR;
}
}
+ if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ /* We need entry information to deal with non-frame-wrapped content */
+ if (!index_entry.initialized) {
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+ ("Essence with non-frame-wrapping require an index table to be present"));
+ return GST_FLOW_ERROR;
+ }
+ /* We cannot deal with non-frame-wrapping in push mode for now */
+ if (!demux->random_access) {
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+ ("Non-frame-wrapping is not support in push mode"));
+ return GST_FLOW_ERROR;
+ }
+ }
+
+ /* FIXME : If we're peeking and don't need to actually parse the data, we
+ * should avoid pulling the content from upstream */
+ if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ g_assert (index_entry.size);
+ GST_DEBUG_OBJECT (demux, "Should only grab %" G_GUINT64_FORMAT " bytes",
+ index_entry.size);
+ ret =
+ gst_mxf_demux_pull_range (demux, index_entry.offset, index_entry.size,
+ &inbuf);
+ if (ret != GST_FLOW_OK)
+ return ret;
+ if (klv->consumed == 0)
+ klv->consumed = klv->data_offset + index_entry.size;
+ else
+ klv->consumed += index_entry.size;
+ if (klv != &demux->current_partition->clip_klv)
+ demux->current_partition->clip_klv = *klv;
+ GST_LOG_OBJECT (demux,
+ "klv data_offset:%" G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT
+ " consumed:%" G_GUINT64_FORMAT, klv->data_offset, klv->length,
+ klv->consumed);
+ /* Switch back to KLV mode if we're done with this one */
+ if (klv->length + klv->data_offset == klv->consumed)
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
+ else
+ demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
+ } else {
ret = gst_mxf_demux_fill_klv (demux, klv);
if (ret != GST_FLOW_OK)
@@ -2740,7 +2918,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
continue;
}
- if (etrack->position != pad->current_essence_track_position) {
+ if (etrack->position < pad->current_essence_track_position) {
GST_DEBUG_OBJECT (pad,
"Not at current component's position (track:%" G_GINT64_FORMAT
" essence:%" G_GINT64_FORMAT ")", etrack->position,
@@ -2753,7 +2931,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
if (earliest && earliest != pad && earliest->position < pad->position &&
pad->position - earliest->position > demux->max_drift) {
- GST_DEBUG_OBJECT (pad,
+ GST_DEBUG_OBJECT (earliest,
"Pad is too far ahead of time (%" GST_TIME_FORMAT " vs earliest:%"
GST_TIME_FORMAT ")", GST_TIME_ARGS (earliest->position),
GST_TIME_ARGS (pad->position));
@@ -2793,6 +2971,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
GST_BUFFER_DURATION (outbuf) =
gst_util_uint64_scale (GST_SECOND,
+ index_entry.duration *
pad->current_essence_track->source_track->edit_rate.d,
pad->current_essence_track->source_track->edit_rate.n);
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
@@ -2864,6 +3043,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
e = gst_event_new_segment (&shift_segment);
} else
e = gst_event_new_segment (&demux->segment);
+ GST_DEBUG_OBJECT (pad, "Sending segment %" GST_PTR_FORMAT, e);
gst_event_set_seqnum (e, demux->seqnum);
gst_pad_push_event (GST_PAD_CAST (pad), e);
pad->need_segment = FALSE;
@@ -2875,17 +3055,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
}
pad->position += GST_BUFFER_DURATION (outbuf);
- pad->current_material_track_position++;
-
- GST_DEBUG_OBJECT (pad,
- "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: pts %"
- GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT
- " position %" G_GUINT64_FORMAT, gst_buffer_get_size (outbuf),
- pad->material_track->parent.track_id,
- GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
- GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
- pad->current_essence_track_position);
+ pad->current_material_track_position += index_entry.duration;
if (pad->discont) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
@@ -2904,6 +3074,16 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
"Replacing empty gap buffer with gap event %" GST_PTR_FORMAT, gap);
gst_pad_push_event (GST_PAD_CAST (pad), gap);
} else {
+ GST_DEBUG_OBJECT (pad,
+ "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: pts %"
+ GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT
+ " position %" G_GUINT64_FORMAT, gst_buffer_get_size (outbuf),
+ pad->material_track->parent.track_id,
+ GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
+ pad->current_essence_track_position);
+
ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
}
outbuf = NULL;
@@ -2916,7 +3096,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
if (ret != GST_FLOW_OK)
goto out;
- pad->current_essence_track_position++;
+ pad->current_essence_track_position += index_entry.duration;
if (pad->current_component) {
if (pad->current_component_duration > 0 &&
@@ -2929,6 +3109,9 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
pad->current_component_index + 1);
if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) {
GST_ERROR_OBJECT (demux, "Switching component failed");
+ } else {
+ pad->current_essence_track->position =
+ pad->current_essence_track_position;
}
} else if (etrack->duration > 0
&& pad->current_essence_track_position >= etrack->duration) {
@@ -2964,7 +3147,7 @@ out:
if (outbuf)
gst_buffer_unref (outbuf);
- etrack->position++;
+ etrack->position += index_entry.duration;
return ret;
}
@@ -3581,25 +3764,6 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, GstMXFKLV * klv,
G_GUINT64_FORMAT ", key: %s", klv->length,
demux->offset, mxf_ul_to_string (key, key_str));
} else if (mxf_is_partition_pack (key)) {
-
- /* If this partition contains the start of an essence container
- * set the positions of all essence streams to 0
- */
- if (ret == GST_FLOW_OK && demux->current_partition
- && demux->current_partition->partition.body_sid != 0
- && demux->current_partition->partition.body_offset == 0) {
- guint i;
-
- for (i = 0; i < demux->essence_tracks->len; i++) {
- GstMXFDemuxEssenceTrack *etrack =
- &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
-
- if (etrack->body_sid != demux->current_partition->partition.body_sid)
- continue;
-
- etrack->position = 0;
- }
- }
ret = gst_mxf_demux_handle_partition_pack (demux, klv);
} else if (mxf_is_primer_pack (key)) {
ret = gst_mxf_demux_handle_primer_pack (demux, klv);
@@ -3639,34 +3803,6 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, GstMXFKLV * klv,
demux->offset, mxf_ul_to_string (key, key_str));
}
- /* In pull mode try to get the last metadata */
- if (mxf_is_partition_pack (key) && ret == GST_FLOW_OK
- && demux->pull_footer_metadata
- && demux->random_access && demux->current_partition
- && demux->current_partition->partition.type == MXF_PARTITION_PACK_HEADER
- && (!demux->current_partition->partition.closed
- || !demux->current_partition->partition.complete)
- && (demux->footer_partition_pack_offset != 0 || demux->random_index_pack)) {
- GST_DEBUG_OBJECT (demux,
- "Open or incomplete header partition, trying to get final metadata from the last partitions");
- gst_mxf_demux_parse_footer_metadata (demux);
- demux->pull_footer_metadata = FALSE;
-
- if (demux->current_partition->partition.body_sid != 0 &&
- demux->current_partition->partition.body_offset == 0) {
- guint i;
- for (i = 0; i < demux->essence_tracks->len; i++) {
- GstMXFDemuxEssenceTrack *etrack =
- &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
-
- if (etrack->body_sid != demux->current_partition->partition.body_sid)
- continue;
-
- etrack->position = 0;
- }
- }
- }
-
beach:
return ret;
}
@@ -3676,6 +3812,8 @@ gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
{
GList *l;
+ GST_LOG_OBJECT (demux, "offset %" G_GUINT64_FORMAT, offset);
+
/* This partition will already be parsed, otherwise
* the position wouldn't be in the index */
for (l = demux->partitions; l; l = l->next) {
@@ -3684,6 +3822,15 @@ gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
if (p->partition.this_partition + demux->run_in <= offset)
demux->current_partition = p;
}
+ if (demux->current_partition)
+ GST_DEBUG_OBJECT (demux,
+ "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
+ G_GUINT64_FORMAT ")", demux->current_partition,
+ demux->current_partition->partition.body_sid,
+ demux->current_partition->partition.index_sid,
+ demux->current_partition->partition.this_partition);
+ else
+ GST_DEBUG_OBJECT (demux, "Haven't found partition for offset yet");
}
static guint64
@@ -3887,6 +4034,16 @@ gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
}
}
+ if (demux->state == GST_MXF_DEMUX_STATE_ESSENCE) {
+ g_assert (demux->current_partition->single_track
+ && demux->current_partition->single_track->wrapping !=
+ MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
+ /* Feeding essence directly (i.e. in the middle of a custom/clip KLV) */
+ ret =
+ gst_mxf_demux_handle_generic_container_essence_element (demux,
+ &demux->current_partition->clip_klv, FALSE);
+ gst_mxf_demux_consume_klv (demux, &demux->current_partition->clip_klv);
+ } else {
ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
@@ -3945,6 +4102,14 @@ gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
demux->offset = offset + demux->run_in;
gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
+ if (p->current_essence_track->wrapping !=
+ MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
+ demux->current_partition->clip_klv.consumed =
+ offset - demux->current_partition->clip_klv.offset;
+ } else
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
+ p->current_essence_track->position = position;
ret = GST_FLOW_OK;
goto beach;
@@ -4102,8 +4267,17 @@ gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
demux->offset, position, earliest->current_essence_track->track_id,
earliest->current_essence_track->body_sid,
earliest->current_essence_track->index_sid);
+ if (demux->current_partition->single_track
+ && demux->current_partition->single_track->wrapping !=
+ MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
+ demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
+ demux->current_partition->clip_klv.consumed =
+ offset - demux->current_partition->clip_klv.offset;
+ } else
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
earliest->current_essence_track->position = position;
+ GST_DEBUG_OBJECT (earliest, "Switching to this pad");
break;
}
}
@@ -4120,7 +4294,7 @@ gst_mxf_demux_loop (GstPad * pad)
demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
- if (demux->run_in == -1) {
+ if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
GstMXFKLV klv;
/* Skip run-in, which is at most 64K and is finished
@@ -4135,6 +4309,7 @@ gst_mxf_demux_loop (GstPad * pad)
GST_DEBUG_OBJECT (demux,
"Found header partition pack at offset %" G_GUINT64_FORMAT,
demux->offset);
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
demux->run_in = demux->offset;
break;
}
@@ -4147,7 +4322,7 @@ gst_mxf_demux_loop (GstPad * pad)
goto pause;
}
- /* First of all pull&parse the random index pack at EOF */
+ /* Grab the RIP at the end of the file (if present) */
gst_mxf_demux_pull_random_index_pack (demux);
}
@@ -4268,6 +4443,7 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
demux->run_in = -1;
demux->offset = 0;
+ demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
}
if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
@@ -4292,7 +4468,7 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
if (gst_adapter_available (demux->adapter) < 16)
break;
- if (demux->run_in == -1) {
+ if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
/* Skip run-in, which is at most 64K and is finished
* by a header partition pack */
@@ -4307,6 +4483,7 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
"Found header partition pack at offset %" G_GUINT64_FORMAT,
demux->offset);
demux->run_in = demux->offset;
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
break;
}
gst_adapter_flush (demux->adapter, 1);
@@ -4320,11 +4497,11 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
continue;
}
- /* Need more data */
- if (demux->run_in == -1 && demux->offset < 64 * 1024)
- break;
+ if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
+ /* Need more data */
+ if (demux->offset < 64 * 1024)
+ break;
- if (G_UNLIKELY (demux->run_in == -1)) {
GST_ERROR_OBJECT (demux, "No valid header partition pack found");
ret = GST_FLOW_ERROR;
break;
@@ -4333,6 +4510,9 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
if (gst_adapter_available (demux->adapter) < 17)
break;
+ /* FIXME : Handle non-klv state */
+ g_assert (demux->state == GST_MXF_DEMUX_STATE_KLV);
+
/* Now actually do something */
memset (&klv, 0, sizeof (GstMXFKLV));
@@ -4644,8 +4824,8 @@ gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
if (format != GST_FORMAT_TIME)
goto wrong_format;
- flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
- keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
+ flush = !!(flags & GST_SEEK_FLAG_FLUSH);
+ keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
/* Work on a copy until we are sure the seek succeeded. */
memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
@@ -4935,8 +5115,8 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
if (rate <= 0.0)
goto wrong_rate;
- flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
- keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
+ flush = !!(flags & GST_SEEK_FLAG_FLUSH);
+ keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
if (!demux->index_table_segments_collected) {
collect_index_table_segments (demux);
@@ -4984,6 +5164,7 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
/* Initialize and reset ourselves if needed */
if (flush || seeksegment.position != demux->segment.position) {
+ GList *tmp;
if (!demux->metadata_resolved || demux->update_metadata) {
if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
@@ -4991,6 +5172,13 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
}
}
+ /* Reset all single-track KLV tracking */
+ for (tmp = demux->partitions; tmp; tmp = tmp->next) {
+ GstMXFDemuxPartition *partition = (GstMXFDemuxPartition *) tmp->data;
+ if (partition->single_track) {
+ partition->clip_klv.consumed = 0;
+ }
+ }
}
keyunit_ts = seeksegment.position;
@@ -5084,6 +5272,7 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
}
p->current_essence_track_position = position;
}
+ p->current_essence_track->position = p->current_essence_track_position;
p->discont = TRUE;
}
gst_flow_combiner_reset (demux->flowcombiner);
@@ -5094,6 +5283,13 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
demux->offset = new_offset + demux->run_in;
}
gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
+ /* Reset the state accordingly */
+ if (demux->current_partition->single_track
+ && demux->current_partition->single_track->wrapping !=
+ MXF_ESSENCE_WRAPPING_FRAME_WRAPPING)
+ demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
+ else
+ demux->state = GST_MXF_DEMUX_STATE_KLV;
}
if (G_UNLIKELY (demux->close_seg_event)) {
diff --git a/gst/mxf/mxfdemux.h b/gst/mxf/mxfdemux.h
index 2936ccb4b..d079a1de1 100644
--- a/gst/mxf/mxfdemux.h
+++ b/gst/mxf/mxfdemux.h
@@ -67,6 +67,13 @@ typedef struct {
guint64 consumed;
} GstMXFKLV;
+
+typedef enum {
+ GST_MXF_DEMUX_STATE_UNKNOWN, /* Still looking for run-in/klv */
+ GST_MXF_DEMUX_STATE_KLV, /* Next read/fetch is a KLV */
+ GST_MXF_DEMUX_STATE_ESSENCE /* Next read/fetch is within a KLV (i.e. non-frame-wrapped) */
+} GstMXFDemuxState;
+
typedef struct _GstMXFDemuxPartition GstMXFDemuxPartition;
typedef struct _GstMXFDemuxEssenceTrack GstMXFDemuxEssenceTrack;
@@ -75,9 +82,19 @@ struct _GstMXFDemuxPartition
MXFPartitionPack partition;
MXFPrimerPack primer;
gboolean parsed_metadata;
- /* Relative offset at which essence starts within this partition.*/
+
+ /* Relative offset at which essence starts within this partition.
+ *
+ * For Frame wrapping, the position of the first KLV
+ * For Clip/Custom wrapping, the position of the first byte of essence in the KLV
+ **/
guint64 essence_container_offset;
+ /* If the partition contains a single essence track, point to it */
+ GstMXFDemuxEssenceTrack *single_track;
+
+ /* For clip-based wrapping, the essence KLV */
+ GstMXFKLV clip_klv;
};
#define MXF_INDEX_DELTA_ID_UNKNOWN -1
@@ -121,6 +138,10 @@ struct _GstMXFDemuxEssenceTrack
MXFEssenceWrapping wrapping;
+ /* Minimum number of edit unit to send in one go.
+ * Default : 1
+ * Used for raw audio track */
+ guint min_edit_units;
};
typedef struct
@@ -217,6 +238,8 @@ struct _GstMXFDemux
GPtrArray *src;
/* < private > */
+ GstMXFDemuxState state;
+
gboolean have_group_id;
guint group_id;
@@ -260,6 +283,7 @@ struct _GstMXFDemux
MXFMetadataPreface *preface;
GHashTable *metadata;
+ /* Current Material Package */
MXFUMID current_package_uid;
MXFMetadataGenericPackage *current_package;
gchar *current_package_string;