mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 11:10:37 +00:00
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>
This commit is contained in:
parent
38ec61c586
commit
726ea62d25
2 changed files with 333 additions and 113 deletions
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue