mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 15:27:07 +00:00
a926db34ad
Original commit message from CVS: * gst/mxf/mxfdemux.c: (gst_mxf_demux_reset), (gst_mxf_demux_handle_random_index_pack), (gst_mxf_demux_pull_random_index_pack), (gst_mxf_demux_loop): * gst/mxf/mxfdemux.h: * gst/mxf/mxfparse.c: (mxf_random_index_pack_parse): * gst/mxf/mxfparse.h: * gst/mxf/mxftypes.h: Implement parsing of the random index pack, which provides a seek table (including body sid) to the start of partition packs. Later this will be used for reading all index table segments of the complete file efficiently.
3135 lines
95 KiB
C
3135 lines
95 KiB
C
/* GStreamer
|
|
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/* TODO:
|
|
* - start at correct position of the component, switch components
|
|
* - RandomIndex / IndexSegment support
|
|
* - timecode tracks
|
|
* - descriptive metadata
|
|
* - generic container system items
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "mxfdemux.h"
|
|
#include "mxfparse.h"
|
|
#include "mxfaes-bwf.h"
|
|
#include "mxfmpeg.h"
|
|
#include "mxfdv-dif.h"
|
|
|
|
#include <string.h>
|
|
|
|
static GstStaticPadTemplate mxf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("application/mxf")
|
|
);
|
|
|
|
static GstStaticPadTemplate audio_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("audio_%u",
|
|
GST_PAD_SRC,
|
|
GST_PAD_SOMETIMES,
|
|
GST_STATIC_CAPS_ANY);
|
|
|
|
static GstStaticPadTemplate video_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("video_%u",
|
|
GST_PAD_SRC,
|
|
GST_PAD_SOMETIMES,
|
|
GST_STATIC_CAPS_ANY);
|
|
|
|
static GstStaticPadTemplate data_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("data_%u",
|
|
GST_PAD_SRC,
|
|
GST_PAD_SOMETIMES,
|
|
GST_STATIC_CAPS_ANY);
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (mxfdemux_debug);
|
|
#define GST_CAT_DEFAULT mxfdemux_debug
|
|
|
|
#define GST_TYPE_MXF_PAD (gst_mxf_pad_get_type())
|
|
#define GST_MXF_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MXF_PAD,GstMXFPad))
|
|
#define GST_MXF_PAD_CAST(pad) ((GstMXFPad *) pad)
|
|
#define GST_IS_MXF_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MXF_PAD))
|
|
|
|
typedef struct
|
|
{
|
|
GstPad parent;
|
|
|
|
guint32 track_id;
|
|
MXFMetadataTrackType track_type;
|
|
gboolean need_segment;
|
|
|
|
GstFlowReturn last_flow;
|
|
|
|
guint64 essence_element_count;
|
|
MXFEssenceElementHandler handle_essence_element;
|
|
gpointer mapping_data;
|
|
|
|
GstTagList *tags;
|
|
|
|
guint current_material_component;
|
|
MXFMetadataGenericPackage *material_package;
|
|
MXFMetadataTrack *material_track;
|
|
MXFMetadataStructuralComponent *component;
|
|
|
|
MXFMetadataGenericPackage *source_package;
|
|
MXFMetadataTrack *source_track;
|
|
|
|
GstCaps *caps;
|
|
} GstMXFPad;
|
|
|
|
typedef struct
|
|
{
|
|
GstPadClass parent;
|
|
|
|
} GstMXFPadClass;
|
|
|
|
G_DEFINE_TYPE (GstMXFPad, gst_mxf_pad, GST_TYPE_PAD);
|
|
|
|
static void
|
|
gst_mxf_pad_finalize (GObject * object)
|
|
{
|
|
GstMXFPad *pad = GST_MXF_PAD (object);
|
|
|
|
gst_caps_replace (&pad->caps, NULL);
|
|
|
|
g_free (pad->mapping_data);
|
|
pad->mapping_data = NULL;
|
|
|
|
if (pad->tags) {
|
|
gst_tag_list_free (pad->tags);
|
|
pad->tags = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (gst_mxf_pad_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gst_mxf_pad_class_init (GstMXFPadClass * klass)
|
|
{
|
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
|
|
gobject_class->finalize = gst_mxf_pad_finalize;
|
|
}
|
|
|
|
static void
|
|
gst_mxf_pad_init (GstMXFPad * pad)
|
|
{
|
|
pad->last_flow = GST_FLOW_OK;
|
|
}
|
|
|
|
static gboolean gst_mxf_demux_sink_event (GstPad * pad, GstEvent * event);
|
|
static gboolean gst_mxf_demux_src_event (GstPad * pad, GstEvent * event);
|
|
static const GstQueryType *gst_mxf_demux_src_query_type (GstPad * pad);
|
|
static gboolean gst_mxf_demux_src_query (GstPad * pad, GstQuery * query);
|
|
|
|
GST_BOILERPLATE (GstMXFDemux, gst_mxf_demux, GstElement, GST_TYPE_ELEMENT);
|
|
|
|
static void
|
|
gst_mxf_demux_flush (GstMXFDemux * demux, gboolean discont)
|
|
{
|
|
GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
|
|
|
|
gst_adapter_clear (demux->adapter);
|
|
|
|
demux->flushing = FALSE;
|
|
|
|
/* Only in push mode */
|
|
if (!demux->random_access) {
|
|
/* We reset the offset and will get one from first push */
|
|
demux->offset = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_remove_pad (GstMXFPad * pad, GstMXFDemux * demux)
|
|
{
|
|
gst_element_remove_pad (GST_ELEMENT (demux), GST_PAD (pad));
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
|
|
{
|
|
GST_DEBUG_OBJECT (demux, "Resetting MXF state");
|
|
mxf_partition_pack_reset (&demux->partition);
|
|
mxf_primer_pack_reset (&demux->primer);
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
|
|
{
|
|
guint i;
|
|
|
|
GST_DEBUG_OBJECT (demux, "Resetting metadata");
|
|
|
|
demux->update_metadata = TRUE;
|
|
demux->final_metadata = FALSE;
|
|
|
|
demux->current_package = NULL;
|
|
|
|
if (demux->src) {
|
|
for (i = 0; i < demux->src->len; i++) {
|
|
GstMXFPad *pad = g_ptr_array_index (demux->src, i);
|
|
|
|
pad->material_track = NULL;
|
|
pad->material_package = NULL;
|
|
pad->component = NULL;
|
|
pad->source_track = NULL;
|
|
pad->source_package = NULL;
|
|
}
|
|
}
|
|
|
|
mxf_metadata_preface_reset (&demux->preface);
|
|
|
|
if (demux->identification) {
|
|
for (i = 0; i < demux->identification->len; i++)
|
|
mxf_metadata_identification_reset (&g_array_index (demux->identification,
|
|
MXFMetadataIdentification, i));
|
|
g_array_free (demux->identification, TRUE);
|
|
demux->identification = NULL;
|
|
}
|
|
|
|
mxf_metadata_content_storage_reset (&demux->content_storage);
|
|
|
|
if (demux->essence_container_data) {
|
|
for (i = 0; i < demux->essence_container_data->len; i++)
|
|
mxf_metadata_essence_container_data_reset (&g_array_index
|
|
(demux->essence_container_data, MXFMetadataEssenceContainerData, i));
|
|
g_array_free (demux->essence_container_data, TRUE);
|
|
demux->essence_container_data = NULL;
|
|
}
|
|
|
|
if (demux->material_package) {
|
|
for (i = 0; i < demux->material_package->len; i++)
|
|
mxf_metadata_generic_package_reset (&g_array_index
|
|
(demux->material_package, MXFMetadataGenericPackage, i));
|
|
g_array_free (demux->material_package, TRUE);
|
|
demux->material_package = NULL;
|
|
}
|
|
|
|
if (demux->source_package) {
|
|
for (i = 0; i < demux->source_package->len; i++)
|
|
mxf_metadata_generic_package_reset (&g_array_index (demux->source_package,
|
|
MXFMetadataGenericPackage, i));
|
|
g_array_free (demux->source_package, TRUE);
|
|
demux->source_package = NULL;
|
|
}
|
|
|
|
if (demux->package) {
|
|
g_ptr_array_free (demux->package, TRUE);
|
|
demux->package = NULL;
|
|
}
|
|
|
|
if (demux->track) {
|
|
for (i = 0; i < demux->track->len; i++)
|
|
mxf_metadata_track_reset (&g_array_index (demux->track,
|
|
MXFMetadataTrack, i));
|
|
g_array_free (demux->track, TRUE);
|
|
demux->track = NULL;
|
|
}
|
|
|
|
if (demux->sequence) {
|
|
for (i = 0; i < demux->sequence->len; i++)
|
|
mxf_metadata_sequence_reset (&g_array_index (demux->sequence,
|
|
MXFMetadataSequence, i));
|
|
g_array_free (demux->sequence, TRUE);
|
|
demux->sequence = NULL;
|
|
}
|
|
|
|
if (demux->structural_component) {
|
|
for (i = 0; i < demux->structural_component->len; i++)
|
|
mxf_metadata_structural_component_reset (&g_array_index
|
|
(demux->structural_component, MXFMetadataStructuralComponent, i));
|
|
g_array_free (demux->structural_component, TRUE);
|
|
demux->structural_component = NULL;
|
|
}
|
|
|
|
if (demux->generic_descriptor) {
|
|
for (i = 0; i < demux->generic_descriptor->len; i++)
|
|
mxf_metadata_generic_descriptor_reset (&g_array_index
|
|
(demux->generic_descriptor, MXFMetadataGenericDescriptor, i));
|
|
g_array_free (demux->generic_descriptor, TRUE);
|
|
demux->generic_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->file_descriptor) {
|
|
for (i = 0; i < demux->file_descriptor->len; i++)
|
|
mxf_metadata_file_descriptor_reset (&g_array_index
|
|
(demux->file_descriptor, MXFMetadataFileDescriptor, i));
|
|
g_array_free (demux->file_descriptor, TRUE);
|
|
demux->file_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->multiple_descriptor) {
|
|
for (i = 0; i < demux->multiple_descriptor->len; i++)
|
|
mxf_metadata_multiple_descriptor_reset (&g_array_index
|
|
(demux->multiple_descriptor, MXFMetadataMultipleDescriptor, i));
|
|
g_array_free (demux->multiple_descriptor, TRUE);
|
|
demux->multiple_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->generic_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->generic_picture_essence_descriptor->len; i++)
|
|
mxf_metadata_generic_picture_essence_descriptor_reset (&g_array_index
|
|
(demux->generic_picture_essence_descriptor,
|
|
MXFMetadataGenericPictureEssenceDescriptor, i));
|
|
g_array_free (demux->generic_picture_essence_descriptor, TRUE);
|
|
demux->generic_picture_essence_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->cdci_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->cdci_picture_essence_descriptor->len; i++)
|
|
mxf_metadata_cdci_picture_essence_descriptor_reset (&g_array_index
|
|
(demux->cdci_picture_essence_descriptor,
|
|
MXFMetadataCDCIPictureEssenceDescriptor, i));
|
|
g_array_free (demux->cdci_picture_essence_descriptor, TRUE);
|
|
demux->cdci_picture_essence_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->rgba_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->rgba_picture_essence_descriptor->len; i++)
|
|
mxf_metadata_rgba_picture_essence_descriptor_reset (&g_array_index
|
|
(demux->rgba_picture_essence_descriptor,
|
|
MXFMetadataRGBAPictureEssenceDescriptor, i));
|
|
g_array_free (demux->rgba_picture_essence_descriptor, TRUE);
|
|
demux->rgba_picture_essence_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->mpeg_video_descriptor) {
|
|
for (i = 0; i < demux->mpeg_video_descriptor->len; i++)
|
|
mxf_metadata_mpeg_video_descriptor_reset (&g_array_index
|
|
(demux->mpeg_video_descriptor, MXFMetadataMPEGVideoDescriptor, i));
|
|
g_array_free (demux->mpeg_video_descriptor, TRUE);
|
|
demux->mpeg_video_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->generic_sound_essence_descriptor) {
|
|
for (i = 0; i < demux->generic_sound_essence_descriptor->len; i++)
|
|
mxf_metadata_generic_sound_essence_descriptor_reset (&g_array_index
|
|
(demux->generic_sound_essence_descriptor,
|
|
MXFMetadataGenericSoundEssenceDescriptor, i));
|
|
g_array_free (demux->generic_sound_essence_descriptor, TRUE);
|
|
demux->generic_sound_essence_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->wave_audio_essence_descriptor) {
|
|
for (i = 0; i < demux->wave_audio_essence_descriptor->len; i++)
|
|
mxf_metadata_wave_audio_essence_descriptor_reset (&g_array_index
|
|
(demux->wave_audio_essence_descriptor,
|
|
MXFMetadataWaveAudioEssenceDescriptor, i));
|
|
g_array_free (demux->wave_audio_essence_descriptor, TRUE);
|
|
demux->wave_audio_essence_descriptor = NULL;
|
|
}
|
|
|
|
if (demux->descriptor) {
|
|
g_ptr_array_free (demux->descriptor, TRUE);
|
|
demux->descriptor = NULL;
|
|
}
|
|
|
|
if (demux->locator) {
|
|
for (i = 0; i < demux->locator->len; i++)
|
|
mxf_metadata_locator_reset (&g_array_index (demux->locator,
|
|
MXFMetadataLocator, i));
|
|
g_array_free (demux->locator, TRUE);
|
|
demux->locator = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_reset (GstMXFDemux * demux)
|
|
{
|
|
GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
|
|
|
|
demux->flushing = FALSE;
|
|
|
|
demux->header_partition_pack_offset = 0;
|
|
demux->footer_partition_pack_offset = 0;
|
|
demux->offset = 0;
|
|
|
|
demux->pull_footer_metadata = TRUE;
|
|
|
|
demux->run_in = -1;
|
|
|
|
memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
|
|
|
|
if (demux->new_seg_event) {
|
|
gst_event_unref (demux->new_seg_event);
|
|
demux->new_seg_event = NULL;
|
|
}
|
|
|
|
if (demux->close_seg_event) {
|
|
gst_event_unref (demux->close_seg_event);
|
|
demux->close_seg_event = NULL;
|
|
}
|
|
|
|
gst_adapter_clear (demux->adapter);
|
|
|
|
if (demux->src) {
|
|
g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
|
|
g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
|
|
g_ptr_array_free (demux->src, TRUE);
|
|
demux->src = NULL;
|
|
}
|
|
|
|
if (demux->partition_index) {
|
|
g_array_free (demux->partition_index, TRUE);
|
|
demux->partition_index = NULL;
|
|
}
|
|
|
|
gst_mxf_demux_reset_mxf_state (demux);
|
|
gst_mxf_demux_reset_metadata (demux);
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_combine_flows (GstMXFDemux * demux,
|
|
GstMXFPad * pad, GstFlowReturn ret)
|
|
{
|
|
guint i;
|
|
|
|
/* store the value */
|
|
pad->last_flow = ret;
|
|
|
|
/* any other error that is not-linked can be returned right away */
|
|
if (ret != GST_FLOW_NOT_LINKED)
|
|
goto done;
|
|
|
|
/* only return NOT_LINKED if all other pads returned NOT_LINKED */
|
|
g_assert (demux->src->len != 0);
|
|
for (i = 0; i < demux->src->len; i++) {
|
|
GstMXFPad *opad = g_ptr_array_index (demux->src, i);
|
|
|
|
if (opad == NULL)
|
|
continue;
|
|
|
|
ret = opad->last_flow;
|
|
/* some other return value (must be SUCCESS but we can return
|
|
* other values as well) */
|
|
if (ret != GST_FLOW_NOT_LINKED)
|
|
goto done;
|
|
}
|
|
/* if we get here, all other pads were unlinked and we return
|
|
* NOT_LINKED then */
|
|
done:
|
|
GST_LOG_OBJECT (demux, "combined return %s", gst_flow_get_name (ret));
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
|
|
guint size, GstBuffer ** buffer)
|
|
{
|
|
GstFlowReturn ret;
|
|
|
|
ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"failed when pulling %u bytes from offset %" G_GUINT64_FORMAT ": %s",
|
|
size, offset, gst_flow_get_name (ret));
|
|
*buffer = NULL;
|
|
return ret;
|
|
}
|
|
|
|
if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"partial pull got %u when expecting %u from offset %" G_GUINT64_FORMAT,
|
|
GST_BUFFER_SIZE (*buffer), size, offset);
|
|
gst_buffer_unref (*buffer);
|
|
ret = GST_FLOW_UNEXPECTED;
|
|
*buffer = NULL;
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
|
|
{
|
|
gboolean ret = TRUE;
|
|
guint i;
|
|
|
|
GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
|
|
GST_EVENT_TYPE_NAME (event));
|
|
|
|
if (!demux->src)
|
|
return ret;
|
|
|
|
for (i = 0; i < demux->src->len; i++) {
|
|
GstPad *pad = GST_PAD (g_ptr_array_index (demux->src, i));
|
|
|
|
ret |= gst_pad_push_event (pad, gst_event_ref (event));
|
|
}
|
|
|
|
gst_event_unref (event);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, const MXFUL * key,
|
|
GstBuffer * buffer)
|
|
{
|
|
if (demux->partition.valid) {
|
|
mxf_partition_pack_reset (&demux->partition);
|
|
mxf_primer_pack_reset (&demux->primer);
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling partition pack of size %u at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_partition_pack_parse (key, &demux->partition,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (demux->partition.type == MXF_PARTITION_PACK_HEADER)
|
|
demux->footer_partition_pack_offset = demux->partition.footer_partition;
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, const MXFUL * key,
|
|
GstBuffer * buffer)
|
|
{
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling primer pack of size %u at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (G_UNLIKELY (!demux->partition.valid)) {
|
|
GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (G_UNLIKELY (demux->primer.valid)) {
|
|
GST_ERROR_OBJECT (demux, "Primer pack already exists");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!mxf_primer_pack_parse (key, &demux->primer,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_preface (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataPreface preface;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata preface of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (demux->final_metadata) {
|
|
GST_DEBUG_OBJECT (demux, "Metadata is already final, skipping");
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
if (!mxf_metadata_preface_parse (key, &preface, &demux->primer,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata preface failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (mxf_timestamp_is_unknown (&demux->preface.last_modified_date)
|
|
|| (!mxf_timestamp_is_unknown (&preface.last_modified_date)
|
|
&& mxf_timestamp_compare (&demux->preface.last_modified_date,
|
|
&preface.last_modified_date) < 0)) {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Timestamp of new preface is newer than old, updating metadata");
|
|
gst_mxf_demux_reset_metadata (demux);
|
|
memcpy (&demux->preface, &preface, sizeof (MXFMetadataPreface));
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_identification (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataIdentification identification;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata identification of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_identification_parse (key, &identification,
|
|
&demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata identification failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->identification)
|
|
demux->identification =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataIdentification));
|
|
|
|
g_array_append_val (demux->identification, identification);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_content_storage (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata content storage of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_content_storage_parse (key,
|
|
&demux->content_storage, &demux->primer, GST_BUFFER_DATA (buffer),
|
|
GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata content storage failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_essence_container_data (GstMXFDemux *
|
|
demux, const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataEssenceContainerData essence_container_data;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata essence container data of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_essence_container_data_parse (key,
|
|
&essence_container_data, &demux->primer, GST_BUFFER_DATA (buffer),
|
|
GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata essence container data failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->essence_container_data)
|
|
demux->essence_container_data =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataEssenceContainerData));
|
|
|
|
g_array_append_val (demux->essence_container_data, essence_container_data);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_material_package (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataGenericPackage material_package;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata material package of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_generic_package_parse (key, &material_package,
|
|
&demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata material package failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->material_package)
|
|
demux->material_package =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataMaterialPackage));
|
|
|
|
g_array_append_val (demux->material_package, material_package);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_source_package (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataGenericPackage source_package;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata source package of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_generic_package_parse (key, &source_package,
|
|
&demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata source package failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->source_package)
|
|
demux->source_package =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataSourcePackage));
|
|
|
|
g_array_append_val (demux->source_package, source_package);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_track (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataTrack track;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata track of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_track_parse (key, &track, &demux->primer,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata track timecode failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->track)
|
|
demux->track = g_array_new (FALSE, FALSE, sizeof (MXFMetadataTrack));
|
|
|
|
g_array_append_val (demux->track, track);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_sequence (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataSequence sequence;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata sequence of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_sequence_parse (key, &sequence,
|
|
&demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata sequence failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->sequence)
|
|
demux->sequence = g_array_new (FALSE, FALSE, sizeof (MXFMetadataSequence));
|
|
|
|
g_array_append_val (demux->sequence, sequence);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_structural_component (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataStructuralComponent component;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata structural component of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (!mxf_metadata_structural_component_parse (key, &component,
|
|
&demux->primer, type, GST_BUFFER_DATA (buffer),
|
|
GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata structural component failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->structural_component)
|
|
demux->structural_component =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataStructuralComponent));
|
|
|
|
g_array_append_val (demux->structural_component, component);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_generic_descriptor (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataGenericDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata generic descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_generic_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset) mxf_metadata_generic_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata generic descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->generic_descriptor)
|
|
demux->generic_descriptor =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataGenericDescriptor));
|
|
|
|
g_array_append_val (demux->generic_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_file_descriptor (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataFileDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata file descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_file_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset) mxf_metadata_file_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata file descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->file_descriptor)
|
|
demux->file_descriptor =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataFileDescriptor));
|
|
|
|
g_array_append_val (demux->file_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_multiple_descriptor (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataMultipleDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata multiple descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_multiple_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset) mxf_metadata_multiple_descriptor_reset))
|
|
{
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata multiple descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->multiple_descriptor)
|
|
demux->multiple_descriptor =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataMultipleDescriptor));
|
|
|
|
g_array_append_val (demux->multiple_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_generic_picture_essence_descriptor (GstMXFDemux *
|
|
demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataGenericPictureEssenceDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata generic picture essence descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_generic_picture_essence_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_generic_picture_essence_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Parsing metadata generic picture essence descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->generic_picture_essence_descriptor)
|
|
demux->generic_picture_essence_descriptor =
|
|
g_array_new (FALSE, FALSE,
|
|
sizeof (MXFMetadataGenericPictureEssenceDescriptor));
|
|
|
|
g_array_append_val (demux->generic_picture_essence_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_cdci_picture_essence_descriptor (GstMXFDemux *
|
|
demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataCDCIPictureEssenceDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata CDCI picture essence descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_cdci_picture_essence_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_cdci_picture_essence_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Parsing metadata CDCI picture essence descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->cdci_picture_essence_descriptor)
|
|
demux->cdci_picture_essence_descriptor =
|
|
g_array_new (FALSE, FALSE,
|
|
sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
|
|
|
|
g_array_append_val (demux->cdci_picture_essence_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_rgba_picture_essence_descriptor (GstMXFDemux *
|
|
demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataRGBAPictureEssenceDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata RGBA picture essence descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_rgba_picture_essence_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_rgba_picture_essence_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Parsing metadata RGBA picture essence descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->rgba_picture_essence_descriptor)
|
|
demux->rgba_picture_essence_descriptor =
|
|
g_array_new (FALSE, FALSE,
|
|
sizeof (MXFMetadataRGBAPictureEssenceDescriptor));
|
|
|
|
g_array_append_val (demux->rgba_picture_essence_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_mpeg_video_descriptor (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataMPEGVideoDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata MPEG video descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_mpeg_video_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_mpeg_video_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata MPEG video descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->mpeg_video_descriptor)
|
|
demux->mpeg_video_descriptor =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFMetadataMPEGVideoDescriptor));
|
|
|
|
g_array_append_val (demux->mpeg_video_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_generic_sound_essence_descriptor (GstMXFDemux *
|
|
demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataGenericSoundEssenceDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata generic sound essence descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_generic_sound_essence_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_generic_sound_essence_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Parsing metadata generic sound essence descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->generic_sound_essence_descriptor)
|
|
demux->generic_sound_essence_descriptor =
|
|
g_array_new (FALSE, FALSE,
|
|
sizeof (MXFMetadataGenericSoundEssenceDescriptor));
|
|
|
|
g_array_append_val (demux->generic_sound_essence_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_wave_audio_essence_descriptor (GstMXFDemux *
|
|
demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataWaveAudioEssenceDescriptor descriptor;
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata wave sound essence descriptor of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_descriptor_parse (key,
|
|
(MXFMetadataGenericDescriptor *) & descriptor, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer),
|
|
(MXFMetadataDescriptorHandleTag)
|
|
mxf_metadata_wave_audio_essence_descriptor_handle_tag,
|
|
(MXFMetadataDescriptorReset)
|
|
mxf_metadata_wave_audio_essence_descriptor_reset)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Parsing metadata wave sound essence descriptor failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->wave_audio_essence_descriptor)
|
|
demux->wave_audio_essence_descriptor =
|
|
g_array_new (FALSE, FALSE,
|
|
sizeof (MXFMetadataWaveAudioEssenceDescriptor));
|
|
|
|
g_array_append_val (demux->wave_audio_essence_descriptor, descriptor);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata_locator (GstMXFDemux * demux,
|
|
const MXFUL * key, guint16 type, GstBuffer * buffer)
|
|
{
|
|
MXFMetadataLocator locator;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata locator of size %u"
|
|
" at offset %" G_GUINT64_FORMAT " with type 0x%04d",
|
|
GST_BUFFER_SIZE (buffer), demux->offset, type);
|
|
|
|
if (!mxf_metadata_locator_parse (key, &locator, &demux->primer,
|
|
type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
GST_ERROR_OBJECT (demux, "Parsing metadata locator failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->locator)
|
|
demux->locator = g_array_new (FALSE, FALSE, sizeof (MXFMetadataLocator));
|
|
|
|
g_array_append_val (demux->locator, locator);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_header_metadata_resolve_references (GstMXFDemux * demux)
|
|
{
|
|
guint i, j, k;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
GST_DEBUG_OBJECT (demux, "Resolve metadata references");
|
|
demux->update_metadata = FALSE;
|
|
if (demux->partition.closed && demux->partition.complete)
|
|
demux->final_metadata = TRUE;
|
|
|
|
/* Fill in demux->descriptor */
|
|
demux->descriptor = g_ptr_array_new ();
|
|
if (demux->generic_descriptor) {
|
|
for (i = 0; i < demux->generic_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->generic_descriptor,
|
|
MXFMetadataGenericDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->file_descriptor) {
|
|
for (i = 0; i < demux->file_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->file_descriptor, MXFMetadataFileDescriptor,
|
|
i));
|
|
}
|
|
}
|
|
if (demux->generic_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->generic_picture_essence_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->generic_picture_essence_descriptor,
|
|
MXFMetadataGenericPictureEssenceDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->cdci_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->cdci_picture_essence_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->cdci_picture_essence_descriptor,
|
|
MXFMetadataCDCIPictureEssenceDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->rgba_picture_essence_descriptor) {
|
|
for (i = 0; i < demux->rgba_picture_essence_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->rgba_picture_essence_descriptor,
|
|
MXFMetadataRGBAPictureEssenceDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->mpeg_video_descriptor) {
|
|
for (i = 0; i < demux->mpeg_video_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->mpeg_video_descriptor,
|
|
MXFMetadataMPEGVideoDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->generic_sound_essence_descriptor) {
|
|
for (i = 0; i < demux->generic_sound_essence_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->generic_sound_essence_descriptor,
|
|
MXFMetadataGenericSoundEssenceDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->wave_audio_essence_descriptor) {
|
|
for (i = 0; i < demux->wave_audio_essence_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->wave_audio_essence_descriptor,
|
|
MXFMetadataWaveAudioEssenceDescriptor, i));
|
|
}
|
|
}
|
|
if (demux->multiple_descriptor) {
|
|
for (i = 0; i < demux->multiple_descriptor->len; i++) {
|
|
g_ptr_array_add (demux->descriptor,
|
|
&g_array_index (demux->multiple_descriptor,
|
|
MXFMetadataMultipleDescriptor, i));
|
|
}
|
|
}
|
|
|
|
/* Fill in demux->package */
|
|
demux->package = g_ptr_array_new ();
|
|
if (demux->material_package) {
|
|
for (i = 0; i < demux->material_package->len; i++) {
|
|
g_ptr_array_add (demux->package, &g_array_index (demux->material_package,
|
|
MXFMetadataGenericPackage, i));
|
|
}
|
|
}
|
|
if (demux->source_package) {
|
|
for (i = 0; i < demux->source_package->len; i++) {
|
|
g_ptr_array_add (demux->package, &g_array_index (demux->source_package,
|
|
MXFMetadataGenericPackage, i));
|
|
}
|
|
}
|
|
|
|
/* Multiple descriptor */
|
|
if (demux->multiple_descriptor && demux->descriptor) {
|
|
for (i = 0; i < demux->multiple_descriptor->len; i++) {
|
|
MXFMetadataMultipleDescriptor *d =
|
|
&g_array_index (demux->multiple_descriptor,
|
|
MXFMetadataMultipleDescriptor, i);
|
|
|
|
d->sub_descriptors =
|
|
g_new0 (MXFMetadataGenericDescriptor *, d->n_sub_descriptors);
|
|
for (j = 0; j < d->n_sub_descriptors; j++) {
|
|
for (k = 0; k < demux->descriptor->len; k++) {
|
|
MXFMetadataGenericDescriptor *e =
|
|
g_ptr_array_index (demux->descriptor, k);
|
|
|
|
if (mxf_ul_is_equal (&d->sub_descriptors_uids[j], &e->instance_uid)) {
|
|
d->sub_descriptors[j] = e;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* See SMPTE 377M 8.4 */
|
|
|
|
/* Preface */
|
|
if (demux->package) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
g_ptr_array_index (demux->package, i);
|
|
|
|
if (mxf_ul_is_equal (&demux->preface.primary_package_uid,
|
|
&package->instance_uid)) {
|
|
demux->preface.primary_package = package;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
demux->preface.identifications =
|
|
g_new0 (MXFMetadataIdentification *, demux->preface.n_identifications);
|
|
if (demux->identification) {
|
|
for (i = 0; i < demux->identification->len; i++) {
|
|
MXFMetadataIdentification *identification =
|
|
&g_array_index (demux->identification,
|
|
MXFMetadataIdentification, i);
|
|
|
|
for (j = 0; j < demux->preface.n_identifications; j++) {
|
|
if (mxf_ul_is_equal (&demux->preface.identifications_uids[j],
|
|
&identification->instance_uid)) {
|
|
demux->preface.identifications[j] = identification;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!mxf_ul_is_equal (&demux->preface.content_storage_uid,
|
|
&demux->content_storage.instance_uid)) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Preface content storage UID not equal to actual content storage instance uid");
|
|
ret = GST_FLOW_ERROR;
|
|
goto error;
|
|
}
|
|
demux->preface.content_storage = &demux->content_storage;
|
|
|
|
/* TODO: dm_schemes */
|
|
|
|
/* Content storage */
|
|
demux->content_storage.packages =
|
|
g_new0 (MXFMetadataGenericPackage *, demux->content_storage.n_packages);
|
|
if (demux->package) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
g_ptr_array_index (demux->package, i);
|
|
|
|
for (j = 0; j < demux->content_storage.n_packages; j++) {
|
|
if (mxf_ul_is_equal (&demux->content_storage.packages_uids[j],
|
|
&package->instance_uid)) {
|
|
demux->content_storage.packages[j] = package;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
demux->content_storage.essence_container_data =
|
|
g_new0 (MXFMetadataEssenceContainerData *,
|
|
demux->content_storage.n_essence_container_data);
|
|
if (demux->essence_container_data) {
|
|
for (i = 0; i < demux->essence_container_data->len; i++) {
|
|
MXFMetadataEssenceContainerData *data =
|
|
&g_array_index (demux->essence_container_data,
|
|
MXFMetadataEssenceContainerData, i);
|
|
|
|
for (j = 0; j < demux->content_storage.n_essence_container_data; j++) {
|
|
if (mxf_ul_is_equal (&demux->
|
|
content_storage.essence_container_data_uids[j],
|
|
&data->instance_uid)) {
|
|
demux->content_storage.essence_container_data[j] = data;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Essence container data */
|
|
if (demux->package && demux->essence_container_data) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
g_ptr_array_index (demux->package, i);
|
|
|
|
for (j = 0; j < demux->essence_container_data->len; j++) {
|
|
MXFMetadataEssenceContainerData *data =
|
|
&g_array_index (demux->essence_container_data,
|
|
MXFMetadataEssenceContainerData, j);
|
|
|
|
if (mxf_umid_is_equal (&data->linked_package_uid,
|
|
&package->package_uid)) {
|
|
data->linked_package = package;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Generic package */
|
|
if (demux->package) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
g_ptr_array_index (demux->package, i);
|
|
|
|
package->tracks = g_new0 (MXFMetadataTrack *, package->n_tracks);
|
|
if (demux->track) {
|
|
for (j = 0; j < package->n_tracks; j++) {
|
|
for (k = 0; k < demux->track->len; k++) {
|
|
MXFMetadataTrack *track =
|
|
&g_array_index (demux->track, MXFMetadataTrack, k);
|
|
|
|
if (mxf_ul_is_equal (&package->tracks_uids[j],
|
|
&track->instance_uid)) {
|
|
package->tracks[j] = track;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Resolve descriptors */
|
|
if (package->n_descriptors > 0 && demux->descriptor) {
|
|
MXFMetadataGenericDescriptor *d = NULL;
|
|
|
|
for (j = 0; j < demux->descriptor->len; j++) {
|
|
MXFMetadataGenericDescriptor *descriptor =
|
|
g_ptr_array_index (demux->descriptor, j);
|
|
|
|
if (mxf_ul_is_equal (&package->descriptors_uid,
|
|
&descriptor->instance_uid)) {
|
|
d = descriptor;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (d && d->type == MXF_METADATA_MULTIPLE_DESCRIPTOR) {
|
|
MXFMetadataMultipleDescriptor *e =
|
|
(MXFMetadataMultipleDescriptor *) d;
|
|
|
|
package->n_descriptors = e->n_sub_descriptors;
|
|
package->descriptors =
|
|
g_new0 (MXFMetadataGenericDescriptor *, e->n_sub_descriptors);
|
|
|
|
/* These are already resolved */
|
|
for (j = 0; j < e->n_sub_descriptors; j++)
|
|
package->descriptors[j] = e->sub_descriptors[j];
|
|
} else {
|
|
package->n_descriptors = 1;
|
|
package->descriptors = g_new0 (MXFMetadataGenericDescriptor *, 1);
|
|
package->descriptors[0] = d;
|
|
}
|
|
}
|
|
|
|
if (package->tracks && package->descriptors) {
|
|
for (j = 0; j < package->n_tracks; j++) {
|
|
MXFMetadataTrack *track = package->tracks[j];
|
|
guint n_descriptor = 0;
|
|
|
|
if (!track)
|
|
continue;
|
|
|
|
for (k = 0; k < package->n_descriptors; k++) {
|
|
MXFMetadataGenericDescriptor *d = package->descriptors[k];
|
|
MXFMetadataFileDescriptor *e;
|
|
|
|
if (!d || !d->is_file_descriptor)
|
|
continue;
|
|
|
|
e = (MXFMetadataFileDescriptor *) d;
|
|
|
|
if (e->linked_track_id == track->track_id)
|
|
n_descriptor++;
|
|
}
|
|
|
|
track->n_descriptor = n_descriptor;
|
|
track->descriptor =
|
|
g_new0 (MXFMetadataFileDescriptor *, n_descriptor);
|
|
n_descriptor = 0;
|
|
|
|
for (k = 0; k < package->n_descriptors; k++) {
|
|
MXFMetadataGenericDescriptor *d = package->descriptors[k];
|
|
MXFMetadataFileDescriptor *e;
|
|
|
|
if (!d || !d->is_file_descriptor)
|
|
continue;
|
|
|
|
e = (MXFMetadataFileDescriptor *) d;
|
|
|
|
if (e->linked_track_id == track->track_id)
|
|
track->descriptor[n_descriptor++] = e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Tracks */
|
|
if (demux->track && demux->sequence) {
|
|
for (i = 0; i < demux->track->len; i++) {
|
|
MXFMetadataTrack *track =
|
|
&g_array_index (demux->track, MXFMetadataTrack, i);
|
|
|
|
for (j = 0; j < demux->sequence->len; j++) {
|
|
MXFMetadataSequence *sequence =
|
|
&g_array_index (demux->sequence, MXFMetadataSequence,
|
|
i);
|
|
|
|
if (mxf_ul_is_equal (&track->sequence_uid, &sequence->instance_uid)) {
|
|
track->sequence = sequence;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Sequences */
|
|
if (demux->sequence) {
|
|
for (i = 0; i < demux->sequence->len; i++) {
|
|
MXFMetadataSequence *sequence =
|
|
&g_array_index (demux->sequence, MXFMetadataSequence, i);
|
|
|
|
sequence->structural_components =
|
|
g_new0 (MXFMetadataStructuralComponent *,
|
|
sequence->n_structural_components);
|
|
|
|
if (demux->structural_component) {
|
|
for (j = 0; j < sequence->n_structural_components; j++) {
|
|
for (k = 0; k < demux->structural_component->len; k++) {
|
|
MXFMetadataStructuralComponent *component =
|
|
&g_array_index (demux->structural_component,
|
|
MXFMetadataStructuralComponent, k);
|
|
|
|
if (mxf_ul_is_equal (&sequence->structural_components_uids[j],
|
|
&component->instance_uid)) {
|
|
sequence->structural_components[j] = component;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Source clips */
|
|
if (demux->structural_component && demux->source_package) {
|
|
for (i = 0; i < demux->structural_component->len; i++) {
|
|
MXFMetadataStructuralComponent *component =
|
|
&g_array_index (demux->structural_component,
|
|
MXFMetadataStructuralComponent, i);
|
|
|
|
if (component->type != MXF_METADATA_SOURCE_CLIP)
|
|
continue;
|
|
|
|
for (j = 0; j < demux->source_package->len; j++) {
|
|
MXFMetadataGenericPackage *package =
|
|
&g_array_index (demux->source_package, MXFMetadataGenericPackage,
|
|
j);
|
|
|
|
if (mxf_umid_is_equal (&component->source_clip.source_package_id,
|
|
&package->package_uid)) {
|
|
component->source_clip.source_package = package;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Generic descriptors */
|
|
if (demux->descriptor) {
|
|
for (i = 0; i < demux->descriptor->len; i++) {
|
|
MXFMetadataGenericDescriptor *descriptor =
|
|
g_ptr_array_index (demux->descriptor, i);
|
|
|
|
descriptor->locators =
|
|
g_new0 (MXFMetadataLocator *, descriptor->n_locators);
|
|
|
|
if (demux->locator) {
|
|
for (j = 0; j < descriptor->n_locators; j++) {
|
|
for (k = 0; k < demux->locator->len; k++) {
|
|
MXFMetadataLocator *locator =
|
|
&g_array_index (demux->locator, MXFMetadataLocator,
|
|
k);
|
|
|
|
if (mxf_ul_is_equal (&descriptor->locators_uids[j],
|
|
&locator->instance_uid)) {
|
|
descriptor->locators[j] = locator;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Mark packages as material, top-level source and source */
|
|
if (demux->material_package) {
|
|
for (i = 0; i < demux->material_package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
&g_array_index (demux->material_package, MXFMetadataGenericPackage,
|
|
i);
|
|
|
|
package->type = MXF_METADATA_GENERIC_PACKAGE_MATERIAL;
|
|
|
|
for (j = 0; j < package->n_tracks; j++) {
|
|
MXFMetadataTrack *track = package->tracks[j];
|
|
MXFMetadataSequence *sequence;
|
|
|
|
if (!track || !track->sequence)
|
|
continue;
|
|
|
|
sequence = track->sequence;
|
|
|
|
for (k = 0; k < sequence->n_structural_components; k++) {
|
|
MXFMetadataStructuralComponent *component =
|
|
sequence->structural_components[k];
|
|
|
|
if (!component || component->type != MXF_METADATA_SOURCE_CLIP
|
|
|| !component->source_clip.source_package)
|
|
continue;
|
|
|
|
component->source_clip.source_package->type =
|
|
MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Store, for every package, the number of timestamp, metadata, essence and other tracks */
|
|
if (demux->package) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *package =
|
|
g_ptr_array_index (demux->package, i);
|
|
|
|
if (!package->tracks || package->n_tracks == 0)
|
|
continue;
|
|
|
|
for (j = 0; j < package->n_tracks; j++) {
|
|
MXFMetadataTrack *track = package->tracks[j];
|
|
MXFMetadataSequence *sequence;
|
|
MXFMetadataTrackType type = MXF_METADATA_TRACK_UNKNOWN;
|
|
|
|
if (!track || !track->sequence)
|
|
continue;
|
|
|
|
sequence = track->sequence;
|
|
|
|
if (mxf_ul_is_zero (&sequence->data_definition)
|
|
&& sequence->structural_components) {
|
|
for (k = 0; k < sequence->n_structural_components; k++) {
|
|
MXFMetadataStructuralComponent *component =
|
|
sequence->structural_components[k];
|
|
if (!component || mxf_ul_is_zero (&component->data_definition))
|
|
continue;
|
|
|
|
type =
|
|
mxf_metadata_track_identifier_parse
|
|
(&component->data_definition);
|
|
break;
|
|
}
|
|
} else {
|
|
type =
|
|
mxf_metadata_track_identifier_parse (&sequence->data_definition);
|
|
}
|
|
|
|
if (type == MXF_METADATA_TRACK_UNKNOWN)
|
|
continue;
|
|
else if ((type & 0xf0) == 0x10)
|
|
package->n_timecode_tracks++;
|
|
else if ((type & 0xf0) == 0x20)
|
|
package->n_metadata_tracks++;
|
|
else if ((type & 0xf0) == 0x30)
|
|
package->n_essence_tracks++;
|
|
else if ((type & 0xf0) == 0x40)
|
|
package->n_other_tracks++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
|
|
error:
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_header_metadata_update_streams (GstMXFDemux * demux)
|
|
{
|
|
MXFMetadataGenericPackage *current_package = NULL;
|
|
guint i, j, k;
|
|
gboolean first_run;
|
|
|
|
GST_DEBUG_OBJECT (demux, "Updating streams");
|
|
|
|
choose_package:
|
|
/* If no package was selected, select the first material package */
|
|
if (mxf_umid_is_zero (&demux->current_package_uid)
|
|
&& !demux->material_package) {
|
|
GST_ERROR_OBJECT (demux, "No material package");
|
|
return GST_FLOW_ERROR;
|
|
} else if (mxf_umid_is_zero (&demux->current_package_uid)) {
|
|
MXFMetadataGenericPackage *p =
|
|
(MXFMetadataGenericPackage *) demux->material_package->data;
|
|
memcpy (&demux->current_package_uid, &p->package_uid, 32);
|
|
current_package = p;
|
|
if (demux->src) {
|
|
for (i = 0; i < demux->src->len; i++) {
|
|
GstMXFPad *pad = g_ptr_array_index (demux->src, i);
|
|
gst_element_remove_pad (GST_ELEMENT_CAST (demux), GST_PAD_CAST (pad));
|
|
gst_object_unref (pad);
|
|
}
|
|
g_ptr_array_free (demux->src, TRUE);
|
|
demux->src = NULL;
|
|
}
|
|
}
|
|
|
|
if (!current_package && demux->package) {
|
|
for (i = 0; i < demux->package->len; i++) {
|
|
MXFMetadataGenericPackage *p = g_ptr_array_index (demux->package, i);
|
|
|
|
if (mxf_umid_is_equal (&p->package_uid, &demux->current_package_uid)) {
|
|
current_package = p;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!current_package) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"Selected package not found in header metadata, choosing the first best");
|
|
memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
|
|
goto choose_package;
|
|
}
|
|
|
|
if (current_package->type == MXF_METADATA_GENERIC_PACKAGE_SOURCE) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"Selected package is not a material package or top-level source package, choosing the first best");
|
|
memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
|
|
goto choose_package;
|
|
}
|
|
|
|
if (!current_package->tracks) {
|
|
GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
|
|
return GST_FLOW_ERROR;
|
|
} else if (!current_package->n_essence_tracks) {
|
|
GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
first_run = (demux->src == NULL);
|
|
demux->current_package = current_package;
|
|
|
|
for (i = 0; i < current_package->n_tracks; i++) {
|
|
MXFMetadataTrack *track = current_package->tracks[i];
|
|
MXFMetadataTrackType track_type = MXF_METADATA_TRACK_UNKNOWN;
|
|
MXFMetadataSequence *sequence;
|
|
MXFMetadataStructuralComponent *component = NULL;
|
|
MXFMetadataGenericPackage *source_package = NULL;
|
|
MXFMetadataTrack *source_track = NULL;
|
|
GstMXFPad *pad = NULL;
|
|
GstCaps *caps = NULL;
|
|
|
|
GST_DEBUG_OBJECT (demux, "Handling track %u", i);
|
|
|
|
if (!track) {
|
|
GST_WARNING_OBJECT (demux, "Unresolved track");
|
|
continue;
|
|
} else if (!track->sequence) {
|
|
GST_WARNING_OBJECT (demux, "Track with no sequence");
|
|
continue;
|
|
}
|
|
|
|
sequence = track->sequence;
|
|
|
|
if (current_package->type == MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE) {
|
|
source_package = current_package;
|
|
source_track = track;
|
|
}
|
|
|
|
track_type =
|
|
mxf_metadata_track_identifier_parse (&sequence->data_definition);
|
|
|
|
/* TODO: handle multiple components, see SMPTE 377M page 37 */
|
|
if (sequence->structural_components && sequence->structural_components[0]) {
|
|
component = sequence->structural_components[0];
|
|
|
|
if (track_type == MXF_METADATA_TRACK_UNKNOWN)
|
|
track_type =
|
|
mxf_metadata_track_identifier_parse (&component->data_definition);
|
|
|
|
if (!source_package && component->type == MXF_METADATA_SOURCE_CLIP
|
|
&& component->source_clip.source_package
|
|
&& component->source_clip.source_package->type ==
|
|
MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE
|
|
&& component->source_clip.source_package->tracks) {
|
|
source_package = component->source_clip.source_package;
|
|
|
|
for (k = 0; k < source_package->n_tracks; k++) {
|
|
MXFMetadataTrack *tmp = source_package->tracks[k];
|
|
|
|
if (tmp->track_id == component->source_clip.source_track_id) {
|
|
source_track = tmp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (track_type && (track_type & 0xf0) != 0x30) {
|
|
GST_DEBUG_OBJECT (demux, "No essence track");
|
|
continue;
|
|
}
|
|
|
|
if (!source_package || track_type == MXF_METADATA_TRACK_UNKNOWN
|
|
|| !source_track || !component) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"No source package or track type for track found");
|
|
continue;
|
|
}
|
|
|
|
if (!source_package->descriptors) {
|
|
GST_WARNING_OBJECT (demux, "Source package has no descriptors");
|
|
continue;
|
|
}
|
|
|
|
if (!source_track->descriptor) {
|
|
GST_WARNING_OBJECT (demux, "No descriptor found for track");
|
|
continue;
|
|
}
|
|
|
|
if (demux->src && demux->src->len > 0) {
|
|
/* Find pad from track_id */
|
|
for (j = 0; j < demux->src->len; j++) {
|
|
GstMXFPad *tmp = g_ptr_array_index (demux->src, j);
|
|
|
|
if (tmp->track_id == track->track_id) {
|
|
pad = tmp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pad && first_run) {
|
|
GstPadTemplate *templ;
|
|
gchar *pad_name;
|
|
|
|
switch (track_type) {
|
|
case MXF_METADATA_TRACK_PICTURE_ESSENCE:
|
|
templ =
|
|
gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
|
|
"video_%u");
|
|
pad_name = g_strdup_printf ("video_%u", source_track->track_id);
|
|
break;
|
|
case MXF_METADATA_TRACK_SOUND_ESSENCE:
|
|
templ =
|
|
gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
|
|
"audio_%u");
|
|
pad_name = g_strdup_printf ("audio_%u", source_track->track_id);
|
|
break;
|
|
case MXF_METADATA_TRACK_DATA_ESSENCE:
|
|
templ =
|
|
gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
|
|
"data_%u");
|
|
pad_name = g_strdup_printf ("data_%u", source_track->track_id);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
|
|
g_assert (templ != NULL);
|
|
|
|
/* Create pad */
|
|
pad = (GstMXFPad *) g_object_new (GST_TYPE_MXF_PAD,
|
|
"name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
|
|
pad->need_segment = TRUE;
|
|
g_free (pad_name);
|
|
}
|
|
|
|
if (!pad) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"Not the first pad addition run, ignoring new track");
|
|
continue;
|
|
}
|
|
|
|
/* Update pad */
|
|
pad->track_id = track->track_id;
|
|
pad->track_type = track_type;
|
|
|
|
pad->material_package = current_package;
|
|
pad->material_track = track;
|
|
pad->current_material_component = 0;
|
|
pad->component = component;
|
|
|
|
pad->source_package = source_package;
|
|
pad->source_track = source_track;
|
|
|
|
pad->handle_essence_element = NULL;
|
|
g_free (pad->mapping_data);
|
|
pad->mapping_data = NULL;
|
|
|
|
switch (track_type) {
|
|
case MXF_METADATA_TRACK_PICTURE_ESSENCE:
|
|
if (mxf_is_mpeg_video_essence_track (source_track))
|
|
caps =
|
|
mxf_mpeg_video_create_caps (source_package, source_track,
|
|
&pad->tags, &pad->handle_essence_element, &pad->mapping_data);
|
|
else if (mxf_is_dv_dif_essence_track (source_track))
|
|
caps =
|
|
mxf_dv_dif_create_caps (source_package, source_track,
|
|
&pad->tags, &pad->handle_essence_element, &pad->mapping_data);
|
|
break;
|
|
case MXF_METADATA_TRACK_SOUND_ESSENCE:
|
|
if (mxf_is_aes_bwf_essence_track (source_track))
|
|
caps =
|
|
mxf_aes_bwf_create_caps (source_package, source_track, &pad->tags,
|
|
&pad->handle_essence_element, &pad->mapping_data);
|
|
else if (mxf_is_dv_dif_essence_track (source_track))
|
|
caps =
|
|
mxf_dv_dif_create_caps (source_package, source_track,
|
|
&pad->tags, &pad->handle_essence_element, &pad->mapping_data);
|
|
break;
|
|
case MXF_METADATA_TRACK_DATA_ESSENCE:
|
|
if (mxf_is_dv_dif_essence_track (source_track))
|
|
caps =
|
|
mxf_dv_dif_create_caps (source_package, source_track,
|
|
&pad->tags, &pad->handle_essence_element, &pad->mapping_data);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
|
|
if (!caps) {
|
|
GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
|
|
gst_object_unref (pad);
|
|
continue;
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
|
|
|
|
if (pad->caps && !gst_caps_is_equal (pad->caps, caps)) {
|
|
gst_pad_set_caps (GST_PAD_CAST (pad), caps);
|
|
gst_caps_replace (&pad->caps, gst_caps_ref (caps));
|
|
} else if (!pad->caps) {
|
|
gst_pad_set_caps (GST_PAD_CAST (pad), caps);
|
|
pad->caps = gst_caps_ref (caps);
|
|
|
|
gst_pad_set_event_function (GST_PAD_CAST (pad),
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
|
|
|
|
gst_pad_set_query_type_function (GST_PAD_CAST (pad),
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query_type));
|
|
gst_pad_set_query_function (GST_PAD_CAST (pad),
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
|
|
|
|
gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
|
|
gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
|
|
|
|
gst_element_add_pad (GST_ELEMENT_CAST (demux), gst_object_ref (pad));
|
|
|
|
if (!demux->src)
|
|
demux->src = g_ptr_array_new ();
|
|
g_ptr_array_add (demux->src, pad);
|
|
}
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key,
|
|
GstBuffer * buffer)
|
|
{
|
|
guint16 type;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
type = GST_READ_UINT16_BE (key->u + 13);
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling metadata of size %u at offset %"
|
|
G_GUINT64_FORMAT " of type 0x%04d", GST_BUFFER_SIZE (buffer),
|
|
demux->offset, type);
|
|
|
|
if (G_UNLIKELY (!demux->partition.valid)) {
|
|
GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (G_UNLIKELY (!demux->primer.valid)) {
|
|
GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (type != MXF_METADATA_PREFACE && !demux->update_metadata) {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Skipping parsing of metadata because it's older than what we have");
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
switch (type) {
|
|
case MXF_METADATA_PREFACE:
|
|
ret = gst_mxf_demux_handle_metadata_preface (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_IDENTIFICATION:
|
|
ret = gst_mxf_demux_handle_metadata_identification (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_CONTENT_STORAGE:
|
|
ret = gst_mxf_demux_handle_metadata_content_storage (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_ESSENCE_CONTAINER_DATA:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_essence_container_data (demux,
|
|
key, buffer);
|
|
break;
|
|
case MXF_METADATA_MATERIAL_PACKAGE:
|
|
ret = gst_mxf_demux_handle_metadata_material_package (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_SOURCE_PACKAGE:
|
|
ret = gst_mxf_demux_handle_metadata_source_package (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_TRACK:
|
|
ret = gst_mxf_demux_handle_metadata_track (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_SEQUENCE:
|
|
ret = gst_mxf_demux_handle_metadata_sequence (demux, key, buffer);
|
|
break;
|
|
case MXF_METADATA_TIMECODE_COMPONENT:
|
|
case MXF_METADATA_SOURCE_CLIP:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_structural_component (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_generic_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_FILE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_file_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_generic_picture_essence_descriptor
|
|
(demux, key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_cdci_picture_essence_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_rgba_picture_essence_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_MPEG_VIDEO_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_mpeg_video_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_generic_sound_essence_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_MULTIPLE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_multiple_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR:
|
|
ret =
|
|
gst_mxf_demux_handle_metadata_wave_audio_essence_descriptor (demux,
|
|
key, type, buffer);
|
|
break;
|
|
case MXF_METADATA_NETWORK_LOCATOR:
|
|
case MXF_METADATA_TEXT_LOCATOR:
|
|
ret = gst_mxf_demux_handle_metadata_locator (demux, key, type, buffer);
|
|
break;
|
|
default:
|
|
GST_WARNING_OBJECT (demux,
|
|
"Unknown or unhandled metadata type 0x%04x", type);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling generic container system item of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
/* TODO: parse this */
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
guint32 track_number;
|
|
guint i, j;
|
|
GstMXFPad *pad = NULL;
|
|
GstBuffer *inbuf;
|
|
GstBuffer *outbuf = NULL;
|
|
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling generic container essence element of size %u"
|
|
" at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
GST_DEBUG_OBJECT (demux, " type = 0x%02x", key->u[12]);
|
|
GST_DEBUG_OBJECT (demux, " essence element count = 0x%02x", key->u[13]);
|
|
GST_DEBUG_OBJECT (demux, " essence element type = 0x%02x", key->u[14]);
|
|
GST_DEBUG_OBJECT (demux, " essence element number = 0x%02x", key->u[15]);
|
|
|
|
if (!demux->current_package) {
|
|
GST_ERROR_OBJECT (demux, "No package selected yet");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
if (!demux->src || demux->src->len == 0) {
|
|
GST_ERROR_OBJECT (demux, "No streams created yet");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
track_number = GST_READ_UINT32_BE (&key->u[12]);
|
|
|
|
for (i = 0; i < demux->src->len; i++) {
|
|
GstMXFPad *p = g_ptr_array_index (demux->src, i);
|
|
|
|
if (p->source_track->track_number == track_number ||
|
|
(p->source_track->track_number == 0 &&
|
|
demux->src->len == 1 &&
|
|
demux->current_package->n_essence_tracks == 1)) {
|
|
if (demux->essence_container_data) {
|
|
for (j = 0; j < demux->essence_container_data->len; j++) {
|
|
MXFMetadataEssenceContainerData *edata =
|
|
&g_array_index (demux->essence_container_data,
|
|
MXFMetadataEssenceContainerData, j);
|
|
|
|
if (p->source_package == edata->linked_package
|
|
&& demux->partition.body_sid == edata->body_sid) {
|
|
pad = p;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
pad = p;
|
|
}
|
|
|
|
if (pad)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pad) {
|
|
GST_WARNING_OBJECT (demux, "No corresponding pad found");
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
/* TODO: Use a better start value */
|
|
if (pad->need_segment) {
|
|
gst_pad_push_event (GST_PAD_CAST (pad),
|
|
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
|
|
pad->need_segment = FALSE;
|
|
}
|
|
|
|
/* Create subbuffer to be able to change metadata */
|
|
inbuf = gst_buffer_create_sub (buffer, 0, GST_BUFFER_SIZE (buffer));
|
|
|
|
GST_BUFFER_TIMESTAMP (inbuf) =
|
|
gst_util_uint64_scale (pad->essence_element_count +
|
|
pad->material_track->origin,
|
|
GST_SECOND * pad->material_track->edit_rate.d,
|
|
pad->material_track->edit_rate.n);
|
|
GST_BUFFER_DURATION (inbuf) =
|
|
gst_util_uint64_scale (GST_SECOND, pad->material_track->edit_rate.d,
|
|
pad->material_track->edit_rate.n);
|
|
GST_BUFFER_OFFSET (inbuf) = pad->essence_element_count;
|
|
GST_BUFFER_OFFSET_END (inbuf) = GST_BUFFER_OFFSET_NONE;
|
|
gst_buffer_set_caps (inbuf, pad->caps);
|
|
|
|
if (pad->handle_essence_element) {
|
|
/* Takes ownership of inbuf */
|
|
ret =
|
|
pad->handle_essence_element (key, inbuf, pad->caps, pad->source_package,
|
|
pad->source_track, pad->component, pad->mapping_data, &outbuf);
|
|
inbuf = NULL;
|
|
} else {
|
|
outbuf = inbuf;
|
|
inbuf = NULL;
|
|
ret = GST_FLOW_OK;
|
|
}
|
|
|
|
pad->essence_element_count++;
|
|
|
|
if (ret != GST_FLOW_OK) {
|
|
GST_ERROR_OBJECT (demux, "Failed to handle essence element");
|
|
if (outbuf) {
|
|
gst_buffer_unref (outbuf);
|
|
outbuf = NULL;
|
|
}
|
|
}
|
|
|
|
if (outbuf) {
|
|
ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
|
|
ret = gst_mxf_demux_combine_flows (demux, pad, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, const MXFUL * key,
|
|
GstBuffer * buffer)
|
|
{
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling random index pack of size %u at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
if (demux->partition_index) {
|
|
GST_DEBUG_OBJECT (demux, "Already parsed random index pack");
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
if (!mxf_random_index_pack_parse (key, GST_BUFFER_DATA (buffer),
|
|
GST_BUFFER_SIZE (buffer), &demux->partition_index)) {
|
|
GST_ERROR_OBJECT (demux, "Parsing random index pack failed");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux,
|
|
const MXFUL * key, GstBuffer * buffer)
|
|
{
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Handling index table segment of size %u at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
|
|
/* TODO: Parse this */
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_pull_klv_packet (GstMXFDemux * demux, guint64 offset, MXFUL * key,
|
|
GstBuffer ** outbuf, guint * read)
|
|
{
|
|
GstBuffer *buffer = NULL;
|
|
const guint8 *data;
|
|
guint64 data_offset = 0;
|
|
guint64 length;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
memset (key, 0, sizeof (MXFUL));
|
|
|
|
/* Pull 16 byte key and first byte of BER encoded length */
|
|
if ((ret =
|
|
gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
|
|
goto beach;
|
|
|
|
data = GST_BUFFER_DATA (buffer);
|
|
|
|
memcpy (key, GST_BUFFER_DATA (buffer), 16);
|
|
|
|
/* Decode BER encoded packet length */
|
|
if ((data[16] & 0x80) == 0) {
|
|
length = data[16];
|
|
data_offset = 17;
|
|
} else {
|
|
guint slen = data[16] & 0x7f;
|
|
|
|
data_offset = 16 + 1 + slen;
|
|
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
|
|
/* Must be at most 8 according to SMPTE-379M 5.3.4 */
|
|
if (slen > 8) {
|
|
GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
|
|
ret = GST_FLOW_ERROR;
|
|
goto beach;
|
|
}
|
|
|
|
/* Now pull the length of the packet */
|
|
if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
|
|
&buffer)) != GST_FLOW_OK)
|
|
goto beach;
|
|
data = GST_BUFFER_DATA (buffer);
|
|
|
|
length = 0;
|
|
while (slen) {
|
|
length = (length << 8) | *data;
|
|
data++;
|
|
slen--;
|
|
}
|
|
}
|
|
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
|
|
/* GStreamer's buffer sizes are stored in a guint so we
|
|
* limit ourself to G_MAXUINT large buffers */
|
|
if (length > G_MAXUINT) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Unsupported KLV packet length: %" G_GUINT64_FORMAT, length);
|
|
ret = GST_FLOW_ERROR;
|
|
goto beach;
|
|
}
|
|
|
|
/* Pull the complete KLV packet */
|
|
if ((ret = gst_mxf_demux_pull_range (demux, offset + data_offset, length,
|
|
&buffer)) != GST_FLOW_OK)
|
|
goto beach;
|
|
|
|
*outbuf = buffer;
|
|
buffer = NULL;
|
|
if (read)
|
|
*read = data_offset + length;
|
|
|
|
beach:
|
|
if (buffer)
|
|
gst_buffer_unref (buffer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
gst_mxf_demux_pull_random_index_pack (GstMXFDemux * demux)
|
|
{
|
|
GstBuffer *buffer;
|
|
GstFlowReturn ret;
|
|
gint64 filesize = -1;
|
|
GstFormat fmt = GST_FORMAT_BYTES;
|
|
guint32 pack_size;
|
|
MXFUL key;
|
|
|
|
if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &filesize) ||
|
|
fmt != GST_FORMAT_BYTES || filesize == -1) {
|
|
GST_DEBUG_OBJECT (demux, "Can't query upstream size");
|
|
return;
|
|
}
|
|
|
|
g_assert (filesize > 4);
|
|
|
|
if ((ret =
|
|
gst_mxf_demux_pull_range (demux, filesize - 4, 4,
|
|
&buffer)) != GST_FLOW_OK) {
|
|
GST_DEBUG_OBJECT (demux, "Failed pulling last 4 bytes");
|
|
return;
|
|
}
|
|
|
|
pack_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer));
|
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
if (pack_size < 20) {
|
|
GST_DEBUG_OBJECT (demux, "Too small pack size");
|
|
return;
|
|
} else if (pack_size > filesize - 20) {
|
|
GST_DEBUG_OBJECT (demux, "Too large pack size");
|
|
return;
|
|
}
|
|
|
|
if ((ret =
|
|
gst_mxf_demux_pull_range (demux, filesize - pack_size, 16,
|
|
&buffer)) != GST_FLOW_OK) {
|
|
GST_DEBUG_OBJECT (demux, "Failed pulling random index pack key");
|
|
return;
|
|
}
|
|
|
|
memcpy (&key, GST_BUFFER_DATA (buffer), 16);
|
|
gst_buffer_unref (buffer);
|
|
|
|
if (!mxf_is_random_index_pack (&key)) {
|
|
GST_DEBUG_OBJECT (demux, "No random index pack");
|
|
return;
|
|
}
|
|
|
|
if ((ret =
|
|
gst_mxf_demux_pull_klv_packet (demux, filesize - pack_size, &key,
|
|
&buffer, NULL)) != GST_FLOW_OK) {
|
|
GST_DEBUG_OBJECT (demux, "Failed pulling random index pack");
|
|
return;
|
|
}
|
|
|
|
|
|
gst_mxf_demux_handle_random_index_pack (demux, &key, buffer);
|
|
gst_buffer_unref (buffer);
|
|
|
|
if (!demux->partition_index)
|
|
demux->partition_index =
|
|
g_array_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry));
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
|
|
{
|
|
MXFPartitionPack partition;
|
|
MXFPrimerPack primer;
|
|
guint64 offset, old_offset = demux->offset;
|
|
MXFUL key;
|
|
GstBuffer *buffer = NULL;
|
|
guint read = 0;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
memcpy (&partition, &demux->partition, sizeof (MXFPartitionPack));
|
|
memcpy (&primer, &demux->primer, sizeof (MXFPrimerPack));
|
|
memset (&demux->partition, 0, sizeof (MXFPartitionPack));
|
|
memset (&demux->primer, 0, sizeof (MXFPrimerPack));
|
|
|
|
gst_mxf_demux_reset_metadata (demux);
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->footer_partition_pack_offset;
|
|
|
|
next_try:
|
|
mxf_partition_pack_reset (&demux->partition);
|
|
mxf_primer_pack_reset (&demux->primer);
|
|
|
|
ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
goto out;
|
|
|
|
if (!mxf_is_partition_pack (&key))
|
|
goto out;
|
|
|
|
if (!mxf_partition_pack_parse (&key, &demux->partition,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)))
|
|
goto out;
|
|
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
|
|
if (demux->partition.header_byte_count == 0) {
|
|
if (demux->partition.prev_partition == 0
|
|
|| demux->partition.this_partition == 0)
|
|
goto out;
|
|
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
|
|
while (TRUE) {
|
|
ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
|
|
if (mxf_is_fill (&key)) {
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
} else if (mxf_is_primer_pack (&key)) {
|
|
if (!mxf_primer_pack_parse (&key, &demux->primer,
|
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
offset =
|
|
demux->header_partition_pack_offset +
|
|
demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
break;
|
|
} else {
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
}
|
|
|
|
/* parse metadata */
|
|
while (TRUE) {
|
|
ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
|
|
if (mxf_is_metadata (&key)) {
|
|
ret = gst_mxf_demux_handle_metadata (demux, &key, buffer);
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
|
|
gst_mxf_demux_reset_metadata (demux);
|
|
offset =
|
|
demux->header_partition_pack_offset +
|
|
demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
} else if (mxf_is_fill (&key)) {
|
|
offset += read;
|
|
gst_buffer_unref (buffer);
|
|
buffer = NULL;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* resolve references etc */
|
|
|
|
if (gst_mxf_demux_handle_header_metadata_resolve_references (demux) !=
|
|
GST_FLOW_OK
|
|
|| gst_mxf_demux_handle_header_metadata_update_streams (demux) !=
|
|
GST_FLOW_OK) {
|
|
offset =
|
|
demux->header_partition_pack_offset + demux->partition.prev_partition;
|
|
goto next_try;
|
|
}
|
|
|
|
demux->final_metadata = TRUE;
|
|
|
|
out:
|
|
if (buffer)
|
|
gst_buffer_unref (buffer);
|
|
|
|
mxf_partition_pack_reset (&demux->partition);
|
|
mxf_primer_pack_reset (&demux->primer);
|
|
memcpy (&demux->partition, &partition, sizeof (MXFPartitionPack));
|
|
memcpy (&demux->primer, &primer, sizeof (MXFPrimerPack));
|
|
|
|
demux->offset = old_offset;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key,
|
|
GstBuffer * buffer)
|
|
{
|
|
gchar key_str[48];
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
/* In pull mode try to get the last metadata */
|
|
if (demux->pull_footer_metadata && !demux->final_metadata
|
|
&& demux->random_access && demux->partition.valid
|
|
&& demux->partition.type == MXF_PARTITION_PACK_HEADER
|
|
&& (!demux->partition.closed || !demux->partition.complete)
|
|
&& demux->footer_partition_pack_offset != 0) {
|
|
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;
|
|
}
|
|
|
|
/* TODO: - Pull random index pack from footer partition?
|
|
* - Pull all partitions for parsing all index segments and having a complete index
|
|
* as first thing. This also will make it possible to use the latest header
|
|
* metadata if it's not in the footer partition
|
|
*/
|
|
|
|
if (demux->update_metadata
|
|
&& !mxf_timestamp_is_unknown (&demux->preface.last_modified_date)
|
|
&& !mxf_is_metadata (key) && !mxf_is_descriptive_metadata (key)
|
|
&& !mxf_is_fill (key)) {
|
|
if ((ret =
|
|
gst_mxf_demux_handle_header_metadata_resolve_references (demux)) !=
|
|
GST_FLOW_OK)
|
|
goto beach;
|
|
if ((ret =
|
|
gst_mxf_demux_handle_header_metadata_update_streams (demux)) !=
|
|
GST_FLOW_OK)
|
|
goto beach;
|
|
}
|
|
|
|
if (!mxf_is_mxf_packet (key)) {
|
|
GST_WARNING_OBJECT (demux,
|
|
"Skipping non-MXF packet of size %u at offset %"
|
|
G_GUINT64_FORMAT ", key: %s", GST_BUFFER_SIZE (buffer), demux->offset,
|
|
mxf_ul_to_string (key, key_str));
|
|
} else if (mxf_is_partition_pack (key)) {
|
|
ret = gst_mxf_demux_handle_partition_pack (demux, key, buffer);
|
|
} else if (mxf_is_primer_pack (key)) {
|
|
ret = gst_mxf_demux_handle_primer_pack (demux, key, buffer);
|
|
} else if (mxf_is_metadata (key)) {
|
|
ret = gst_mxf_demux_handle_metadata (demux, key, buffer);
|
|
} else if (mxf_is_generic_container_system_item (key)) {
|
|
ret =
|
|
gst_mxf_demux_handle_generic_container_system_item (demux, key, buffer);
|
|
} else if (mxf_is_generic_container_essence_element (key)) {
|
|
ret =
|
|
gst_mxf_demux_handle_generic_container_essence_element (demux, key,
|
|
buffer);
|
|
} else if (mxf_is_random_index_pack (key)) {
|
|
ret = gst_mxf_demux_handle_random_index_pack (demux, key, buffer);
|
|
} else if (mxf_is_index_table_segment (key)) {
|
|
ret = gst_mxf_demux_handle_index_table_segment (demux, key, buffer);
|
|
} else if (mxf_is_fill (key)) {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Skipping filler packet of size %u at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
|
|
} else {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Skipping unknown packet of size %u at offset %"
|
|
G_GUINT64_FORMAT ", key: %s", GST_BUFFER_SIZE (buffer), demux->offset,
|
|
mxf_ul_to_string (key, key_str));
|
|
}
|
|
|
|
beach:
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
|
|
{
|
|
GstBuffer *buffer = NULL;
|
|
MXFUL key;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
guint read = 0;
|
|
|
|
ret =
|
|
gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
|
|
&read);
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
goto beach;
|
|
|
|
ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer);
|
|
|
|
demux->offset += read;
|
|
|
|
beach:
|
|
if (buffer)
|
|
gst_buffer_unref (buffer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_loop (GstPad * pad)
|
|
{
|
|
GstMXFDemux *demux = NULL;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
|
|
demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
|
|
|
|
if (demux->run_in == -1) {
|
|
/* Skip run-in, which is at most 64K and is finished
|
|
* by a header partition pack */
|
|
while (demux->offset < 64 * 1024) {
|
|
GstBuffer *buffer;
|
|
|
|
if ((ret =
|
|
gst_mxf_demux_pull_range (demux, demux->offset, 16,
|
|
&buffer)) != GST_FLOW_OK)
|
|
break;
|
|
|
|
if (mxf_is_header_partition_pack ((const MXFUL *)
|
|
GST_BUFFER_DATA (buffer))) {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Found header partition pack at offset %" G_GUINT64_FORMAT,
|
|
demux->offset);
|
|
demux->run_in = demux->offset;
|
|
demux->header_partition_pack_offset = demux->offset;
|
|
gst_buffer_unref (buffer);
|
|
break;
|
|
}
|
|
|
|
demux->offset++;
|
|
gst_buffer_unref (buffer);
|
|
}
|
|
}
|
|
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
goto pause;
|
|
|
|
if (G_UNLIKELY (demux->run_in == -1)) {
|
|
GST_ERROR_OBJECT (demux, "No valid header partition pack found");
|
|
ret = GST_FLOW_ERROR;
|
|
goto pause;
|
|
}
|
|
|
|
/* First of all pull&parse the random index pack at EOF */
|
|
if (!demux->partition_index) {
|
|
gst_mxf_demux_pull_random_index_pack (demux);
|
|
}
|
|
|
|
/* Now actually do something */
|
|
ret = gst_mxf_demux_pull_and_handle_klv_packet (demux);
|
|
|
|
/* pause if something went wrong */
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
goto pause;
|
|
|
|
/* check EOS condition */
|
|
if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
|
|
(demux->segment.stop != -1) &&
|
|
(demux->segment.last_stop >= demux->segment.stop)) {
|
|
ret = GST_FLOW_UNEXPECTED;
|
|
goto pause;
|
|
}
|
|
|
|
gst_object_unref (demux);
|
|
|
|
return;
|
|
|
|
pause:
|
|
{
|
|
const gchar *reason = gst_flow_get_name (ret);
|
|
|
|
GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
|
|
gst_pad_pause_task (pad);
|
|
|
|
if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
|
|
if (ret == GST_FLOW_UNEXPECTED) {
|
|
/* perform EOS logic */
|
|
if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
|
|
gint64 stop;
|
|
|
|
/* for segment playback we need to post when (in stream time)
|
|
* we stopped, this is either stop (when set) or the duration. */
|
|
if ((stop = demux->segment.stop) == -1)
|
|
stop = demux->segment.duration;
|
|
|
|
GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
|
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
|
gst_message_new_segment_done (GST_OBJECT_CAST (demux),
|
|
GST_FORMAT_TIME, stop));
|
|
} else {
|
|
/* normal playback, send EOS to all linked pads */
|
|
GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
|
|
if (!gst_mxf_demux_push_src_event (demux, gst_event_new_eos ())) {
|
|
GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
|
|
}
|
|
}
|
|
} else {
|
|
GST_ELEMENT_ERROR (demux, STREAM, FAILED,
|
|
("Internal data stream error."),
|
|
("stream stopped, reason %s", reason));
|
|
gst_mxf_demux_push_src_event (demux, gst_event_new_eos ());
|
|
}
|
|
}
|
|
gst_object_unref (demux);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_mxf_demux_chain (GstPad * pad, GstBuffer * inbuf)
|
|
{
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
GstMXFDemux *demux = NULL;
|
|
MXFUL key;
|
|
const guint8 *data = NULL;
|
|
guint64 length = 0;
|
|
guint64 offset = 0;
|
|
GstBuffer *buffer = NULL;
|
|
|
|
demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
|
|
|
|
GST_LOG_OBJECT (demux, "received buffer of %u bytes at offset %"
|
|
G_GUINT64_FORMAT, GST_BUFFER_SIZE (inbuf), GST_BUFFER_OFFSET (inbuf));
|
|
|
|
if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
|
|
GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
|
|
demux->run_in = -1;
|
|
demux->offset = 0;
|
|
}
|
|
|
|
if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
|
|
GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
|
|
demux->offset = GST_BUFFER_OFFSET (inbuf);
|
|
}
|
|
|
|
gst_adapter_push (demux->adapter, inbuf);
|
|
inbuf = NULL;
|
|
|
|
while (ret == GST_FLOW_OK) {
|
|
if (G_UNLIKELY (demux->flushing)) {
|
|
GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
|
|
ret = GST_FLOW_WRONG_STATE;
|
|
break;
|
|
}
|
|
|
|
if (gst_adapter_available (demux->adapter) < 16)
|
|
break;
|
|
|
|
if (demux->run_in == -1) {
|
|
/* Skip run-in, which is at most 64K and is finished
|
|
* by a header partition pack */
|
|
|
|
while (demux->offset < 64 * 1024
|
|
&& gst_adapter_available (demux->adapter) >= 16) {
|
|
data = gst_adapter_peek (demux->adapter, 16);
|
|
|
|
if (mxf_is_header_partition_pack ((const MXFUL *)
|
|
data)) {
|
|
GST_DEBUG_OBJECT (demux,
|
|
"Found header partition pack at offset %" G_GUINT64_FORMAT,
|
|
demux->offset);
|
|
demux->run_in = demux->offset;
|
|
demux->header_partition_pack_offset = demux->offset;
|
|
break;
|
|
}
|
|
gst_adapter_flush (demux->adapter, 1);
|
|
}
|
|
}
|
|
|
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
|
break;
|
|
|
|
/* Need more data */
|
|
if (demux->run_in == -1 && 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;
|
|
}
|
|
|
|
if (gst_adapter_available (demux->adapter) < 17)
|
|
break;
|
|
|
|
/* Now actually do something */
|
|
memset (&key, 0, sizeof (MXFUL));
|
|
|
|
/* Pull 16 byte key and first byte of BER encoded length */
|
|
data = gst_adapter_peek (demux->adapter, 17);
|
|
|
|
memcpy (&key, data, 16);
|
|
|
|
/* Decode BER encoded packet length */
|
|
if ((data[16] & 0x80) == 0) {
|
|
length = data[16];
|
|
offset = 17;
|
|
} else {
|
|
guint slen = data[16] & 0x7f;
|
|
|
|
offset = 16 + 1 + slen;
|
|
|
|
/* Must be at most 8 according to SMPTE-379M 5.3.4 and
|
|
* GStreamer buffers can only have a 4 bytes length */
|
|
if (slen > 8) {
|
|
GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
|
|
ret = GST_FLOW_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (gst_adapter_available (demux->adapter) < 17 + slen)
|
|
break;
|
|
|
|
data = gst_adapter_peek (demux->adapter, 17 + slen);
|
|
data += 17;
|
|
|
|
length = 0;
|
|
while (slen) {
|
|
length = (length << 8) | *data;
|
|
data++;
|
|
slen--;
|
|
}
|
|
}
|
|
|
|
/* GStreamer's buffer sizes are stored in a guint so we
|
|
* limit ourself to G_MAXUINT large buffers */
|
|
if (length > G_MAXUINT) {
|
|
GST_ERROR_OBJECT (demux,
|
|
"Unsupported KLV packet length: %" G_GUINT64_FORMAT, length);
|
|
ret = GST_FLOW_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (gst_adapter_available (demux->adapter) < offset + length)
|
|
break;
|
|
|
|
gst_adapter_flush (demux->adapter, offset);
|
|
buffer = gst_adapter_take_buffer (demux->adapter, length);
|
|
|
|
ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer);
|
|
gst_buffer_unref (buffer);
|
|
}
|
|
|
|
gst_object_unref (demux);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_src_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstMXFDemux *demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
|
|
gboolean ret;
|
|
|
|
GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_SEEK:
|
|
/* TODO: handle this */
|
|
gst_event_unref (event);
|
|
ret = FALSE;
|
|
break;
|
|
default:
|
|
ret = gst_pad_push_event (demux->sinkpad, event);
|
|
break;
|
|
}
|
|
|
|
gst_object_unref (demux);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const GstQueryType *
|
|
gst_mxf_demux_src_query_type (GstPad * pad)
|
|
{
|
|
static const GstQueryType types[] = {
|
|
GST_QUERY_POSITION,
|
|
GST_QUERY_DURATION,
|
|
0
|
|
};
|
|
|
|
return types;
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
|
|
{
|
|
GstMXFDemux *demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
|
|
gboolean ret = FALSE;
|
|
GstMXFPad *mxfpad = GST_MXF_PAD (pad);
|
|
|
|
GST_DEBUG_OBJECT (pad, "handling query %s",
|
|
gst_query_type_get_name (GST_QUERY_TYPE (query)));
|
|
|
|
switch (GST_QUERY_TYPE (query)) {
|
|
case GST_QUERY_POSITION:
|
|
{
|
|
GstFormat format;
|
|
gint64 pos;
|
|
|
|
gst_query_parse_position (query, &format, NULL);
|
|
if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
|
|
goto error;
|
|
|
|
pos = mxfpad->essence_element_count;
|
|
if (format == GST_FORMAT_TIME) {
|
|
if (!mxfpad->material_track || mxfpad->material_track->edit_rate.n == 0
|
|
|| mxfpad->material_track->edit_rate.d == 0)
|
|
goto error;
|
|
|
|
pos =
|
|
gst_util_uint64_scale (pos + mxfpad->material_track->origin,
|
|
GST_SECOND * mxfpad->material_track->edit_rate.d,
|
|
mxfpad->material_track->edit_rate.n);
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (pad,
|
|
"Returning position %" G_GINT64_FORMAT " in format %s", pos,
|
|
gst_format_get_name (format));
|
|
|
|
gst_query_set_position (query, format, pos);
|
|
ret = TRUE;
|
|
|
|
break;
|
|
}
|
|
case GST_QUERY_DURATION:{
|
|
gint64 duration;
|
|
GstFormat format;
|
|
|
|
gst_query_parse_duration (query, &format, NULL);
|
|
if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
|
|
goto error;
|
|
|
|
if (!mxfpad->material_track || !mxfpad->material_track->sequence)
|
|
goto error;
|
|
|
|
duration = mxfpad->material_track->sequence->duration;
|
|
if (format == GST_FORMAT_TIME) {
|
|
if (mxfpad->material_track->edit_rate.n == 0 ||
|
|
mxfpad->material_track->edit_rate.d == 0)
|
|
goto error;
|
|
|
|
duration =
|
|
gst_util_uint64_scale (duration,
|
|
GST_SECOND * mxfpad->material_track->edit_rate.d,
|
|
mxfpad->material_track->edit_rate.n);
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (pad,
|
|
"Returning duration %" G_GINT64_FORMAT " in format %s", duration,
|
|
gst_format_get_name (format));
|
|
|
|
gst_query_set_duration (query, format, duration);
|
|
ret = TRUE;
|
|
break;
|
|
}
|
|
default:
|
|
/* else forward upstream */
|
|
ret = gst_pad_peer_query (demux->sinkpad, query);
|
|
break;
|
|
}
|
|
|
|
done:
|
|
gst_object_unref (demux);
|
|
return ret;
|
|
|
|
/* ERRORS */
|
|
error:
|
|
{
|
|
GST_DEBUG_OBJECT (pad, "query failed");
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_sink_activate (GstPad * sinkpad)
|
|
{
|
|
if (gst_pad_check_pull_range (sinkpad)) {
|
|
return gst_pad_activate_pull (sinkpad, TRUE);
|
|
} else {
|
|
return gst_pad_activate_push (sinkpad, TRUE);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
|
|
{
|
|
GstMXFDemux *demux;
|
|
|
|
demux = GST_MXF_DEMUX (gst_pad_get_parent (sinkpad));
|
|
|
|
demux->random_access = FALSE;
|
|
|
|
gst_object_unref (demux);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
|
|
{
|
|
GstMXFDemux *demux;
|
|
|
|
demux = GST_MXF_DEMUX (gst_pad_get_parent (sinkpad));
|
|
|
|
if (active) {
|
|
demux->random_access = TRUE;
|
|
gst_object_unref (demux);
|
|
return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
|
|
sinkpad);
|
|
} else {
|
|
demux->random_access = FALSE;
|
|
gst_object_unref (demux);
|
|
return gst_pad_stop_task (sinkpad);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_mxf_demux_sink_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstMXFDemux *demux;
|
|
gboolean ret = FALSE;
|
|
|
|
demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
|
|
|
|
GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_FLUSH_START:
|
|
demux->flushing = TRUE;
|
|
ret = gst_mxf_demux_push_src_event (demux, event);
|
|
break;
|
|
case GST_EVENT_FLUSH_STOP:
|
|
gst_mxf_demux_flush (demux, TRUE);
|
|
ret = gst_mxf_demux_push_src_event (demux, event);
|
|
break;
|
|
case GST_EVENT_EOS:
|
|
if (!gst_mxf_demux_push_src_event (demux, event))
|
|
GST_WARNING_OBJECT (pad, "failed pushing EOS on streams");
|
|
ret = TRUE;
|
|
break;
|
|
case GST_EVENT_NEWSEGMENT:
|
|
/* TODO: handle this */
|
|
gst_event_unref (event);
|
|
ret = FALSE;
|
|
break;
|
|
default:
|
|
ret = gst_mxf_demux_push_src_event (demux, event);
|
|
break;
|
|
}
|
|
|
|
gst_object_unref (demux);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstStateChangeReturn
|
|
gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
|
|
{
|
|
GstMXFDemux *demux = GST_MXF_DEMUX (element);
|
|
GstStateChangeReturn ret;
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
if (ret == GST_STATE_CHANGE_FAILURE)
|
|
return ret;
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
gst_mxf_demux_reset (demux);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_finalize (GObject * object)
|
|
{
|
|
GstMXFDemux *demux = GST_MXF_DEMUX (object);
|
|
|
|
if (demux->adapter) {
|
|
g_object_unref (demux->adapter);
|
|
demux->adapter = NULL;
|
|
}
|
|
|
|
if (demux->new_seg_event) {
|
|
gst_event_unref (demux->new_seg_event);
|
|
demux->new_seg_event = NULL;
|
|
}
|
|
|
|
if (demux->close_seg_event) {
|
|
gst_event_unref (demux->close_seg_event);
|
|
demux->close_seg_event = NULL;
|
|
}
|
|
|
|
if (demux->src) {
|
|
g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
|
|
g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
|
|
g_ptr_array_free (demux->src, TRUE);
|
|
demux->src = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_base_init (gpointer g_class)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&mxf_sink_template));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&audio_src_template));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&video_src_template));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&data_src_template));
|
|
gst_element_class_set_details_simple (element_class, "MXF Demuxer",
|
|
"Codec/Demuxer",
|
|
"Demux MXF files", "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
|
|
{
|
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
|
|
|
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mxf_demux_finalize);
|
|
|
|
gstelement_class->change_state =
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
|
|
}
|
|
|
|
static void
|
|
gst_mxf_demux_init (GstMXFDemux * demux, GstMXFDemuxClass * g_class)
|
|
{
|
|
demux->sinkpad =
|
|
gst_pad_new_from_static_template (&mxf_sink_template, "sink");
|
|
|
|
gst_pad_set_event_function (demux->sinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
|
|
gst_pad_set_chain_function (demux->sinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
|
|
gst_pad_set_activate_function (demux->sinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
|
|
gst_pad_set_activatepull_function (demux->sinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_pull));
|
|
gst_pad_set_activatepush_function (demux->sinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_push));
|
|
|
|
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
|
|
|
|
demux->adapter = gst_adapter_new ();
|
|
demux->src = g_ptr_array_new ();
|
|
gst_segment_init (&demux->segment, GST_FORMAT_TIME);
|
|
|
|
gst_mxf_demux_reset (demux);
|
|
}
|