summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/deinterlace/gstdeinterlace.c3
-rw-r--r--gst/mxf/Makefile.am10
-rw-r--r--gst/mxf/mxf.c8
-rw-r--r--gst/mxf/mxfaes-bwf.c533
-rw-r--r--gst/mxf/mxfalaw.c160
-rw-r--r--gst/mxf/mxfdemux.c2
-rw-r--r--gst/mxf/mxfdv-dif.c98
-rw-r--r--gst/mxf/mxfjpeg2000.c121
-rw-r--r--gst/mxf/mxfmetadata.c2296
-rw-r--r--gst/mxf/mxfmetadata.h6
-rw-r--r--gst/mxf/mxfmpeg.c555
-rw-r--r--gst/mxf/mxfmux.c1429
-rw-r--r--gst/mxf/mxfmux.h103
-rw-r--r--gst/mxf/mxfparse.c289
-rw-r--r--gst/mxf/mxfparse.h12
-rw-r--r--gst/mxf/mxftypes.h8
-rw-r--r--gst/mxf/mxful.c268
-rw-r--r--gst/mxf/mxful.h59
-rw-r--r--gst/mxf/mxfup.c451
-rw-r--r--gst/mxf/mxfvc3.c87
-rw-r--r--gst/mxf/mxfwrite.c567
-rw-r--r--gst/mxf/mxfwrite.h85
22 files changed, 6858 insertions, 292 deletions
diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c
index 70fe1420..b2a25afe 100644
--- a/gst/deinterlace/gstdeinterlace.c
+++ b/gst/deinterlace/gstdeinterlace.c
@@ -353,6 +353,9 @@ gst_deinterlace_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
height = filter->uv_height;
fill_value = 128;
break;
+ default:
+ g_assert_not_reached ();
+ break;
}
for (x = 0; x < width; x++) {
diff --git a/gst/mxf/Makefile.am b/gst/mxf/Makefile.am
index ed824355..96534c4b 100644
--- a/gst/mxf/Makefile.am
+++ b/gst/mxf/Makefile.am
@@ -14,7 +14,10 @@ libgstmxf_la_SOURCES = \
mxfup.c \
mxfvc3.c \
mxfmetadata.c \
- mxfdms1.c
+ mxfdms1.c \
+ mxfwrite.c \
+ mxfmux.c \
+ mxful.c
libgstmxf_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
libgstmxf_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \
@@ -36,5 +39,8 @@ noinst_HEADERS = \
mxfvc3.h \
mxftypes.h \
mxfmetadata.h \
- mxfdms1.h
+ mxfdms1.h \
+ mxfwrite.h \
+ mxfmux.h \
+ mxful.h
diff --git a/gst/mxf/mxf.c b/gst/mxf/mxf.c
index ec477721..a906f1d8 100644
--- a/gst/mxf/mxf.c
+++ b/gst/mxf/mxf.c
@@ -24,6 +24,7 @@
#include "mxfquark.h"
#include "mxfdemux.h"
+#include "mxfmux.h"
#include "mxfaes-bwf.h"
#include "mxfmpeg.h"
#include "mxfdv-dif.h"
@@ -53,6 +54,8 @@ mxf_init (void)
static gboolean
plugin_init (GstPlugin * plugin)
{
+ GST_DEBUG_CATEGORY_INIT (mxf_debug, "mxf", 0, "MXF");
+
mxf_init ();
mxf_quark_initialize ();
mxf_metadata_init_types ();
@@ -67,11 +70,10 @@ plugin_init (GstPlugin * plugin)
mxf_dms1_initialize ();
if (!gst_element_register (plugin, "mxfdemux", GST_RANK_PRIMARY,
- GST_TYPE_MXF_DEMUX))
+ GST_TYPE_MXF_DEMUX) ||
+ !gst_element_register (plugin, "mxfmux", GST_RANK_NONE, GST_TYPE_MXF_MUX))
return FALSE;
- GST_DEBUG_CATEGORY_INIT (mxf_debug, "mxf", 0, "MXF");
-
return TRUE;
}
diff --git a/gst/mxf/mxfaes-bwf.c b/gst/mxf/mxfaes-bwf.c
index d40ff6a6..df9c0047 100644
--- a/gst/mxf/mxfaes-bwf.c
+++ b/gst/mxf/mxfaes-bwf.c
@@ -35,6 +35,7 @@
#include <gst/gst.h>
#include <string.h>
+#include "mxfwrite.h"
#include "mxfaes-bwf.h"
#include "mxfquark.h"
@@ -305,6 +306,210 @@ mxf_metadata_wave_audio_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_wave_audio_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataWaveAudioEssenceDescriptor *self =
+ MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_wave_audio_essence_descriptor_parent_class)->write_tags (m,
+ primer);
+ MXFLocalTag *t;
+ static const guint8 block_align_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 sequence_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00
+ };
+ static const guint8 avg_bps_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x03, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 channel_assignment_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x07,
+ 0x04, 0x02, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_envelope_version_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_envelope_format_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x07, 0x00, 0x00, 0x00
+ };
+ static const guint8 points_per_peak_value_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x08, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_envelope_block_size_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x09, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_channels_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x0A, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_frames_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x0B, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_of_peaks_position_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x0C, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_envelope_timestamp_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x0D, 0x00, 0x00, 0x00
+ };
+ static const guint8 peak_envelope_data_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x08,
+ 0x04, 0x02, 0x03, 0x01, 0x0E, 0x00, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &block_align_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->block_align);
+ mxf_primer_pack_add_mapping (primer, 0x3d0a, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->sequence_offset) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sequence_offset_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->sequence_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3d0b, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &avg_bps_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->avg_bps);
+ mxf_primer_pack_add_mapping (primer, 0x3d09, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (!mxf_ul_is_zero (&self->channel_assignment)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &channel_assignment_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->channel_assignment, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3d32, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_envelope_version) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_envelope_version_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->peak_envelope_version);
+ mxf_primer_pack_add_mapping (primer, 0x3d29, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_envelope_format) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_envelope_format_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->peak_envelope_format);
+ mxf_primer_pack_add_mapping (primer, 0x3d2a, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->points_per_peak_value) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &points_per_peak_value_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->points_per_peak_value);
+ mxf_primer_pack_add_mapping (primer, 0x3d2b, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_envelope_block_size) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_envelope_block_size_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->peak_envelope_block_size);
+ mxf_primer_pack_add_mapping (primer, 0x3d2c, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_channels) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_channels_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->peak_channels);
+ mxf_primer_pack_add_mapping (primer, 0x3d2d, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_frames) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_frames_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->peak_frames);
+ mxf_primer_pack_add_mapping (primer, 0x3d2e, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_of_peaks_position) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_of_peaks_position_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->peak_of_peaks_position);
+ mxf_primer_pack_add_mapping (primer, 0x3d2f, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_timestamp_is_unknown (&self->peak_envelope_timestamp)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_envelope_timestamp_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_timestamp_write (&self->peak_envelope_timestamp, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x3d30, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->peak_envelope_data) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &peak_envelope_data_ul, 16);
+ t->size = self->peak_envelope_data_length;
+ t->data = g_memdup (self->peak_envelope_data, t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3d31, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_wave_audio_essence_descriptor_init
(MXFMetadataWaveAudioEssenceDescriptor * self)
@@ -324,6 +529,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (WAVE_AUDIO_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_wave_audio_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_wave_audio_essence_descriptor_write_tags;
metadata_class->type = 0x0148;
}
@@ -705,6 +912,139 @@ mxf_metadata_aes3_audio_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_aes3_audio_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataAES3AudioEssenceDescriptor *self =
+ MXF_METADATA_AES3_AUDIO_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_aes3_audio_essence_descriptor_parent_class)->write_tags (m,
+ primer);
+ MXFLocalTag *t;
+ static const guint8 emphasis_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00
+ };
+ static const guint8 block_start_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x02, 0x03, 0x00, 0x00, 0x00
+ };
+ static const guint8 auxiliary_bits_mode_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 channel_status_mode_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00
+ };
+ static const guint8 fixed_channel_status_data_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x03, 0x00, 0x00, 0x00
+ };
+ static const guint8 user_data_mode_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 fixed_user_data_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x05, 0x01, 0x05, 0x00, 0x00, 0x00
+ };
+
+ if (self->emphasis) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &emphasis_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->emphasis);
+ mxf_primer_pack_add_mapping (primer, 0x3d0d, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->block_start_offset) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &block_start_offset_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->block_start_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3d0f, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->auxiliary_bits_mode) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &auxiliary_bits_mode_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->auxiliary_bits_mode);
+ mxf_primer_pack_add_mapping (primer, 0x3d08, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->channel_status_mode) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &channel_status_mode_ul, 16);
+ t->size = 8 + self->n_channel_status_mode;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_channel_status_mode);
+ GST_WRITE_UINT32_BE (t->data + 4, 1);
+ memcpy (t->data + 8, self->channel_status_mode, t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3d10, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->fixed_channel_status_data) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &fixed_channel_status_data_ul, 16);
+ t->size = 8 + 24 * self->n_fixed_channel_status_data;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_fixed_channel_status_data);
+ GST_WRITE_UINT32_BE (t->data + 4, 24);
+ for (i = 0; i < self->n_fixed_channel_status_data; i++)
+ memcpy (t->data + 8 + 24 * i, self->fixed_channel_status_data[i], 24);
+ mxf_primer_pack_add_mapping (primer, 0x3d11, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->user_data_mode) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &user_data_mode_ul, 16);
+ t->size = 8 + self->n_user_data_mode;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_user_data_mode);
+ GST_WRITE_UINT32_BE (t->data + 4, 1);
+ memcpy (t->data + 8, self->user_data_mode, t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3d12, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->fixed_user_data) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &fixed_user_data_ul, 16);
+ t->size = 8 + 24 * self->n_fixed_user_data;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_fixed_user_data);
+ GST_WRITE_UINT32_BE (t->data + 4, 24);
+ for (i = 0; i < self->n_fixed_user_data; i++)
+ memcpy (t->data + 8 + 24 * i, self->fixed_user_data[i], 24);
+ mxf_primer_pack_add_mapping (primer, 0x3d11, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
static void
mxf_metadata_aes3_audio_essence_descriptor_init
@@ -728,6 +1068,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (AES3_AUDIO_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_aes3_audio_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_aes3_audio_essence_descriptor_write_tags;
metadata_class->type = 0x0147;
}
@@ -1051,6 +1393,190 @@ static const MXFEssenceElementHandler mxf_aes_bwf_essence_handler = {
mxf_aes_bwf_create_caps
};
+typedef struct
+{
+ guint64 error;
+ gint width, rate, channels;
+ MXFFraction edit_rate;
+} BWFMappingData;
+
+static GstFlowReturn
+mxf_bwf_write_func (GstBuffer * buffer, GstCaps * caps, gpointer mapping_data,
+ GstAdapter * adapter, GstBuffer ** outbuf, gboolean flush)
+{
+ BWFMappingData *md = mapping_data;
+ guint bytes;
+ guint64 speu =
+ gst_util_uint64_scale (md->rate, md->edit_rate.d, md->edit_rate.n);
+
+ md->error += (md->edit_rate.d * md->rate) % (md->edit_rate.n);
+ if (md->error >= md->edit_rate.n) {
+ md->error = 0;
+ speu += 1;
+ }
+
+ bytes = (speu * md->channels * md->width) / 8;
+
+ if (buffer)
+ gst_adapter_push (adapter, buffer);
+
+ if (gst_adapter_available (adapter) == 0)
+ return GST_FLOW_OK;
+
+ if (flush)
+ bytes = MIN (gst_adapter_available (adapter), bytes);
+
+ if (gst_adapter_available (adapter) >= bytes) {
+ *outbuf = gst_adapter_take_buffer (adapter, bytes);
+ }
+
+ if (gst_adapter_available (adapter) >= bytes)
+ return GST_FLOW_CUSTOM_SUCCESS;
+ else
+ return GST_FLOW_OK;
+}
+
+static const guint8 bwf_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x01, 0x00
+};
+
+static MXFMetadataFileDescriptor *
+mxf_bwf_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataWaveAudioEssenceDescriptor *ret;
+ GstStructure *s;
+ BWFMappingData *md;
+ gint width, rate, channels, endianness;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "audio/x-raw-int") != 0 ||
+ !gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "rate", &rate) ||
+ !gst_structure_get_int (s, "channels", &channels) ||
+ !gst_structure_get_int (s, "endianness", &endianness)) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ return NULL;
+ }
+
+ ret = (MXFMetadataWaveAudioEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR);
+
+ memcpy (&ret->parent.parent.essence_container, &bwf_essence_container_ul, 16);
+ if (endianness == G_LITTLE_ENDIAN)
+ memcpy (&ret->parent.sound_essence_compression,
+ &mxf_sound_essence_compression_uncompressed, 16);
+ else
+ memcpy (&ret->parent.sound_essence_compression,
+ &mxf_sound_essence_compression_aiff, 16);
+
+ ret->block_align = (width / 8) * channels;
+ ret->parent.quantization_bits = width;
+ ret->avg_bps = ret->block_align * rate;
+
+ if (!mxf_metadata_generic_sound_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_bwf_write_func;
+
+ md = g_new0 (BWFMappingData, 1);
+ md->width = width;
+ md->rate = rate;
+ md->channels = channels;
+ *mapping_data = md;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_bwf_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_bwf_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ guint i;
+ gdouble min = G_MAXDOUBLE;
+ BWFMappingData *md = mapping_data;
+
+ for (i = 0; i < package->parent.n_tracks; i++) {
+ MXFMetadataTimelineTrack *tmp;
+
+ if (!MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[i]) ||
+ package->parent.tracks[i] == (MXFMetadataTrack *) track)
+ continue;
+
+ tmp = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[i]);
+ if (((gdouble) tmp->edit_rate.n) / ((gdouble) tmp->edit_rate.d) < min) {
+ min = ((gdouble) tmp->edit_rate.n) / ((gdouble) tmp->edit_rate.d);
+ memcpy (edit_rate, &tmp->edit_rate, sizeof (MXFFraction));
+ }
+ }
+
+ if (min == G_MAXDOUBLE) {
+ /* 100ms edit units */
+ edit_rate->n = 10;
+ edit_rate->d = 1;
+ }
+
+ memcpy (&md->edit_rate, edit_rate, sizeof (MXFFraction));
+}
+
+static guint32
+mxf_bwf_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x16 << 24) | (0x01 << 8);
+}
+
+static MXFEssenceElementWriter mxf_bwf_essence_element_writer = {
+ mxf_bwf_get_descriptor,
+ mxf_bwf_update_descriptor,
+ mxf_bwf_get_edit_rate,
+ mxf_bwf_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
+#define BWF_CAPS \
+ "audio/x-raw-int, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, MAX ], " \
+ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
+ "width = (int) 32, " \
+ "depth = (int) 32, " \
+ "signed = (boolean) TRUE; " \
+ "audio/x-raw-int, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, MAX ], " \
+ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
+ "width = (int) 24, " \
+ "depth = (int) 24, " \
+ "signed = (boolean) TRUE; " \
+ "audio/x-raw-int, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, MAX ], " \
+ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
+ "width = (int) 16, " \
+ "depth = (int) 16, " \
+ "signed = (boolean) TRUE; " \
+ "audio/x-raw-int, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, MAX ], " \
+ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
+ "width = (int) 8, " \
+ "depth = (int) 8, " \
+ "signed = (boolean) FALSE"
+
void
mxf_aes_bwf_init (void)
{
@@ -1058,4 +1584,11 @@ mxf_aes_bwf_init (void)
mxf_metadata_register (MXF_TYPE_METADATA_AES3_AUDIO_ESSENCE_DESCRIPTOR);
mxf_essence_element_handler_register (&mxf_aes_bwf_essence_handler);
+
+ mxf_bwf_essence_element_writer.pad_template =
+ gst_pad_template_new ("bwf_audio_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string (BWF_CAPS));
+ memcpy (&mxf_bwf_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_SOUND_ESSENCE), 16);
+ mxf_essence_element_writer_register (&mxf_bwf_essence_element_writer);
}
diff --git a/gst/mxf/mxfalaw.c b/gst/mxf/mxfalaw.c
index 074f1a48..40517af0 100644
--- a/gst/mxf/mxfalaw.c
+++ b/gst/mxf/mxfalaw.c
@@ -29,6 +29,7 @@
#include <string.h>
#include "mxfalaw.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -138,8 +139,167 @@ static const MXFEssenceElementHandler mxf_alaw_essence_element_handler = {
mxf_alaw_create_caps
};
+typedef struct
+{
+ guint64 error;
+ gint rate, channels;
+ MXFFraction edit_rate;
+} ALawMappingData;
+
+static GstFlowReturn
+mxf_alaw_write_func (GstBuffer * buffer, GstCaps * caps, gpointer mapping_data,
+ GstAdapter * adapter, GstBuffer ** outbuf, gboolean flush)
+{
+ ALawMappingData *md = mapping_data;
+ guint bytes;
+ guint64 speu =
+ gst_util_uint64_scale (md->rate, md->edit_rate.d, md->edit_rate.n);
+
+ md->error += (md->edit_rate.d * md->rate) % (md->edit_rate.n);
+ if (md->error >= md->edit_rate.n) {
+ md->error = 0;
+ speu += 1;
+ }
+
+ bytes = speu * md->channels;
+
+ if (buffer)
+ gst_adapter_push (adapter, buffer);
+
+ if (gst_adapter_available (adapter) == 0)
+ return GST_FLOW_OK;
+
+ if (flush)
+ bytes = MIN (gst_adapter_available (adapter), bytes);
+
+ if (gst_adapter_available (adapter) >= bytes) {
+ *outbuf = gst_adapter_take_buffer (adapter, bytes);
+ }
+
+ if (gst_adapter_available (adapter) >= bytes)
+ return GST_FLOW_CUSTOM_SUCCESS;
+ else
+ return GST_FLOW_OK;
+}
+
+static const guint8 alaw_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x03,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0a, 0x01, 0x00
+};
+
+static const MXFUL mxf_sound_essence_compression_alaw =
+ { {0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x03, 0x04, 0x02, 0x02, 0x02,
+ 0x03, 0x01, 0x01, 0x00}
+};
+
+static MXFMetadataFileDescriptor *
+mxf_alaw_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataGenericSoundEssenceDescriptor *ret;
+ GstStructure *s;
+ ALawMappingData *md;
+ gint rate, channels;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "audio/x-alaw") != 0 ||
+ !gst_structure_get_int (s, "rate", &rate) ||
+ !gst_structure_get_int (s, "channels", &channels)) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ return NULL;
+ }
+
+ ret = (MXFMetadataGenericSoundEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR);
+
+ memcpy (&ret->parent.essence_container, &alaw_essence_container_ul, 16);
+ memcpy (&ret->sound_essence_compression, &mxf_sound_essence_compression_alaw,
+ 16);
+
+ if (!mxf_metadata_generic_sound_essence_descriptor_from_caps (ret, caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_alaw_write_func;
+
+ md = g_new0 (ALawMappingData, 1);
+ md->rate = rate;
+ md->channels = channels;
+ *mapping_data = md;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_alaw_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_alaw_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ guint i;
+ gdouble min = G_MAXDOUBLE;
+ ALawMappingData *md = mapping_data;
+
+ for (i = 0; i < package->parent.n_tracks; i++) {
+ MXFMetadataTimelineTrack *tmp;
+
+ if (!MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[i]) ||
+ package->parent.tracks[i] == (MXFMetadataTrack *) track)
+ continue;
+
+ tmp = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[i]);
+ if (((gdouble) tmp->edit_rate.n) / ((gdouble) tmp->edit_rate.d) < min) {
+ min = ((gdouble) tmp->edit_rate.n) / ((gdouble) tmp->edit_rate.d);
+ memcpy (edit_rate, &tmp->edit_rate, sizeof (MXFFraction));
+ }
+ }
+
+ if (min == G_MAXDOUBLE) {
+ /* 100ms edit units */
+ edit_rate->n = 10;
+ edit_rate->d = 1;
+ }
+
+ memcpy (&md->edit_rate, edit_rate, sizeof (MXFFraction));
+}
+
+static guint32
+mxf_alaw_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x16 << 24) | (0x08 << 8);
+}
+
+static MXFEssenceElementWriter mxf_alaw_essence_element_writer = {
+ mxf_alaw_get_descriptor,
+ mxf_alaw_update_descriptor,
+ mxf_alaw_get_edit_rate,
+ mxf_alaw_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
+#define ALAW_CAPS \
+ "audio/x-alaw, " \
+ "rate = (int) [ 8000, 192000 ], " \
+ "channels = (int) [ 1, 2 ]"
+
void
mxf_alaw_init (void)
{
mxf_essence_element_handler_register (&mxf_alaw_essence_element_handler);
+
+ mxf_alaw_essence_element_writer.pad_template =
+ gst_pad_template_new ("alaw_audio_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string (ALAW_CAPS));
+ memcpy (&mxf_alaw_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_SOUND_ESSENCE), 16);
+ mxf_essence_element_writer_register (&mxf_alaw_essence_element_writer);
}
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index 9e486f1e..733e920d 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -1779,7 +1779,7 @@ gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
pad->last_stop);
if (ret != GST_FLOW_OK)
- break;
+ goto out;
pad->current_essence_track_position++;
diff --git a/gst/mxf/mxfdv-dif.c b/gst/mxf/mxfdv-dif.c
index 10e71b78..220100a3 100644
--- a/gst/mxf/mxfdv-dif.c
+++ b/gst/mxf/mxfdv-dif.c
@@ -24,7 +24,8 @@
/* TODO:
* - playbin hangs on a lot of MXF/DV-DIF files (bug #563827)
* - decodebin2 creates loops inside the linking graph (bug #563828)
- * - Forwarding of timestamps in dvdemux?
+ * - track descriptor might be multiple descriptor, one for sound, one for video
+ * - there might be 2 tracks for one essence, i.e. one audio/one video track
*/
#ifdef HAVE_CONFIG_H
@@ -32,9 +33,11 @@
#endif
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <string.h>
#include "mxfdv-dif.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -104,6 +107,8 @@ mxf_dv_dif_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
MXFEssenceElementHandleFunc * handler, gpointer * mapping_data)
{
GstCaps *caps = NULL;
+ guint i;
+ MXFMetadataGenericPictureEssenceDescriptor *d = NULL;
g_return_val_if_fail (track != NULL, NULL);
@@ -112,6 +117,15 @@ mxf_dv_dif_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
return NULL;
}
+ for (i = 0; i < track->parent.n_descriptor; i++) {
+ if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->
+ parent.descriptor[i])) {
+ d = MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->
+ parent.descriptor[i]);
+ break;
+ }
+ }
+
*handler = mxf_dv_dif_handle_essence_element;
/* SMPTE 383M 8 */
@@ -123,6 +137,9 @@ mxf_dv_dif_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
gst_caps_new_simple ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
NULL);
+ if (d)
+ mxf_metadata_generic_picture_essence_descriptor_set_caps (d, caps);
+
if (!*tags)
*tags = gst_tag_list_new ();
@@ -136,8 +153,87 @@ static const MXFEssenceElementHandler mxf_dv_dif_essence_element_handler = {
mxf_dv_dif_create_caps
};
+static GstFlowReturn
+mxf_dv_dif_write_func (GstBuffer * buffer, GstCaps * caps,
+ gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf,
+ gboolean flush)
+{
+ *outbuf = buffer;
+ return GST_FLOW_OK;
+}
+
+static const guint8 dv_dif_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x02, 0x7f, 0x01
+};
+
+static MXFMetadataFileDescriptor *
+mxf_dv_dif_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataCDCIPictureEssenceDescriptor *ret;
+
+ ret = (MXFMetadataCDCIPictureEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR);
+
+ memcpy (&ret->parent.parent.essence_container, &dv_dif_essence_container_ul,
+ 16);
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+ *handler = mxf_dv_dif_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_dv_dif_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_dv_dif_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ edit_rate->n = a->sample_rate.n;
+ edit_rate->d = a->sample_rate.d;
+}
+
+static guint32
+mxf_dv_dif_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x18 << 24) | (0x01 << 8);
+}
+
+static MXFEssenceElementWriter mxf_dv_dif_essence_element_writer = {
+ mxf_dv_dif_get_descriptor,
+ mxf_dv_dif_update_descriptor,
+ mxf_dv_dif_get_edit_rate,
+ mxf_dv_dif_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
void
mxf_dv_dif_init (void)
{
mxf_essence_element_handler_register (&mxf_dv_dif_essence_element_handler);
+
+ mxf_dv_dif_essence_element_writer.pad_template =
+ gst_pad_template_new ("dv_dif_video_sink_%u", GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ gst_caps_from_string ("video/x-dv, width = "
+ GST_VIDEO_SIZE_RANGE ", height = " GST_VIDEO_SIZE_RANGE
+ ", framerate = " GST_VIDEO_FPS_RANGE ", systemstream = true"));
+ memcpy (&mxf_dv_dif_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_PICTURE_ESSENCE),
+ 16);
+ mxf_essence_element_writer_register (&mxf_dv_dif_essence_element_writer);
}
diff --git a/gst/mxf/mxfjpeg2000.c b/gst/mxf/mxfjpeg2000.c
index c9d7b2aa..9d949d4e 100644
--- a/gst/mxf/mxfjpeg2000.c
+++ b/gst/mxf/mxfjpeg2000.c
@@ -31,9 +31,11 @@
#endif
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <string.h>
#include "mxfjpeg2000.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -202,8 +204,127 @@ static const MXFEssenceElementHandler mxf_jpeg2000_essence_element_handler = {
mxf_jpeg2000_create_caps
};
+static GstFlowReturn
+mxf_jpeg2000_write_func (GstBuffer * buffer, GstCaps * caps,
+ gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf,
+ gboolean flush)
+{
+ *outbuf = buffer;
+ return GST_FLOW_OK;
+}
+
+static const guint8 jpeg2000_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0c, 0x01, 0x00
+};
+
+static const guint jpeg2000_picture_essence_coding[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00
+};
+
+static MXFMetadataFileDescriptor *
+mxf_jpeg2000_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataRGBAPictureEssenceDescriptor *ret;
+ GstStructure *s;
+ guint32 fourcc;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "image/x-jpc") != 0 ||
+ !gst_structure_get_fourcc (s, "fourcc", &fourcc)) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ return NULL;
+ }
+
+ ret = (MXFMetadataRGBAPictureEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR);
+
+ memcpy (&ret->parent.parent.essence_container, &jpeg2000_essence_container_ul,
+ 16);
+ memcpy (&ret->parent.picture_essence_coding, &jpeg2000_picture_essence_coding,
+ 16);
+
+ if (fourcc == GST_MAKE_FOURCC ('s', 'R', 'G', 'B')) {
+ ret->n_pixel_layout = 3;
+ ret->pixel_layout = g_new0 (guint8, 6);
+ ret->pixel_layout[0] = 'R';
+ ret->pixel_layout[1] = 8;
+ ret->pixel_layout[2] = 'G';
+ ret->pixel_layout[3] = 8;
+ ret->pixel_layout[4] = 'B';
+ ret->pixel_layout[5] = 8;
+ } else if (fourcc == GST_MAKE_FOURCC ('s', 'Y', 'U', 'V')) {
+ ret->n_pixel_layout = 3;
+ ret->pixel_layout = g_new0 (guint8, 6);
+ ret->pixel_layout[0] = 'Y';
+ ret->pixel_layout[1] = 8;
+ ret->pixel_layout[2] = 'U';
+ ret->pixel_layout[3] = 8;
+ ret->pixel_layout[4] = 'V';
+ ret->pixel_layout[5] = 8;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_jpeg2000_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_jpeg2000_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_jpeg2000_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ edit_rate->n = a->sample_rate.n;
+ edit_rate->d = a->sample_rate.d;
+}
+
+static guint32
+mxf_jpeg2000_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x15 << 24) | (0x08 << 8);
+}
+
+static MXFEssenceElementWriter mxf_jpeg2000_essence_element_writer = {
+ mxf_jpeg2000_get_descriptor,
+ mxf_jpeg2000_update_descriptor,
+ mxf_jpeg2000_get_edit_rate,
+ mxf_jpeg2000_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
void
mxf_jpeg2000_init (void)
{
mxf_essence_element_handler_register (&mxf_jpeg2000_essence_element_handler);
+
+ mxf_jpeg2000_essence_element_writer.pad_template =
+ gst_pad_template_new ("jpeg2000_video_sink_%u", GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ gst_caps_from_string ("image/x-jpc, fields = 1, width = "
+ GST_VIDEO_SIZE_RANGE ", height = " GST_VIDEO_SIZE_RANGE
+ ", framerate = " GST_VIDEO_FPS_RANGE
+ ", fourcc = (GstFourcc) { sRGB, sYUV }"));
+ memcpy (&mxf_jpeg2000_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_PICTURE_ESSENCE),
+ 16);
+ mxf_essence_element_writer_register (&mxf_jpeg2000_essence_element_writer);
}
diff --git a/gst/mxf/mxfmetadata.c b/gst/mxf/mxfmetadata.c
index cc53ec15..07c18b0f 100644
--- a/gst/mxf/mxfmetadata.c
+++ b/gst/mxf/mxfmetadata.c
@@ -27,6 +27,7 @@
#include "mxfparse.h"
#include "mxfmetadata.h"
#include "mxfquark.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -238,6 +239,115 @@ mxf_metadata_base_to_structure (MXFMetadataBase * self)
return NULL;
}
+GstBuffer *
+mxf_metadata_base_to_buffer (MXFMetadataBase * self, MXFPrimerPack * primer)
+{
+ MXFMetadataBaseClass *klass;
+ GstBuffer *ret;
+ GList *tags, *l;
+ guint size = 0, slen;
+ guint8 ber[9];
+ MXFLocalTag *t, *last;
+ guint8 *data;
+
+ g_return_val_if_fail (MXF_IS_METADATA_BASE (self), NULL);
+ g_return_val_if_fail (primer != NULL, NULL);
+
+ klass = MXF_METADATA_BASE_GET_CLASS (self);
+ g_return_val_if_fail (klass->write_tags, NULL);
+
+ tags = klass->write_tags (self, primer);
+ g_return_val_if_fail (tags != NULL, NULL);
+
+ /* Add unknown tags */
+ if (self->other_tags) {
+ MXFLocalTag *tmp;
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ GHashTableIter iter;
+
+ g_hash_table_iter_init (&iter, self->other_tags);
+#else
+ GList *l, *values;
+
+ values = g_hash_table_get_values (self->other_tags);
+#endif
+
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) & t)) {
+#else
+ for (l = values; l; l = l->next) {
+ t = l->data;
+#endif
+ tmp = g_slice_dup (MXFLocalTag, t);
+ if (t->g_slice) {
+ tmp->data = g_slice_alloc (t->size);
+ mxf_primer_pack_add_mapping (primer, 0x0000, &t->key);
+ memcpy (tmp->data, t->data, t->size);
+ } else {
+ tmp->data = g_memdup (t->data, t->size);
+ }
+ tags = g_list_prepend (tags, tmp);
+ }
+
+#if !GLIB_CHECK_VERSION (2, 16, 0)
+ g_list_free (values);
+#endif
+ }
+
+ l = g_list_last (tags);
+ last = l->data;
+ tags = g_list_delete_link (tags, l);
+ /* Last element contains the metadata UL */
+ g_return_val_if_fail (last->size == 0, NULL);
+
+ for (l = tags; l; l = l->next) {
+ t = l->data;
+ g_assert (G_MAXUINT - t->size >= size);
+ size += 4 + t->size;
+ }
+
+ slen = mxf_ber_encode_size (size, ber);
+ size += 16 + slen;
+
+ ret = gst_buffer_new_and_alloc (size);
+
+ memcpy (GST_BUFFER_DATA (ret), &last->key, 16);
+ mxf_local_tag_free (last);
+ last = NULL;
+ memcpy (GST_BUFFER_DATA (ret) + 16, ber, slen);
+
+ data = GST_BUFFER_DATA (ret) + 16 + slen;
+ size -= 16 + slen;
+
+ for (l = tags; l; l = l->next) {
+ guint16 local_tag;
+
+ g_assert (size >= 4);
+ t = l->data;
+
+ local_tag =
+ GPOINTER_TO_UINT (g_hash_table_lookup (primer->reverse_mappings,
+ &t->key));
+ g_assert (local_tag != 0);
+
+ GST_WRITE_UINT16_BE (data, local_tag);
+ GST_WRITE_UINT16_BE (data + 2, t->size);
+ data += 4;
+ size -= 4;
+ g_assert (size >= t->size);
+
+ memcpy (data, t->data, t->size);
+ data += t->size;
+ size -= t->size;
+
+ mxf_local_tag_free (t);
+ }
+
+ g_list_free (tags);
+
+ return ret;
+}
+
G_DEFINE_ABSTRACT_TYPE (MXFMetadata, mxf_metadata, MXF_TYPE_METADATA_BASE);
static gboolean
@@ -281,12 +391,65 @@ error:
return FALSE;
}
+static GList *
+mxf_metadata_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer)
+{
+ MXFMetadata *self = MXF_METADATA (m);
+ GList *ret = NULL;
+ MXFLocalTag *t;
+ MXFMetadataClass *klass;
+ static const guint8 metadata_key[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 instance_uid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 generation_uid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+
+ g_return_val_if_fail (MXF_IS_METADATA (self), NULL);
+ klass = MXF_METADATA_GET_CLASS (self);
+
+ /* Last element contains the metadata key */
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, metadata_key, 16);
+ GST_WRITE_UINT16_BE (&t->key.u[13], klass->type);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &instance_uid_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (16);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->parent.instance_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3c0a, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (!mxf_ul_is_zero (&self->parent.generation_uid)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &generation_uid_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (16);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->parent.generation_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x0102, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_class_init (MXFMetadataClass * klass)
{
MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass;
metadata_base_class->handle_tag = mxf_metadata_handle_tag;
+ metadata_base_class->write_tags = mxf_metadata_write_tags;
}
static void
@@ -712,6 +875,159 @@ mxf_metadata_preface_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_preface_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer)
+{
+ MXFMetadataPreface *self = MXF_METADATA_PREFACE (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS (mxf_metadata_preface_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ guint i;
+ static const guint8 last_modified_date_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x04, 0x00, 0x00
+ };
+ static const guint8 version_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x03, 0x01, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 object_model_version_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x03, 0x01, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 primary_package_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x08, 0x00, 0x00
+ };
+ static const guint8 identifications_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x04, 0x00, 0x00
+ };
+ static const guint8 content_storage_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x01, 0x00, 0x00
+ };
+ static const guint8 operational_pattern_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 essence_containers_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00
+ };
+ static const guint8 dm_schemes_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x02, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &last_modified_date_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (8);
+ t->g_slice = TRUE;
+ mxf_timestamp_write (&self->last_modified_date, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x3b02, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &version_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (2);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->version);
+ mxf_primer_pack_add_mapping (primer, 0x3b05, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->object_model_version) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &object_model_version_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (4);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->object_model_version);
+ mxf_primer_pack_add_mapping (primer, 0x3b07, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_ul_is_zero (&self->primary_package_uid)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &primary_package_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (16);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->primary_package_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3b08, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &identifications_ul, 16);
+ t->size = 8 + 16 * self->n_identifications;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ mxf_primer_pack_add_mapping (primer, 0x3b06, &t->key);
+ GST_WRITE_UINT32_BE (t->data, self->n_identifications);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_identifications; i++) {
+ if (!self->identifications[i])
+ continue;
+
+ memcpy (t->data + 8 + 16 * i,
+ &MXF_METADATA_BASE (self->identifications[i])->instance_uid, 16);
+ }
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &content_storage_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_primer_pack_add_mapping (primer, 0x3b03, &t->key);
+ memcpy (t->data, &MXF_METADATA_BASE (self->content_storage)->instance_uid,
+ 16);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &operational_pattern_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_primer_pack_add_mapping (primer, 0x3b09, &t->key);
+ memcpy (t->data, &self->operational_pattern, 16);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &essence_containers_ul, 16);
+ t->size = 8 + 16 * self->n_essence_containers;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ mxf_primer_pack_add_mapping (primer, 0x3b0a, &t->key);
+ GST_WRITE_UINT32_BE (t->data, self->n_essence_containers);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_essence_containers; i++) {
+ memcpy (t->data + 8 + 16 * i, &self->essence_containers[i], 16);
+ }
+ ret = g_list_prepend (ret, t);
+
+ if (self->dm_schemes) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &dm_schemes_ul, 16);
+ t->size = 8 + 16 * self->n_dm_schemes;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ mxf_primer_pack_add_mapping (primer, 0x3b0b, &t->key);
+ GST_WRITE_UINT32_BE (t->data, self->n_dm_schemes);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_dm_schemes; i++) {
+ memcpy (t->data + 8 + 16 * i, &self->dm_schemes[i], 16);
+ }
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_preface_init (MXFMetadataPreface * self)
{
@@ -729,6 +1045,7 @@ mxf_metadata_preface_class_init (MXFMetadataPrefaceClass * klass)
metadata_base_class->handle_tag = mxf_metadata_preface_handle_tag;
metadata_base_class->resolve = mxf_metadata_preface_resolve;
metadata_base_class->to_structure = mxf_metadata_preface_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_preface_write_tags;
metadata_base_class->name_quark = MXF_QUARK (PREFACE);
metadata_class->type = 0x012f;
}
@@ -912,6 +1229,127 @@ mxf_metadata_identification_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_identification_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataIdentification *self = MXF_METADATA_IDENTIFICATION (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_identification_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 company_name_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00
+ };
+ static const guint8 product_name_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x03, 0x01, 0x00, 0x00
+ };
+ static const guint8 product_version_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 version_string_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x05, 0x01, 0x00, 0x00
+ };
+ static const guint8 product_uid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00
+ };
+ static const guint8 modification_date_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x03, 0x00, 0x00
+ };
+ static const guint8 toolkit_version_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x0A, 0x00, 0x00, 0x00
+ };
+ static const guint8 platform_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x06, 0x01, 0x00, 0x00
+ };
+
+ if (self->company_name) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &company_name_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->company_name, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3c01, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->product_name) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &product_name_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->product_name, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3c02, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_product_version_is_valid (&self->product_version)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &product_version_ul, 16);
+ t->size = 10;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_product_version_write (&self->product_version, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x3c03, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->version_string) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &version_string_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->version_string, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3c04, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_ul_is_zero (&self->product_uid)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &product_uid_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->product_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3c05, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_timestamp_is_unknown (&self->modification_date)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &modification_date_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_timestamp_write (&self->modification_date, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x3c06, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_product_version_is_valid (&self->toolkit_version)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &toolkit_version_ul, 16);
+ t->size = 10;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_product_version_write (&self->toolkit_version, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x3c07, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->platform) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &platform_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->platform, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x3c08, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_identification_init (MXFMetadataIdentification * self)
{
@@ -929,6 +1367,7 @@ mxf_metadata_identification_class_init (MXFMetadataIdentificationClass * klass)
metadata_base_class->handle_tag = mxf_metadata_identification_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (IDENTIFICATION);
metadata_base_class->to_structure = mxf_metadata_identification_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_identification_write_tags;
metadata_class->type = 0x0130;
}
@@ -1151,6 +1590,69 @@ mxf_metadata_content_storage_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_content_storage_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_content_storage_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ guint i;
+ static const guint8 packages_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x01, 0x00, 0x00
+ };
+ static const guint8 essence_container_data_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x02, 0x00, 0x00
+ };
+
+ if (self->packages) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &packages_ul, 16);
+ t->size = 8 + 16 * self->n_packages;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_packages);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_packages; i++) {
+ if (!self->packages[i])
+ continue;
+
+ memcpy (t->data + 8 + i * 16,
+ &MXF_METADATA_BASE (self->packages[i])->instance_uid, 16);
+ }
+
+ mxf_primer_pack_add_mapping (primer, 0x1901, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->essence_container_data) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &essence_container_data_ul, 16);
+ t->size = 8 + 16 * self->n_essence_container_data;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_essence_container_data);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_essence_container_data; i++) {
+ if (!self->essence_container_data[i])
+ continue;
+
+ memcpy (t->data + 8 + i * 16,
+ &MXF_METADATA_BASE (self->essence_container_data[i])->instance_uid,
+ 16);
+ }
+
+ mxf_primer_pack_add_mapping (primer, 0x1902, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_content_storage_init (MXFMetadataContentStorage * self)
{
@@ -1169,6 +1671,7 @@ mxf_metadata_content_storage_class_init (MXFMetadataContentStorageClass * klass)
metadata_base_class->resolve = mxf_metadata_content_storage_resolve;
metadata_base_class->name_quark = MXF_QUARK (CONTENT_STORAGE);
metadata_base_class->to_structure = mxf_metadata_content_storage_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_content_storage_write_tags;
metadata_class->type = 0x0118;
}
@@ -1298,6 +1801,63 @@ mxf_metadata_essence_container_data_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_essence_container_data_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataEssenceContainerData *self =
+ MXF_METADATA_ESSENCE_CONTAINER_DATA (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_essence_container_data_parent_class)->write_tags (m,
+ primer);
+ MXFLocalTag *t;
+ static const guint8 linked_package_uid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 body_sid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 index_sid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &linked_package_uid_ul, 16);
+ t->size = 32;
+ t->data = g_slice_alloc0 (32);
+ t->g_slice = TRUE;
+ if (self->linked_package)
+ memcpy (t->data, &self->linked_package->parent.package_uid, 32);
+ mxf_primer_pack_add_mapping (primer, 0x2701, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &body_sid_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (4);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->body_sid);
+ mxf_primer_pack_add_mapping (primer, 0x3f07, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->index_sid) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &index_sid_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (4);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->index_sid);
+ mxf_primer_pack_add_mapping (primer, 0x3f07, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_essence_container_data_init (MXFMetadataEssenceContainerData *
self)
@@ -1318,6 +1878,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (ESSENCE_CONTAINER_DATA);
metadata_base_class->to_structure =
mxf_metadata_essence_container_data_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_essence_container_data_write_tags;
metadata_class->type = 0x0123;
}
@@ -1518,6 +2080,95 @@ mxf_metadata_generic_package_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_generic_package_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_generic_package_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 package_uid_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 name_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x03, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 package_creation_date_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x01, 0x03, 0x00, 0x00
+ };
+ static const guint8 package_modified_date_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x05, 0x00, 0x00
+ };
+ static const guint8 tracks_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x05, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &package_uid_ul, 16);
+ t->size = 32;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->package_uid, 32);
+ mxf_primer_pack_add_mapping (primer, 0x4401, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->name) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &name_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->name, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x4402, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &package_creation_date_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_timestamp_write (&self->package_creation_date, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x4405, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &package_modified_date_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ mxf_timestamp_write (&self->package_modified_date, t->data);
+ mxf_primer_pack_add_mapping (primer, 0x4404, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->tracks) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &tracks_ul, 16);
+ t->size = 8 + 16 * self->n_tracks;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_tracks);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_tracks; i++) {
+ if (!self->tracks[i])
+ continue;
+
+ memcpy (t->data + 8 + 16 * i,
+ &MXF_METADATA_BASE (self->tracks[i])->instance_uid, 16);
+ }
+ mxf_primer_pack_add_mapping (primer, 0x4403, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_generic_package_init (MXFMetadataGenericPackage * self)
{
@@ -1534,6 +2185,7 @@ mxf_metadata_generic_package_class_init (MXFMetadataGenericPackageClass * klass)
metadata_base_class->handle_tag = mxf_metadata_generic_package_handle_tag;
metadata_base_class->resolve = mxf_metadata_generic_package_resolve;
metadata_base_class->to_structure = mxf_metadata_generic_package_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_generic_package_write_tags;
}
G_DEFINE_TYPE (MXFMetadataMaterialPackage, mxf_metadata_material_package,
@@ -1802,6 +2454,34 @@ mxf_metadata_source_package_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_source_package_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataSourcePackage *self = MXF_METADATA_SOURCE_PACKAGE (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_source_package_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 descriptor_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x03, 0x00, 0x00
+ };
+
+ if (self->descriptor) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &descriptor_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &MXF_METADATA_BASE (self->descriptor)->instance_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x4701, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_source_package_init (MXFMetadataSourcePackage * self)
{
@@ -1818,6 +2498,7 @@ mxf_metadata_source_package_class_init (MXFMetadataSourcePackageClass * klass)
metadata_base_class->resolve = mxf_metadata_source_package_resolve;
metadata_base_class->name_quark = MXF_QUARK (SOURCE_PACKAGE);
metadata_base_class->to_structure = mxf_metadata_source_package_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_source_package_write_tags;
metadata_class->type = 0x0137;
}
@@ -1959,6 +2640,69 @@ mxf_metadata_track_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_track_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer)
+{
+ MXFMetadataTrack *self = MXF_METADATA_TRACK (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS (mxf_metadata_track_parent_class)->write_tags (m,
+ primer);
+ MXFLocalTag *t;
+ static const guint8 track_id_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 track_number_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 track_name_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 sequence_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x04, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &track_id_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->track_id);
+ mxf_primer_pack_add_mapping (primer, 0x4801, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &track_number_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->track_number);
+ mxf_primer_pack_add_mapping (primer, 0x4804, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->track_name) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &track_name_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->track_name, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x4802, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sequence_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &MXF_METADATA_BASE (self->sequence)->instance_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x4803, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
+
static void
mxf_metadata_track_init (MXFMetadataTrack * self)
{
@@ -1975,6 +2719,7 @@ mxf_metadata_track_class_init (MXFMetadataTrackClass * klass)
metadata_base_class->handle_tag = mxf_metadata_track_handle_tag;
metadata_base_class->resolve = mxf_metadata_track_resolve;
metadata_base_class->to_structure = mxf_metadata_track_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_track_write_tags;
}
/* SMPTE RP224 */
@@ -2022,6 +2767,18 @@ mxf_metadata_track_identifier_parse (const MXFUL * track_identifier)
return MXF_METADATA_TRACK_UNKNOWN;
}
+const MXFUL *
+mxf_metadata_track_identifier_get (MXFMetadataTrackType type)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (mxf_metadata_track_identifier); i++)
+ if (mxf_metadata_track_identifier[i].type == type)
+ return (const MXFUL *) &mxf_metadata_track_identifier[i].ul;
+
+ return NULL;
+}
+
G_DEFINE_TYPE (MXFMetadataTimelineTrack, mxf_metadata_timeline_track,
MXF_TYPE_METADATA_TRACK);
@@ -2078,6 +2835,46 @@ mxf_metadata_timeline_track_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_timeline_track_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataTimelineTrack *self = MXF_METADATA_TIMELINE_TRACK (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_timeline_track_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 edit_rate_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 origin_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &edit_rate_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->edit_rate.n);
+ GST_WRITE_UINT32_BE (t->data + 4, self->edit_rate.d);
+ mxf_primer_pack_add_mapping (primer, 0x4b01, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &origin_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->origin);
+ mxf_primer_pack_add_mapping (primer, 0x4b02, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
+
static void
mxf_metadata_timeline_track_init (MXFMetadataTimelineTrack * self)
{
@@ -2093,6 +2890,7 @@ mxf_metadata_timeline_track_class_init (MXFMetadataTimelineTrackClass * klass)
metadata_base_class->handle_tag = mxf_metadata_timeline_track_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (TIMELINE_TRACK);
metadata_base_class->to_structure = mxf_metadata_timeline_track_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_timeline_track_write_tags;
metadata_class->type = 0x013b;
}
@@ -2152,6 +2950,46 @@ mxf_metadata_event_track_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_event_track_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataEventTrack *self = MXF_METADATA_EVENT_TRACK (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_event_track_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 event_edit_rate_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 event_origin_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x0B, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &event_edit_rate_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->event_edit_rate.n);
+ GST_WRITE_UINT32_BE (t->data + 4, self->event_edit_rate.d);
+ mxf_primer_pack_add_mapping (primer, 0x4901, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &event_origin_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->event_origin);
+ mxf_primer_pack_add_mapping (primer, 0x4902, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
+
static void
mxf_metadata_event_track_init (MXFMetadataEventTrack * self)
{
@@ -2167,6 +3005,7 @@ mxf_metadata_event_track_class_init (MXFMetadataEventTrackClass * klass)
metadata_base_class->handle_tag = mxf_metadata_event_track_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (EVENT_TRACK);
metadata_base_class->to_structure = mxf_metadata_event_track_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_event_track_write_tags;
metadata_class->type = 0x0139;
}
@@ -2345,6 +3184,71 @@ mxf_metadata_sequence_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_sequence_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer)
+{
+ MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS (mxf_metadata_sequence_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 data_definition_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 duration_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00
+ };
+ static const guint8 structural_components_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x09, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &data_definition_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->data_definition, 16);
+ mxf_primer_pack_add_mapping (primer, 0x0201, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &duration_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->duration);
+ mxf_primer_pack_add_mapping (primer, 0x0202, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->structural_components) {
+ guint i;
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &structural_components_ul, 16);
+ t->size = 8 + 16 * self->n_structural_components;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+
+ GST_WRITE_UINT32_BE (t->data, self->n_structural_components);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_structural_components; i++) {
+ if (!self->structural_components[i])
+ continue;
+
+ memcpy (t->data + 8 + i * 16,
+ &MXF_METADATA_BASE (self->structural_components[i])->instance_uid,
+ 16);
+ }
+
+ mxf_primer_pack_add_mapping (primer, 0x1001, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_sequence_init (MXFMetadataSequence * self)
{
@@ -2363,6 +3267,7 @@ mxf_metadata_sequence_class_init (MXFMetadataSequenceClass * klass)
metadata_base_class->resolve = mxf_metadata_sequence_resolve;
metadata_base_class->name_quark = MXF_QUARK (SEQUENCE);
metadata_base_class->to_structure = mxf_metadata_sequence_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_sequence_write_tags;
metadata_class->type = 0x010f;
}
@@ -2429,6 +3334,45 @@ mxf_metadata_structural_component_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_structural_component_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataStructuralComponent *self = MXF_METADATA_STRUCTURAL_COMPONENT (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_structural_component_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 data_definition_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 duration_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &data_definition_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->data_definition, 16);
+ mxf_primer_pack_add_mapping (primer, 0x0201, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &duration_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->duration);
+ mxf_primer_pack_add_mapping (primer, 0x0202, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
+
static void
mxf_metadata_structural_component_init (MXFMetadataStructuralComponent * self)
{
@@ -2445,6 +3389,8 @@ static void
mxf_metadata_structural_component_handle_tag;
metadata_base_class->to_structure =
mxf_metadata_structural_component_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_structural_component_write_tags;
}
G_DEFINE_TYPE (MXFMetadataTimecodeComponent, mxf_metadata_timecode_component,
@@ -2512,6 +3458,58 @@ mxf_metadata_timecode_component_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_timecode_component_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataTimecodeComponent *self = MXF_METADATA_TIMECODE_COMPONENT (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_timecode_component_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 rounded_timecode_base_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x04, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00
+ };
+ static const guint8 start_timecode_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00
+ };
+ static const guint8 drop_frame_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x04, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &rounded_timecode_base_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->rounded_timecode_base);
+ mxf_primer_pack_add_mapping (primer, 0x1502, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &start_timecode_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->start_timecode);
+ mxf_primer_pack_add_mapping (primer, 0x1501, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &drop_frame_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->drop_frame) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0x1503, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
+
static void
mxf_metadata_timecode_component_init (MXFMetadataTimecodeComponent * self)
{
@@ -2529,6 +3527,7 @@ mxf_metadata_timecode_component_class_init (MXFMetadataTimecodeComponentClass *
metadata_base_class->name_quark = MXF_QUARK (TIMECODE_COMPONENT);
metadata_base_class->to_structure =
mxf_metadata_timecode_component_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_timecode_component_write_tags;
metadata_class->type = 0x0114;
}
@@ -2643,6 +3642,57 @@ mxf_metadata_source_clip_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_source_clip_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataSourceClip *self = MXF_METADATA_SOURCE_CLIP (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_source_clip_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 start_position_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00
+ };
+ static const guint8 source_package_id_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 source_track_id_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00
+ };
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &start_position_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->start_position);
+ mxf_primer_pack_add_mapping (primer, 0x1201, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &source_package_id_ul, 16);
+ t->size = 32;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->source_package_id, 32);
+ mxf_primer_pack_add_mapping (primer, 0x1101, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &source_track_id_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->source_track_id);
+ mxf_primer_pack_add_mapping (primer, 0x1102, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ return ret;
+}
static void
mxf_metadata_source_clip_init (MXFMetadataSourceClip * self)
@@ -2660,6 +3710,7 @@ mxf_metadata_source_clip_class_init (MXFMetadataSourceClipClass * klass)
metadata_base_class->resolve = mxf_metadata_source_clip_resolve;
metadata_base_class->name_quark = MXF_QUARK (SOURCE_CLIP);
metadata_base_class->to_structure = mxf_metadata_source_clip_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_source_clip_write_tags;
metadata_class->type = 0x0111;
}
@@ -2771,6 +3822,39 @@ mxf_metadata_dm_source_clip_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_dm_source_clip_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataDMSourceClip *self = MXF_METADATA_DM_SOURCE_CLIP (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_dm_source_clip_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 track_ids_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x07, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (self->track_ids) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &track_ids_ul, 16);
+ t->size = 8 + 4 * self->n_track_ids;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_track_ids);
+ GST_WRITE_UINT32_BE (t->data + 4, 4);
+ for (i = 0; i < self->n_track_ids; i++)
+ GST_WRITE_UINT32_BE (t->data + 8 + i * 4, self->track_ids[i]);
+ mxf_primer_pack_add_mapping (primer, 0x6103, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_dm_source_clip_init (MXFMetadataDMSourceClip * self)
{
@@ -2788,6 +3872,7 @@ mxf_metadata_dm_source_clip_class_init (MXFMetadataDMSourceClipClass * klass)
metadata_base_class->handle_tag = mxf_metadata_dm_source_clip_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (DM_SOURCE_CLIP);
metadata_base_class->to_structure = mxf_metadata_dm_source_clip_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_dm_source_clip_write_tags;
metadata_class->type = 0x0145;
}
@@ -2965,10 +4050,84 @@ mxf_metadata_dm_segment_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_dm_segment_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer)
+{
+ MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS (mxf_metadata_dm_segment_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 event_start_position_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00
+ };
+ static const guint8 event_comment_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 track_ids_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 dm_framework_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x0C, 0x00, 0x00
+ };
+
+ if (self->event_start_position != -1) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &event_start_position_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->event_start_position);
+ mxf_primer_pack_add_mapping (primer, 0x0601, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->event_comment) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &event_comment_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->event_comment, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x0602, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->track_ids) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &track_ids_ul, 16);
+ t->size = 8 + 4 * self->n_track_ids;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_track_ids);
+ GST_WRITE_UINT32_BE (t->data + 4, 4);
+ for (i = 0; i < self->n_track_ids; i++)
+ GST_WRITE_UINT32_BE (t->data + 8 + i * 4, self->track_ids[i]);
+ mxf_primer_pack_add_mapping (primer, 0x6102, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->dm_framework) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &dm_framework_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &MXF_METADATA_BASE (self->dm_framework)->instance_uid, 16);
+ mxf_primer_pack_add_mapping (primer, 0x6101, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_dm_segment_init (MXFMetadataDMSegment * self)
{
-
+ self->event_start_position = -1;
}
static void
@@ -2983,6 +4142,7 @@ mxf_metadata_dm_segment_class_init (MXFMetadataDMSegmentClass * klass)
metadata_base_class->resolve = mxf_metadata_dm_segment_resolve;
metadata_base_class->name_quark = MXF_QUARK (DM_SEGMENT);
metadata_base_class->to_structure = mxf_metadata_dm_segment_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_dm_segment_write_tags;
metadata_class->type = 0x0141;
}
@@ -3129,6 +4289,43 @@ mxf_metadata_generic_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_generic_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataGenericDescriptor *self = MXF_METADATA_GENERIC_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_generic_descriptor_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 locators_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x03, 0x00, 0x00
+ };
+
+ if (self->locators) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &locators_ul, 16);
+ t->size = 8 + 16 * self->n_locators;;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_locators);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_locators; i++) {
+ if (!self->locators[i])
+ continue;
+ memcpy (t->data + 8 + 16 * i,
+ &MXF_METADATA_BASE (self->locators[i])->instance_uid, 16);
+ }
+ mxf_primer_pack_add_mapping (primer, 0x2f01, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_generic_descriptor_init (MXFMetadataGenericDescriptor * self)
{
@@ -3147,6 +4344,7 @@ mxf_metadata_generic_descriptor_class_init (MXFMetadataGenericDescriptorClass *
metadata_base_class->resolve = mxf_metadata_generic_descriptor_resolve;
metadata_base_class->to_structure =
mxf_metadata_generic_descriptor_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_generic_descriptor_write_tags;
}
G_DEFINE_TYPE (MXFMetadataFileDescriptor, mxf_metadata_file_descriptor,
@@ -3247,6 +4445,91 @@ mxf_metadata_file_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_file_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataFileDescriptor *self = MXF_METADATA_FILE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_file_descriptor_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 linked_track_id_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x06, 0x01, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 sample_rate_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 container_duration_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x06, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 essence_container_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00
+ };
+ static const guint8 codec_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x03, 0x00, 0x00
+ };
+
+ if (self->linked_track_id) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &linked_track_id_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->linked_track_id);
+ mxf_primer_pack_add_mapping (primer, 0x3006, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sample_rate_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->sample_rate.n);
+ GST_WRITE_UINT32_BE (t->data + 4, self->sample_rate.d);
+ mxf_primer_pack_add_mapping (primer, 0x3001, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->container_duration > 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &container_duration_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->container_duration);
+ mxf_primer_pack_add_mapping (primer, 0x3002, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &essence_container_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->essence_container, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3004, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (!mxf_ul_is_zero (&self->codec)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &codec_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->codec, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3005, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_file_descriptor_init (MXFMetadataFileDescriptor * self)
{
@@ -3262,6 +4545,7 @@ mxf_metadata_file_descriptor_class_init (MXFMetadataFileDescriptorClass * klass)
metadata_base_class->handle_tag = mxf_metadata_file_descriptor_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (FILE_DESCRIPTOR);
metadata_base_class->to_structure = mxf_metadata_file_descriptor_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_file_descriptor_write_tags;
metadata_class->type = 0x0125;
}
@@ -3567,6 +4851,383 @@ mxf_metadata_generic_picture_essence_descriptor_to_structure (MXFMetadataBase *
return ret;
}
+static GList *
+mxf_metadata_generic_picture_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataGenericPictureEssenceDescriptor *self =
+ MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_generic_picture_essence_descriptor_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 signal_standard_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 frame_layout_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 stored_width_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00
+ };
+ static const guint8 stored_height_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 stored_f2_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x08, 0x00, 0x00, 0x00
+ };
+ static const guint8 sampled_width_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00
+ };
+ static const guint8 sampled_height_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x07, 0x00, 0x00, 0x00
+ };
+ static const guint8 sampled_x_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x09, 0x00, 0x00, 0x00
+ };
+ static const guint8 sampled_y_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0A, 0x00, 0x00, 0x00
+ };
+ static const guint8 display_height_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0B, 0x00, 0x00, 0x00
+ };
+ static const guint8 display_width_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0C, 0x00, 0x00, 0x00
+ };
+ static const guint8 display_x_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0D, 0x00, 0x00, 0x00
+ };
+ static const guint8 display_y_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0E, 0x00, 0x00, 0x00
+ };
+ static const guint8 display_f2_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x07, 0x00, 0x00, 0x00
+ };
+ static const guint8 aspect_ratio_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 active_format_descriptor_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x09, 0x00, 0x00, 0x00
+ };
+ static const guint8 video_line_map_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x03, 0x02, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 alpha_transparency_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 capture_gamma_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00
+ };
+ static const guint8 image_alignment_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 image_start_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 image_end_offset_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 field_dominance_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00
+ };
+ static const guint8 picture_essence_coding_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (self->signal_standard != 1) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &signal_standard_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->signal_standard);
+ mxf_primer_pack_add_mapping (primer, 0x3215, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->frame_layout != 255) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &frame_layout_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->frame_layout);
+ mxf_primer_pack_add_mapping (primer, 0x320c, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->stored_width != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &stored_width_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->stored_width);
+ mxf_primer_pack_add_mapping (primer, 0x3203, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->stored_height != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &stored_height_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->stored_height);
+ mxf_primer_pack_add_mapping (primer, 0x3202, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->stored_f2_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &stored_f2_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->stored_f2_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3216, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->sampled_width != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sampled_width_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->sampled_width);
+ mxf_primer_pack_add_mapping (primer, 0x3205, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->sampled_height != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sampled_height_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->sampled_height);
+ mxf_primer_pack_add_mapping (primer, 0x3204, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->sampled_x_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sampled_x_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->sampled_x_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3206, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->sampled_y_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sampled_y_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->sampled_y_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3207, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->display_height != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &display_height_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->display_height);
+ mxf_primer_pack_add_mapping (primer, 0x3208, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->display_width != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &display_width_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->display_width);
+ mxf_primer_pack_add_mapping (primer, 0x3209, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->display_x_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &display_x_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->display_x_offset);
+ mxf_primer_pack_add_mapping (primer, 0x320a, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->display_y_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &display_y_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->display_y_offset);
+ mxf_primer_pack_add_mapping (primer, 0x320b, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->display_f2_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &display_f2_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->display_f2_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3217, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->aspect_ratio.n != 0 && self->aspect_ratio.d != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &aspect_ratio_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->aspect_ratio.n);
+ GST_WRITE_UINT32_BE (t->data + 4, self->aspect_ratio.d);
+ mxf_primer_pack_add_mapping (primer, 0x320e, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->active_format_descriptor != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &active_format_descriptor_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->active_format_descriptor);
+ mxf_primer_pack_add_mapping (primer, 0x3218, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->video_line_map[0] != 0 || self->video_line_map[1] != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &video_line_map_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT64_BE (t->data, self->video_line_map[0]);
+ GST_WRITE_UINT64_BE (t->data + 8, self->video_line_map[1]);
+ mxf_primer_pack_add_mapping (primer, 0x320d, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->alpha_transparency != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &alpha_transparency_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->alpha_transparency);
+ mxf_primer_pack_add_mapping (primer, 0x320f, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_ul_is_zero (&self->capture_gamma)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &capture_gamma_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->capture_gamma, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3210, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->image_alignment_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &image_alignment_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->image_alignment_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3211, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->image_start_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &image_start_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->image_start_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3213, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->image_end_offset != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &image_end_offset_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->image_end_offset);
+ mxf_primer_pack_add_mapping (primer, 0x3214, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->field_dominance != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &field_dominance_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->field_dominance);
+ mxf_primer_pack_add_mapping (primer, 0x3212, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_ul_is_zero (&self->picture_essence_coding)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &picture_essence_coding_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->picture_essence_coding, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3201, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_generic_picture_essence_descriptor_init
(MXFMetadataGenericPictureEssenceDescriptor * self)
@@ -3588,6 +5249,8 @@ static void
MXF_QUARK (GENERIC_PICTURE_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_generic_picture_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_generic_picture_essence_descriptor_write_tags;
metadata_class->type = 0x0127;
}
@@ -3641,6 +5304,66 @@ void mxf_metadata_generic_picture_essence_descriptor_set_caps
par_n, par_d, NULL);
}
+static gint
+gst_greatest_common_divisor (gint a, gint b)
+{
+ while (b != 0) {
+ int temp = a;
+
+ a = b;
+ b = temp % b;
+ }
+
+ return ABS (a);
+}
+
+gboolean
+ mxf_metadata_generic_picture_essence_descriptor_from_caps
+ (MXFMetadataGenericPictureEssenceDescriptor * self, GstCaps * caps) {
+ gint par_n, par_d, gcd;
+ gint width, height;
+ gint fps_n, fps_d;
+ MXFMetadataFileDescriptor *f = (MXFMetadataFileDescriptor *) self;
+ GstStructure *s;
+
+ g_return_val_if_fail (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
+ (self), FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) {
+ GST_ERROR ("Invalid framerate");
+ return FALSE;
+ }
+ f->sample_rate.n = fps_n;
+ f->sample_rate.d = fps_d;
+
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "height", &height)) {
+ GST_ERROR ("Invalid width/height");
+ return FALSE;
+ }
+
+ self->stored_width = width;
+ self->stored_height = height;
+
+ if (!gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d)) {
+ par_n = 1;
+ par_d = 1;
+ }
+
+ self->aspect_ratio.n = par_n * width;
+ self->aspect_ratio.d = par_d * height;
+ gcd =
+ gst_greatest_common_divisor (self->aspect_ratio.n, self->aspect_ratio.d);
+ self->aspect_ratio.n /= gcd;
+ self->aspect_ratio.d /= gcd;
+
+ return TRUE;
+}
+
+
G_DEFINE_TYPE (MXFMetadataGenericSoundEssenceDescriptor,
mxf_metadata_generic_sound_essence_descriptor,
MXF_TYPE_METADATA_FILE_DESCRIPTOR);
@@ -3770,12 +5493,147 @@ mxf_metadata_generic_sound_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_generic_sound_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataGenericSoundEssenceDescriptor *self =
+ MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_generic_sound_essence_descriptor_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 audio_sampling_rate_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00
+ };
+ static const guint8 locked_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x02, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 audio_ref_level_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00
+ };
+ static const guint8 electro_spatial_formulation_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 channel_count_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 quantization_bits_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x02, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 dial_norm_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 sound_essence_compression_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x02, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (self->audio_sampling_rate.d && self->audio_sampling_rate.n) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &audio_sampling_rate_ul, 16);
+ t->size = 8;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->audio_sampling_rate.n);
+ GST_WRITE_UINT32_BE (t->data + 4, self->audio_sampling_rate.d);
+ mxf_primer_pack_add_mapping (primer, 0x3d03, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &locked_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->locked) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0x3d02, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ if (self->audio_ref_level) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &audio_ref_level_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->audio_ref_level);
+ mxf_primer_pack_add_mapping (primer, 0x3d04, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->electro_spatial_formulation != 255) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &electro_spatial_formulation_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->electro_spatial_formulation);
+ mxf_primer_pack_add_mapping (primer, 0x3d05, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->channel_count) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &channel_count_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->channel_count);
+ mxf_primer_pack_add_mapping (primer, 0x3d07, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->quantization_bits) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &quantization_bits_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->quantization_bits);
+ mxf_primer_pack_add_mapping (primer, 0x3d01, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->dial_norm != 0) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &dial_norm_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->dial_norm);
+ mxf_primer_pack_add_mapping (primer, 0x3d0c, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (!mxf_ul_is_zero (&self->sound_essence_compression)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sound_essence_compression_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->sound_essence_compression, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3d06, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_generic_sound_essence_descriptor_init
(MXFMetadataGenericSoundEssenceDescriptor * self)
{
self->audio_sampling_rate.n = 48000;
self->audio_sampling_rate.d = 1;
+ self->electro_spatial_formulation = 255;
}
static void
@@ -3791,6 +5649,8 @@ static void
MXF_QUARK (GENERIC_SOUND_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_generic_sound_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_generic_sound_essence_descriptor_write_tags;
metadata_class->type = 0x0142;
}
@@ -3817,6 +5677,38 @@ void mxf_metadata_generic_sound_essence_descriptor_set_caps
}
}
+gboolean
+ mxf_metadata_generic_sound_essence_descriptor_from_caps
+ (MXFMetadataGenericSoundEssenceDescriptor * self, GstCaps * caps) {
+ gint rate;
+ gint channels;
+ GstStructure *s;
+
+ g_return_val_if_fail (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (self),
+ FALSE);
+ g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (s, "rate", &rate) || rate == 0) {
+ GST_WARNING ("No samplerate");
+ return FALSE;
+ } else {
+ self->audio_sampling_rate.n = rate;
+ self->audio_sampling_rate.d = 1;
+ }
+
+ if (!gst_structure_get_int (s, "channels", &channels) || channels == 0) {
+ GST_WARNING ("No channels");
+ return FALSE;
+ } else {
+ self->channel_count = channels;
+ }
+
+ return TRUE;
+}
+
+
G_DEFINE_TYPE (MXFMetadataCDCIPictureEssenceDescriptor,
mxf_metadata_cdci_picture_essence_descriptor,
MXF_TYPE_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR);
@@ -3933,7 +5825,7 @@ mxf_metadata_cdci_picture_essence_descriptor_to_structure (MXFMetadataBase * m)
gst_structure_id_set (ret, MXF_QUARK (VERTICAL_SUBSAMPLING), G_TYPE_UINT,
self->vertical_subsampling, NULL);
- if (self->color_siting != 0)
+ if (self->color_siting != 255)
gst_structure_id_set (ret, MXF_QUARK (COLOR_SITING), G_TYPE_UCHAR,
self->color_siting, NULL);
@@ -3963,11 +5855,176 @@ mxf_metadata_cdci_picture_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_cdci_picture_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataCDCIPictureEssenceDescriptor *self =
+ MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_cdci_picture_essence_descriptor_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 component_depth_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x0A, 0x00, 0x00, 0x00
+ };
+ static const guint8 horizontal_subsampling_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x05, 0x00, 0x00, 0x00
+ };
+ static const guint8 vertical_subsampling_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x01, 0x10, 0x00, 0x00, 0x00
+ };
+ static const guint8 color_siting_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00
+ };
+ static const guint8 reversed_byte_order_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x03, 0x01, 0x02, 0x01, 0x0A, 0x00, 0x00, 0x00
+ };
+ static const guint8 padding_bits_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00
+ };
+ static const guint8 alpha_sample_depth_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x07, 0x00, 0x00, 0x00
+ };
+ static const guint8 black_ref_level_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00
+ };
+ static const guint8 white_ref_level_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x03, 0x04, 0x00, 0x00, 0x00
+ };
+ static const guint8 color_range_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00
+ };
+
+ if (self->component_depth) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &component_depth_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->component_depth);
+ mxf_primer_pack_add_mapping (primer, 0x3301, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->horizontal_subsampling) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &horizontal_subsampling_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->horizontal_subsampling);
+ mxf_primer_pack_add_mapping (primer, 0x3302, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->vertical_subsampling) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &vertical_subsampling_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->vertical_subsampling);
+ mxf_primer_pack_add_mapping (primer, 0x3308, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->color_siting != 0xff) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &color_siting_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->color_siting);
+ mxf_primer_pack_add_mapping (primer, 0x3303, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->reversed_byte_order) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &reversed_byte_order_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->reversed_byte_order) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0x330b, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->padding_bits) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &padding_bits_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->padding_bits);
+ mxf_primer_pack_add_mapping (primer, 0x3307, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->alpha_sample_depth) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &alpha_sample_depth_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->alpha_sample_depth);
+ mxf_primer_pack_add_mapping (primer, 0x3309, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->black_ref_level) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &black_ref_level_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->black_ref_level);
+ mxf_primer_pack_add_mapping (primer, 0x3304, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->white_ref_level) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &white_ref_level_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->white_ref_level);
+ mxf_primer_pack_add_mapping (primer, 0x3305, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->color_range) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &color_range_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->color_range);
+ mxf_primer_pack_add_mapping (primer, 0x3306, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_cdci_picture_essence_descriptor_init
(MXFMetadataCDCIPictureEssenceDescriptor * self)
{
-
+ self->color_siting = 0xff;
}
static void
@@ -3982,6 +6039,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (CDCI_PICTURE_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_cdci_picture_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_cdci_picture_essence_descriptor_write_tags;
metadata_class->type = 0x0128;
}
@@ -4138,6 +6197,112 @@ mxf_metadata_rgba_picture_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_rgba_picture_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataRGBAPictureEssenceDescriptor *self =
+ MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_rgba_picture_essence_descriptor_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 component_max_ref_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0B, 0x00, 0x00, 0x00
+ };
+ static const guint8 component_min_ref_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0C, 0x00, 0x00, 0x00
+ };
+ static const guint8 alpha_max_ref_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0D, 0x00, 0x00, 0x00
+ };
+ static const guint8 alpha_min_ref_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0E, 0x00, 0x00, 0x00
+ };
+ static const guint8 scanning_direction_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00
+ };
+ static const guint8 pixel_layout_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x06, 0x00, 0x00, 0x00
+ };
+
+ if (self->component_max_ref != 255) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &component_max_ref_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->component_max_ref);
+ mxf_primer_pack_add_mapping (primer, 0x3406, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->component_min_ref) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &component_min_ref_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->component_min_ref);
+ mxf_primer_pack_add_mapping (primer, 0x3407, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->alpha_max_ref != 255) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &alpha_max_ref_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->alpha_max_ref);
+ mxf_primer_pack_add_mapping (primer, 0x3408, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->alpha_min_ref) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &alpha_min_ref_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->alpha_min_ref);
+ mxf_primer_pack_add_mapping (primer, 0x3409, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->scanning_direction) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &scanning_direction_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->scanning_direction);
+ mxf_primer_pack_add_mapping (primer, 0x3405, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->pixel_layout) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &pixel_layout_ul, 16);
+ t->size = 2 * self->n_pixel_layout + 2;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, self->pixel_layout, self->n_pixel_layout * 2);
+ mxf_primer_pack_add_mapping (primer, 0x3401, &t->key);
+ ret = g_list_prepend (ret, t);
+
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_rgba_picture_essence_descriptor_init
(MXFMetadataRGBAPictureEssenceDescriptor * self)
@@ -4161,6 +6326,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (RGBA_PICTURE_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_rgba_picture_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_rgba_picture_essence_descriptor_write_tags;
metadata_class->type = 0x0129;
}
@@ -4227,6 +6394,36 @@ mxf_metadata_generic_data_essence_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_generic_data_essence_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataGenericDataEssenceDescriptor *self =
+ MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_generic_data_essence_descriptor_parent_class)->write_tags
+ (m, primer);
+ MXFLocalTag *t;
+ static const guint8 data_essence_coding_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x03,
+ 0x04, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (!mxf_ul_is_zero (&self->data_essence_coding)) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &data_essence_coding_ul, 16);
+ t->size = 16;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ memcpy (t->data, &self->data_essence_coding, 16);
+ mxf_primer_pack_add_mapping (primer, 0x3e01, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_generic_data_essence_descriptor_init
(MXFMetadataGenericDataEssenceDescriptor * self)
@@ -4246,6 +6443,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (GENERIC_DATA_ESSENCE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_generic_data_essence_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_generic_data_essence_descriptor_write_tags;
metadata_class->type = 0x0143;
}
@@ -4391,6 +6590,44 @@ mxf_metadata_multiple_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_multiple_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataMultipleDescriptor *self = MXF_METADATA_MULTIPLE_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_multiple_descriptor_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 sub_descriptors_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x0B, 0x00, 0x00
+ };
+
+ if (self->sub_descriptors) {
+ guint i;
+
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &sub_descriptors_ul, 16);
+ t->size = 8 + 16 * self->n_sub_descriptors;
+ t->data = g_slice_alloc0 (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->n_sub_descriptors);
+ GST_WRITE_UINT32_BE (t->data + 4, 16);
+ for (i = 0; i < self->n_sub_descriptors; i++) {
+ if (!self->sub_descriptors[i])
+ continue;
+
+ memcpy (t->data + 8 + 16 * i,
+ &MXF_METADATA_BASE (self->sub_descriptors[i])->instance_uid, 16);
+ }
+ mxf_primer_pack_add_mapping (primer, 0x3f01, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_multiple_descriptor_init (MXFMetadataMultipleDescriptor * self)
{
@@ -4411,6 +6648,7 @@ mxf_metadata_multiple_descriptor_class_init (MXFMetadataMultipleDescriptorClass
metadata_base_class->name_quark = MXF_QUARK (MULTIPLE_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_multiple_descriptor_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_multiple_descriptor_write_tags;
metadata_class->type = 0x0144;
}
@@ -4480,6 +6718,31 @@ mxf_metadata_text_locator_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_text_locator_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataTextLocator *self = MXF_METADATA_TEXT_LOCATOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_text_locator_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 locator_name_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00
+ };
+
+ if (self->locator_name) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &locator_name_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->locator_name, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x4101, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_text_locator_init (MXFMetadataTextLocator * self)
{
@@ -4497,6 +6760,7 @@ mxf_metadata_text_locator_class_init (MXFMetadataTextLocatorClass * klass)
metadata_base_class->handle_tag = mxf_metadata_text_locator_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (TEXT_LOCATOR);
metadata_base_class->to_structure = mxf_metadata_text_locator_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_text_locator_write_tags;
metadata_class->type = 0x0133;
}
@@ -4553,6 +6817,31 @@ mxf_metadata_network_locator_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_network_locator_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataNetworkLocator *self = MXF_METADATA_NETWORK_LOCATOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_network_locator_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+ static const guint8 url_string_ul[] = {
+ 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00
+ };
+
+ if (self->url_string) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &url_string_ul, 16);
+ t->data = mxf_utf8_to_utf16 (self->url_string, &t->size);
+ mxf_primer_pack_add_mapping (primer, 0x4001, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_network_locator_init (MXFMetadataNetworkLocator * self)
{
@@ -4569,6 +6858,7 @@ mxf_metadata_network_locator_class_init (MXFMetadataNetworkLocatorClass * klass)
metadata_base_class->handle_tag = mxf_metadata_network_locator_handle_tag;
metadata_base_class->name_quark = MXF_QUARK (NETWORK_LOCATOR);
metadata_base_class->to_structure = mxf_metadata_network_locator_to_structure;
+ metadata_base_class->write_tags = mxf_metadata_network_locator_write_tags;
metadata_class->type = 0x0133;
}
diff --git a/gst/mxf/mxfmetadata.h b/gst/mxf/mxfmetadata.h
index 635c6e02..bbdbc62f 100644
--- a/gst/mxf/mxfmetadata.h
+++ b/gst/mxf/mxfmetadata.h
@@ -386,6 +386,7 @@ struct _MXFMetadataBaseClass {
gboolean (*handle_tag) (MXFMetadataBase *self, MXFPrimerPack *primer, guint16 tag, const guint8 *tag_data, guint tag_size);
gboolean (*resolve) (MXFMetadataBase *self, GHashTable *metadata);
GstStructure * (*to_structure) (MXFMetadataBase *self);
+ GList * (*write_tags) (MXFMetadataBase *self, MXFPrimerPack *primer);
GQuark name_quark;
};
@@ -751,15 +752,20 @@ struct _MXFDescriptiveMetadataFrameworkInterface {
gboolean mxf_metadata_base_parse (MXFMetadataBase *self, MXFPrimerPack *primer, const guint8 *data, guint size);
gboolean mxf_metadata_base_resolve (MXFMetadataBase *self, GHashTable *metadata);
GstStructure * mxf_metadata_base_to_structure (MXFMetadataBase *self);
+GstBuffer * mxf_metadata_base_to_buffer (MXFMetadataBase *self, MXFPrimerPack *primer);
MXFMetadata *mxf_metadata_new (guint16 type, MXFPrimerPack *primer, guint64 offset, const guint8 *data, guint size);
void mxf_metadata_register (GType type);
void mxf_metadata_init_types (void);
MXFMetadataTrackType mxf_metadata_track_identifier_parse (const MXFUL * track_identifier);
+const MXFUL * mxf_metadata_track_identifier_get (MXFMetadataTrackType type);
void mxf_metadata_generic_picture_essence_descriptor_set_caps (MXFMetadataGenericPictureEssenceDescriptor * self, GstCaps * caps);
+gboolean mxf_metadata_generic_picture_essence_descriptor_from_caps (MXFMetadataGenericPictureEssenceDescriptor * self, GstCaps * caps);
+
void mxf_metadata_generic_sound_essence_descriptor_set_caps (MXFMetadataGenericSoundEssenceDescriptor * self, GstCaps * caps);
+gboolean mxf_metadata_generic_sound_essence_descriptor_from_caps (MXFMetadataGenericSoundEssenceDescriptor * self, GstCaps * caps);
void mxf_descriptive_metadata_register (guint8 scheme, GType *types);
MXFDescriptiveMetadata * mxf_descriptive_metadata_new (guint8 scheme, guint32 type, MXFPrimerPack * primer, guint64 offset, const guint8 * data, guint size);
diff --git a/gst/mxf/mxfmpeg.c b/gst/mxf/mxfmpeg.c
index 996199af..868aeb80 100644
--- a/gst/mxf/mxfmpeg.c
+++ b/gst/mxf/mxfmpeg.c
@@ -33,10 +33,12 @@
#endif
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <string.h>
#include "mxfmpeg.h"
#include "mxfquark.h"
+#include "mxfwrite.h"
#include <gst/base/gstbytereader.h>
@@ -243,10 +245,133 @@ mxf_metadata_mpeg_video_descriptor_to_structure (MXFMetadataBase * m)
return ret;
}
+static GList *
+mxf_metadata_mpeg_video_descriptor_write_tags (MXFMetadataBase * m,
+ MXFPrimerPack * primer)
+{
+ MXFMetadataMPEGVideoDescriptor *self = MXF_METADATA_MPEG_VIDEO_DESCRIPTOR (m);
+ GList *ret =
+ MXF_METADATA_BASE_CLASS
+ (mxf_metadata_mpeg_video_descriptor_parent_class)->write_tags (m, primer);
+ MXFLocalTag *t;
+
+ if (self->single_sequence != -1) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_single_sequence_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->single_sequence) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->const_b_frames) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_constant_b_frames_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->const_b_frames) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->coded_content_type) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_coded_content_type_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->coded_content_type);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->low_delay) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_low_delay_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->low_delay) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->closed_gop) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_closed_gop_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->closed_gop) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->identical_gop) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_identical_gop_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, (self->identical_gop) ? 1 : 0);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->max_gop) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_identical_gop_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->max_gop);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->b_picture_count) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_b_picture_count_ul, 16);
+ t->size = 2;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT16_BE (t->data, self->b_picture_count);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->bitrate) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_bitrate_ul, 16);
+ t->size = 4;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT32_BE (t->data, self->bitrate);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ if (self->profile_and_level) {
+ t = g_slice_new0 (MXFLocalTag);
+ memcpy (&t->key, &_profile_and_level_ul, 16);
+ t->size = 1;
+ t->data = g_slice_alloc (t->size);
+ t->g_slice = TRUE;
+ GST_WRITE_UINT8 (t->data, self->profile_and_level);
+ mxf_primer_pack_add_mapping (primer, 0, &t->key);
+ ret = g_list_prepend (ret, t);
+ }
+
+ return ret;
+}
+
static void
mxf_metadata_mpeg_video_descriptor_init (MXFMetadataMPEGVideoDescriptor * self)
{
-
+ self->single_sequence = -1;
}
static void
@@ -261,6 +386,8 @@ static void
metadata_base_class->name_quark = MXF_QUARK (MPEG_VIDEO_DESCRIPTOR);
metadata_base_class->to_structure =
mxf_metadata_mpeg_video_descriptor_to_structure;
+ metadata_base_class->write_tags =
+ mxf_metadata_mpeg_video_descriptor_write_tags;
metadata_class->type = 0x0151;
}
@@ -380,8 +507,6 @@ mxf_mpeg_is_mpeg4_keyframe (GstBuffer * buffer)
}
}
- g_assert_not_reached ();
-
return FALSE;
}
@@ -577,7 +702,7 @@ mxf_mpeg_es_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
codec_name = "MPEG-1 Audio";
} else if (mxf_ul_is_equal (&s->sound_essence_compression,
&sound_essence_compression_ac3)) {
- caps = gst_caps_new_simple ("audio/ac3", NULL);
+ caps = gst_caps_new_simple ("audio/x-ac3", NULL);
codec_name = "AC3 Audio";
} else if (mxf_ul_is_equal (&s->sound_essence_compression,
&sound_essence_compression_mpeg1_layer1)) {
@@ -736,9 +861,431 @@ static const MXFEssenceElementHandler mxf_mpeg_essence_element_handler = {
mxf_mpeg_create_caps
};
+typedef struct
+{
+ guint spf;
+ guint rate;
+} MPEGAudioMappingData;
+
+static GstFlowReturn
+mxf_mpeg_audio_write_func (GstBuffer * buffer, GstCaps * caps,
+ gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf,
+ gboolean flush)
+{
+ *outbuf = buffer;
+ return GST_FLOW_OK;
+}
+
+static const guint8 mpeg_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x01, 0x01
+};
+
+static MXFMetadataFileDescriptor *
+mxf_mpeg_audio_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataGenericSoundEssenceDescriptor *ret;
+ GstStructure *s;
+ MPEGAudioMappingData *md = g_new0 (MPEGAudioMappingData, 1);
+ gint rate;
+
+ md->spf = -1;
+ *mapping_data = md;
+
+ ret = (MXFMetadataGenericSoundEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR);
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "audio/mpeg") == 0) {
+ gint mpegversion;
+
+ if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ if (mpegversion == 1) {
+ gint layer = 0;
+ gint mpegaudioversion = 0;
+
+ gst_structure_get_int (s, "layer", &layer);
+ gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion);
+
+ if (mpegaudioversion == 1 && layer == 1)
+ memcpy (&ret->sound_essence_compression,
+ &sound_essence_compression_mpeg1_layer1, 16);
+ else if (mpegaudioversion == 1 && layer == 2)
+ memcpy (&ret->sound_essence_compression,
+ &sound_essence_compression_mpeg1_layer12, 16);
+ else if (mpegaudioversion == 2 && layer == 1)
+ memcpy (&ret->sound_essence_compression,
+ &sound_essence_compression_mpeg2_layer1, 16);
+
+ if (layer == 1)
+ md->spf = 384;
+ else if (layer == 2 || mpegversion == 1)
+ md->spf = 1152;
+ else
+ md->spf = 576; /* MPEG-2 or 2.5 */
+
+ /* Otherwise all 0x00, must be some kind of mpeg1 audio */
+ } else if (mpegversion == 2) {
+ memcpy (&ret->sound_essence_compression, &sound_essence_compression_aac,
+ 16);
+ md->spf = 1024; /* FIXME: is this correct? */
+ }
+ } else if (strcmp (gst_structure_get_name (s), "audio/x-ac3") == 0) {
+ memcpy (&ret->sound_essence_compression, &sound_essence_compression_ac3,
+ 16);
+ md->spf = 256; /* FIXME: is this correct? */
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (!gst_structure_get_int (s, "rate", &rate)) {
+ GST_ERROR ("Invalid rate");
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+ md->rate = rate;
+
+ memcpy (&ret->parent.essence_container, &mpeg_essence_container_ul, 16);
+
+ if (!mxf_metadata_generic_sound_essence_descriptor_from_caps (ret, caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_mpeg_audio_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_mpeg_audio_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_mpeg_audio_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ MPEGAudioMappingData *md = mapping_data;
+
+ edit_rate->n = md->rate;
+ edit_rate->d = md->spf;
+}
+
+static guint32
+mxf_mpeg_audio_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x16 << 24) | (0x05 << 8);
+}
+
+static MXFEssenceElementWriter mxf_mpeg_audio_essence_element_writer = {
+ mxf_mpeg_audio_get_descriptor,
+ mxf_mpeg_audio_update_descriptor,
+ mxf_mpeg_audio_get_edit_rate,
+ mxf_mpeg_audio_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
+#define MPEG_AUDIO_CAPS \
+ "audio/mpeg, " \
+ "mpegversion = (int) 1, " \
+ "layer = (int) [ 1, 3 ], " \
+ "rate = (int) [ 8000, 48000 ], " \
+ "channels = (int) [ 1, 2 ], " \
+ "parsed = (boolean) TRUE; " \
+ "audio/x-ac3, " \
+ "rate = (int) [ 4000, 96000 ], " \
+ "channels = (int) [ 1, 6 ]; " \
+ "audio/mpeg, " \
+ "mpegversion = (int) 2, " \
+ "rate = (int) [ 8000, 96000 ], " \
+ "channels = (int) [ 1, 8 ]"
+
+/* See ISO/IEC 13818-2 for MPEG ES format */
+gboolean
+mxf_mpeg_is_mpeg2_frame (GstBuffer * buffer)
+{
+ GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
+ guint32 tmp;
+
+ while (gst_byte_reader_get_remaining (&reader) > 3) {
+ if (gst_byte_reader_peek_uint24_be (&reader, &tmp) && tmp == 0x000001) {
+ guint8 type;
+
+ /* Found sync code */
+ gst_byte_reader_skip (&reader, 3);
+
+ if (!gst_byte_reader_get_uint8 (&reader, &type))
+ break;
+
+ /* PICTURE */
+ if (type == 0x00) {
+ return TRUE;
+ }
+ } else {
+ gst_byte_reader_skip (&reader, 1);
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+mxf_mpeg_is_mpeg4_frame (GstBuffer * buffer)
+{
+ GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
+ guint32 tmp;
+
+ while (gst_byte_reader_get_remaining (&reader) > 3) {
+ if (gst_byte_reader_peek_uint24_be (&reader, &tmp) && tmp == 0x000001) {
+ guint8 type;
+
+ /* Found sync code */
+ gst_byte_reader_skip (&reader, 3);
+
+ if (!gst_byte_reader_get_uint8 (&reader, &type))
+ break;
+
+ /* PICTURE */
+ if (type == 0xb6) {
+ return TRUE;
+ }
+ } else {
+ gst_byte_reader_skip (&reader, 1);
+ }
+ }
+
+ return FALSE;
+}
+
+static GstFlowReturn
+mxf_mpeg_video_write_func (GstBuffer * buffer, GstCaps * caps,
+ gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf,
+ gboolean flush)
+{
+ MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_OTHER;
+
+ if (mapping_data)
+ type = *((MXFMPEGEssenceType *) mapping_data);
+
+ if (type == MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2) {
+ if (buffer && !mxf_mpeg_is_mpeg2_frame (buffer)) {
+ gst_adapter_push (adapter, buffer);
+ *outbuf = NULL;
+ return GST_FLOW_OK;
+ } else if (buffer || gst_adapter_available (adapter)) {
+ guint av = gst_adapter_available (adapter);
+ GstBuffer *ret;
+
+ if (buffer)
+ ret = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) + av);
+ else
+ ret = gst_buffer_new_and_alloc (av);
+
+ if (av) {
+ GstBuffer *tmp = gst_adapter_take_buffer (adapter, av);
+ memcpy (GST_BUFFER_DATA (ret), GST_BUFFER_DATA (tmp), av);
+ gst_buffer_unref (tmp);
+ }
+
+ if (buffer) {
+ memcpy (GST_BUFFER_DATA (ret) + av, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+ gst_buffer_unref (buffer);
+ }
+ *outbuf = ret;
+ return GST_FLOW_OK;
+ }
+ } else if (type == MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4) {
+ if (buffer && !mxf_mpeg_is_mpeg4_frame (buffer)) {
+ gst_adapter_push (adapter, buffer);
+ *outbuf = NULL;
+ return GST_FLOW_OK;
+ } else if (buffer || gst_adapter_available (adapter)) {
+ guint av = gst_adapter_available (adapter);
+ GstBuffer *ret;
+
+ if (buffer)
+ ret = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) + av);
+ else
+ ret = gst_buffer_new_and_alloc (av);
+
+ if (av) {
+ GstBuffer *tmp = gst_adapter_take_buffer (adapter, av);
+ memcpy (GST_BUFFER_DATA (ret), GST_BUFFER_DATA (tmp), av);
+ gst_buffer_unref (tmp);
+ }
+
+ if (buffer) {
+ memcpy (GST_BUFFER_DATA (ret) + av, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+ gst_buffer_unref (buffer);
+ }
+ *outbuf = ret;
+ return GST_FLOW_OK;
+ }
+ }
+
+ *outbuf = buffer;
+ return GST_FLOW_OK;
+}
+
+static const guint8 mpeg_video_picture_essence_compression_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x00,
+ 0x04, 0x01, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00
+};
+
+static MXFMetadataFileDescriptor *
+mxf_mpeg_video_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataMPEGVideoDescriptor *ret;
+ GstStructure *s;
+
+ ret = (MXFMetadataMPEGVideoDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_MPEG_VIDEO_DESCRIPTOR);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ memcpy (&ret->parent.parent.parent.essence_container,
+ &mpeg_essence_container_ul, 16);
+ memcpy (&ret->parent.parent.picture_essence_coding,
+ &mpeg_video_picture_essence_compression_ul, 16);
+ if (strcmp (gst_structure_get_name (s), "video/mpeg") == 0) {
+ gint mpegversion;
+
+ if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ if (mpegversion == 1) {
+ MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2;
+
+ *mapping_data = g_new0 (MXFMPEGEssenceType, 1);
+ memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType));
+ ret->parent.parent.picture_essence_coding.u[13] = 0x10;
+ } else if (mpegversion == 2) {
+ MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2;
+
+ *mapping_data = g_new0 (MXFMPEGEssenceType, 1);
+ memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType));
+ ret->parent.parent.picture_essence_coding.u[13] = 0x01;
+ } else {
+ const GValue *v;
+ const GstBuffer *codec_data;
+ MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4;
+
+ *mapping_data = g_new0 (MXFMPEGEssenceType, 1);
+ memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType));
+
+ ret->parent.parent.picture_essence_coding.u[13] = 0x20;
+ if ((v = gst_structure_get_value (s, "codec_data"))) {
+ MXFLocalTag *t = g_slice_new0 (MXFLocalTag);
+ codec_data = gst_value_get_buffer (v);
+ t->size = GST_BUFFER_SIZE (codec_data);
+ t->data = g_memdup (GST_BUFFER_DATA (codec_data), t->size);
+ memcpy (&t->key, &sony_mpeg4_extradata, 16);
+ mxf_local_tag_insert (t, &MXF_METADATA_BASE (ret)->other_tags);
+ }
+ }
+ } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) {
+ MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_AVC;
+
+ *mapping_data = g_new0 (MXFMPEGEssenceType, 1);
+ memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType));
+ ret->parent.parent.picture_essence_coding.u[13] = 0x30;
+ } else {
+ g_assert_not_reached ();
+ }
+
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->
+ parent.parent, caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_mpeg_video_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_mpeg_video_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_mpeg_video_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ (*edit_rate).n = a->sample_rate.n;
+ (*edit_rate).d = a->sample_rate.d;
+}
+
+static guint32
+mxf_mpeg_video_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x15 << 24) | (0x05 << 8);
+}
+
+static MXFEssenceElementWriter mxf_mpeg_video_essence_element_writer = {
+ mxf_mpeg_video_get_descriptor,
+ mxf_mpeg_video_update_descriptor,
+ mxf_mpeg_video_get_edit_rate,
+ mxf_mpeg_video_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
+#define MPEG_VIDEO_CAPS \
+"video/mpeg, " \
+"mpegversion = (int) { 1, 2, 4 }, " \
+"systemstream = (boolean) FALSE, " \
+"width = " GST_VIDEO_SIZE_RANGE ", " \
+"height = " GST_VIDEO_SIZE_RANGE ", " \
+"framerate = " GST_VIDEO_FPS_RANGE "; " \
+"video/x-h264, " \
+"width = " GST_VIDEO_SIZE_RANGE ", " \
+"height = " GST_VIDEO_SIZE_RANGE ", " \
+"framerate = " GST_VIDEO_FPS_RANGE
+
void
mxf_mpeg_init (void)
{
mxf_metadata_register (MXF_TYPE_METADATA_MPEG_VIDEO_DESCRIPTOR);
mxf_essence_element_handler_register (&mxf_mpeg_essence_element_handler);
+
+ mxf_mpeg_audio_essence_element_writer.pad_template =
+ gst_pad_template_new ("mpeg_audio_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string (MPEG_AUDIO_CAPS));
+ memcpy (&mxf_mpeg_audio_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_SOUND_ESSENCE), 16);
+ mxf_essence_element_writer_register (&mxf_mpeg_audio_essence_element_writer);
+
+ mxf_mpeg_video_essence_element_writer.pad_template =
+ gst_pad_template_new ("mpeg_video_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string (MPEG_VIDEO_CAPS));
+ memcpy (&mxf_mpeg_video_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_PICTURE_ESSENCE),
+ 16);
+ mxf_essence_element_writer_register (&mxf_mpeg_video_essence_element_writer);
+
}
diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c
new file mode 100644
index 00000000..0052d2e1
--- /dev/null
+++ b/gst/mxf/mxfmux.c
@@ -0,0 +1,1429 @@
+/* GStreamer
+ * Copyright (C) 2009 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "mxfmux.h"
+
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (mxfmux_debug);
+#define GST_CAT_DEFAULT mxfmux_debug
+
+static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/mxf")
+ );
+
+enum
+{
+ PROP_0
+};
+
+GST_BOILERPLATE (GstMXFMux, gst_mxf_mux, GstElement, GST_TYPE_ELEMENT);
+
+static void gst_mxf_mux_finalize (GObject * object);
+static void gst_mxf_mux_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_mxf_mux_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_mxf_mux_collected (GstCollectPads * pads,
+ gpointer user_data);
+
+static gboolean gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event);
+static GstPad *gst_mxf_mux_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name);
+static void gst_mxf_mux_release_pad (GstElement * element, GstPad * pad);
+
+static GstStateChangeReturn
+gst_mxf_mux_change_state (GstElement * element, GstStateChange transition);
+
+static void gst_mxf_mux_reset (GstMXFMux * mux);
+
+static GstFlowReturn
+gst_mxf_mux_push (GstMXFMux * mux, GstBuffer * buf)
+{
+ guint size = GST_BUFFER_SIZE (buf);
+ GstFlowReturn ret;
+
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
+ ret = gst_pad_push (mux->srcpad, buf);
+ mux->offset += size;
+
+ return ret;
+}
+
+static void
+gst_mxf_mux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ const GstPadTemplate **p;
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+
+ p = mxf_essence_element_writer_get_pad_templates ();
+ while (p && *p) {
+ gst_element_class_add_pad_template (element_class,
+ (GstPadTemplate *) gst_object_ref (GST_OBJECT (*p)));
+ p++;
+ }
+
+ gst_element_class_set_details_simple (element_class, "MXF muxer",
+ "Codec/Muxer",
+ "Muxes video/audio streams into a MXF stream",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void
+gst_mxf_mux_class_init (GstMXFMuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ GST_DEBUG_CATEGORY_INIT (mxfmux_debug, "mxfmux", 0, "MXF muxer");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_mxf_mux_finalize;
+ gobject_class->set_property = gst_mxf_mux_set_property;
+ gobject_class->get_property = gst_mxf_mux_get_property;
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_mxf_mux_change_state);
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_mxf_mux_request_new_pad);
+ gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_mxf_mux_release_pad);
+}
+
+static void
+gst_mxf_mux_init (GstMXFMux * mux, GstMXFMuxClass * g_class)
+{
+ GstCaps *caps;
+
+ mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
+ gst_pad_set_event_function (mux->srcpad, gst_mxf_mux_handle_src_event);
+ caps = gst_caps_new_simple ("application/mxf", NULL);
+ gst_pad_set_caps (mux->srcpad, caps);
+ gst_caps_unref (caps);
+ gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
+
+ mux->collect = gst_collect_pads_new ();
+ gst_collect_pads_set_function (mux->collect,
+ (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_mxf_mux_collected), mux);
+
+ gst_mxf_mux_reset (mux);
+}
+
+static void
+gst_mxf_mux_finalize (GObject * object)
+{
+ GstMXFMux *mux = GST_MXF_MUX (object);
+
+ gst_mxf_mux_reset (mux);
+
+ if (mux->metadata) {
+ g_hash_table_destroy (mux->metadata);
+ mux->metadata = NULL;
+ }
+
+ gst_object_unref (mux->collect);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_mxf_mux_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ //GstMXFMux *mux = GST_MXF_MUX (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_mxf_mux_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ //GstMXFMux *mux = GST_MXF_MUX (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_mxf_mux_reset (GstMXFMux * mux)
+{
+ GSList *sl;
+
+ while ((sl = mux->collect->data) != NULL) {
+ GstMXFMuxPad *cpad = (GstMXFMuxPad *) sl->data;
+
+ gst_object_unref (cpad->adapter);
+ g_free (cpad->mapping_data);
+
+ gst_collect_pads_remove_pad (mux->collect, cpad->collect.pad);
+ }
+
+ mux->state = GST_MXF_MUX_STATE_HEADER;
+ mux->n_pads = 0;
+
+ if (mux->metadata) {
+ g_hash_table_destroy (mux->metadata);
+ mux->preface = NULL;
+ }
+ mux->metadata = mxf_metadata_hash_table_new ();
+
+ mxf_partition_pack_reset (&mux->partition);
+ mxf_primer_pack_reset (&mux->primer);
+ memset (&mux->min_edit_rate, 0, sizeof (MXFFraction));
+ mux->last_gc_timestamp = 0;
+ mux->last_gc_position = 0;
+ mux->offset = 0;
+}
+
+static gboolean
+gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event)
+{
+ GstEventType type;
+
+ type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
+
+ switch (type) {
+ case GST_EVENT_SEEK:
+ /* disable seeking for now */
+ return FALSE;
+ default:
+ break;
+ }
+
+ return gst_pad_event_default (pad, event);
+}
+
+static gboolean
+gst_mxf_mux_handle_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ /* TODO: do something with the tags */
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ /* We don't support NEWSEGMENT events */
+ ret = FALSE;
+ gst_event_unref (event);
+ break;
+ default:
+ break;
+ }
+
+ /* now GstCollectPads can take care of the rest, e.g. EOS */
+ if (ret)
+ ret = mux->collect_event (pad, event);
+ gst_object_unref (mux);
+
+ return ret;
+}
+
+static gboolean
+gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
+ GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
+ gboolean ret = TRUE;
+ MXFUL d_instance_uid = { {0,} };
+ MXFMetadataFileDescriptor *old_descriptor = cpad->descriptor;
+
+ GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
+
+ if (old_descriptor) {
+ memcpy (&d_instance_uid, &MXF_METADATA_BASE (old_descriptor)->instance_uid,
+ 16);
+ cpad->descriptor = NULL;
+ g_free (cpad->mapping_data);
+ cpad->mapping_data = NULL;
+ }
+
+ cpad->descriptor =
+ cpad->writer->get_descriptor (gst_pad_get_pad_template (pad), caps,
+ &cpad->write_func, &cpad->mapping_data);
+
+ if (!cpad->descriptor) {
+ GST_ERROR_OBJECT (mux,
+ "Couldn't get descriptor for pad '%s' with caps %" GST_PTR_FORMAT,
+ GST_PAD_NAME (pad), caps);
+ gst_object_unref (mux);
+ return FALSE;
+ }
+
+ if (mxf_ul_is_zero (&d_instance_uid))
+ mxf_ul_set (&d_instance_uid, mux->metadata);
+
+ memcpy (&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, &d_instance_uid,
+ 16);
+
+ g_hash_table_replace (mux->metadata,
+ &MXF_METADATA_BASE (cpad->descriptor)->instance_uid, cpad->descriptor);
+
+ if (old_descriptor) {
+ if (mux->preface && mux->preface->content_storage &&
+ mux->preface->content_storage->packages) {
+ guint i, j;
+
+ for (i = 0; i < mux->preface->content_storage->n_packages; i++) {
+ MXFMetadataSourcePackage *package;
+
+ if (!MXF_IS_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
+ packages[i]))
+ continue;
+
+ package =
+ MXF_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
+ packages[i]);
+
+ if (!package->descriptor)
+ continue;
+
+ if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor)) {
+ MXFMetadataMultipleDescriptor *tmp =
+ MXF_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor);
+
+ for (j = 0; j < tmp->n_sub_descriptors; j++) {
+ if (tmp->sub_descriptors[j] ==
+ MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
+ tmp->sub_descriptors[j] =
+ MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
+ memcpy (&tmp->sub_descriptors_uids[j], &d_instance_uid, 16);
+ }
+ }
+ } else if (package->descriptor ==
+ MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
+ package->descriptor =
+ MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
+ memcpy (&package->descriptor_uid, &d_instance_uid, 16);
+ }
+ }
+ }
+ }
+
+ gst_object_unref (mux);
+
+ return ret;
+}
+
+static GstPad *
+gst_mxf_mux_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * pad_name)
+{
+ GstMXFMux *mux = GST_MXF_MUX (element);
+ GstMXFMuxPad *cpad;
+ GstPad *pad = NULL;
+ guint pad_number;
+ gchar *name = NULL;
+ const MXFEssenceElementWriter *writer;
+
+ if (mux->state != GST_MXF_MUX_STATE_HEADER) {
+ GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
+ return NULL;
+ }
+
+ writer = mxf_essence_element_writer_find (templ);
+ if (!writer) {
+ GST_ERROR_OBJECT (mux, "Not our template");
+ return NULL;
+ }
+
+ pad_number = g_atomic_int_exchange_and_add ((gint *) & mux->n_pads, 1);
+ name = g_strdup_printf (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), pad_number);
+
+ GST_DEBUG_OBJECT (mux, "Creating pad '%s'", name);
+ pad = gst_pad_new_from_template (templ, name);
+ g_free (name);
+ cpad = (GstMXFMuxPad *)
+ gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstMXFMuxPad));
+ cpad->last_timestamp = 0;
+ cpad->adapter = gst_adapter_new ();
+ cpad->writer = writer;
+
+ /* FIXME: hacked way to override/extend the event function of
+ * GstCollectPads; because it sets its own event function giving the
+ * element no access to events.
+ */
+ mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
+ gst_pad_set_event_function (pad,
+ GST_DEBUG_FUNCPTR (gst_mxf_mux_handle_sink_event));
+
+ gst_pad_set_setcaps_function (pad, gst_mxf_mux_setcaps);
+ gst_pad_use_fixed_caps (pad);
+ gst_pad_set_active (pad, TRUE);
+ gst_element_add_pad (element, pad);
+
+ return pad;
+}
+
+static void
+gst_mxf_mux_release_pad (GstElement * element, GstPad * pad)
+{
+ /*GstMXFMux *mux = GST_MXF_MUX (GST_PAD_PARENT (pad));
+ GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
+
+ gst_object_unref (cpad->adapter);
+ g_free (cpad->mapping_data);
+
+ gst_collect_pads_remove_pad (mux->collect, pad);
+ gst_element_remove_pad (element, pad); */
+}
+
+static GstFlowReturn
+gst_mxf_mux_create_metadata (GstMXFMux * mux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GSList *l;
+ GArray *tmp;
+
+ GST_DEBUG_OBJECT (mux, "Creating MXF metadata");
+
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+
+ if (!cpad || !cpad->descriptor || !GST_PAD_CAPS (cpad->collect.pad))
+ return GST_FLOW_ERROR;
+
+ if (cpad->writer->update_descriptor)
+ cpad->writer->update_descriptor (cpad->descriptor,
+ GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
+ cpad->collect.buffer);
+ }
+
+ /* Preface */
+ mux->preface =
+ (MXFMetadataPreface *) gst_mini_object_new (MXF_TYPE_METADATA_PREFACE);
+ mxf_ul_set (&MXF_METADATA_BASE (mux->preface)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
+
+ mxf_timestamp_set_now (&mux->preface->last_modified_date);
+ mux->preface->version = 258;
+ mux->preface->object_model_version = 1;
+
+ mxf_op_set_generalized (&mux->preface->operational_pattern, MXF_OP_1a, TRUE,
+ TRUE, FALSE);
+
+ tmp = g_array_new (FALSE, FALSE, sizeof (MXFUL));
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ guint i;
+ gboolean found = FALSE;
+
+ if (!cpad || !cpad->descriptor ||
+ mxf_ul_is_zero (&cpad->descriptor->essence_container))
+ return GST_FLOW_ERROR;
+
+ for (i = 0; i < tmp->len; i++) {
+ if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
+ &g_array_index (tmp, MXFUL, i))) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ g_array_append_val (tmp, cpad->descriptor->essence_container);
+ }
+ mux->preface->n_essence_containers = tmp->len;
+ mux->preface->essence_containers = (MXFUL *) g_array_free (tmp, FALSE);
+
+ /* This will later be used as UID for the material package */
+ mxf_ul_set (&mux->preface->primary_package_uid, mux->metadata);
+
+ /* Identifications */
+ {
+ MXFMetadataIdentification *identification;
+ static const guint8 gst_uid[] = {
+ 0xe5, 0xde, 0xcd, 0x04, 0x24, 0x90, 0x69, 0x18,
+ 0x8a, 0xc9, 0xb5, 0xd7, 0x02, 0x58, 0x46, 0x78
+ };
+ guint major, minor, micro, nano;
+
+ mux->preface->n_identifications = 1;
+ mux->preface->identifications = g_new0 (MXFMetadataIdentification *, 1);
+ identification = mux->preface->identifications[0] =
+ (MXFMetadataIdentification *)
+ gst_mini_object_new (MXF_TYPE_METADATA_IDENTIFICATION);
+
+ mxf_ul_set (&MXF_METADATA_BASE (identification)->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (identification)->instance_uid, identification);
+
+ mxf_ul_set (&identification->this_generation_uid, NULL);
+
+ identification->company_name = g_strdup ("GStreamer");
+ identification->product_name = g_strdup ("GStreamer Multimedia Framework");
+
+ gst_version (&major, &minor, &micro, &nano);
+ identification->product_version.major = major;
+ identification->product_version.minor = minor;
+ identification->product_version.patch = micro;
+ identification->product_version.build = nano;
+ identification->product_version.release =
+ (nano == 0) ? 1 : (nano == 1) ? 2 : 4;
+
+ identification->version_string =
+ g_strdup_printf ("%u.%u.%u.%u", major, minor, micro, nano);
+ memcpy (&identification->product_uid, &gst_uid, 16);
+
+ memcpy (&identification->modification_date,
+ &mux->preface->last_modified_date, sizeof (MXFTimestamp));
+ memcpy (&identification->toolkit_version, &identification->product_version,
+ sizeof (MXFProductVersion));
+
+#ifdef HAVE_SYS_UTSNAME_H
+ {
+ struct utsname sys_details;
+
+ if (uname (&sys_details) == 0) {
+ identification->platform = g_strdup_printf ("%s %s %s",
+ sys_details.sysname, sys_details.release, sys_details.machine);
+ }
+ }
+#endif
+
+#if defined(G_OS_WIN32)
+ if (identification->platform == NULL)
+ identification->platform = g_strdup ("Microsoft Windows");
+#elif defined(G_OS_BEOS)
+ if (identification->platform == NULL)
+ identification->platform = g_strdup ("BEOS");
+#elif defined(G_OS_UNIX)
+ if (identification->platform == NULL)
+ identification->platform = g_strdup ("Unix");
+#endif
+ }
+
+ /* Content storage */
+ {
+ MXFMetadataContentStorage *cstorage;
+ guint i;
+
+ cstorage = mux->preface->content_storage = (MXFMetadataContentStorage *)
+ gst_mini_object_new (MXF_TYPE_METADATA_CONTENT_STORAGE);
+ mxf_ul_set (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
+
+ cstorage->n_packages = 2;
+ cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
+
+ /* Source package */
+ {
+ MXFMetadataSourcePackage *p;
+
+ cstorage->packages[1] = (MXFMetadataGenericPackage *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_PACKAGE);
+ mxf_ul_set (&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
+ cstorage->packages[1]);
+ p = (MXFMetadataSourcePackage *) cstorage->packages[1];
+
+ mxf_umid_set (&p->parent.package_uid);
+ p->parent.name = g_strdup ("Source package");
+ memcpy (&p->parent.package_creation_date,
+ &mux->preface->last_modified_date, sizeof (MXFTimestamp));
+ memcpy (&p->parent.package_modified_date,
+ &mux->preface->last_modified_date, sizeof (MXFTimestamp));
+
+ p->parent.n_tracks = g_slist_length (mux->collect->data);
+ p->parent.tracks = g_new0 (MXFMetadataTrack *, p->parent.n_tracks);
+
+ if (p->parent.n_tracks > 1) {
+ MXFMetadataMultipleDescriptor *d;
+
+ p->descriptor = (MXFMetadataGenericDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR);
+ d = (MXFMetadataMultipleDescriptor *) p->descriptor;
+ d->n_sub_descriptors = p->parent.n_tracks;
+ d->sub_descriptors =
+ g_new0 (MXFMetadataGenericDescriptor *, p->parent.n_tracks);
+
+ mxf_ul_set (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (d)->instance_uid, d);
+ }
+
+ /* Tracks */
+ {
+ guint n = 0;
+
+ /* Essence tracks */
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ MXFMetadataTimelineTrack *track;
+ MXFMetadataSequence *sequence;
+ MXFMetadataSourceClip *clip;
+
+ p->parent.tracks[n] = (MXFMetadataTrack *)
+ gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
+ track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
+ mxf_ul_set (&MXF_METADATA_BASE (track)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (track)->instance_uid, track);
+
+ track->parent.track_id = n + 1;
+ track->parent.track_number =
+ cpad->writer->get_track_number_template (cpad->descriptor,
+ GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data);
+
+ cpad->writer->get_edit_rate (cpad->descriptor,
+ GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
+ cpad->collect.buffer, p, track, &track->edit_rate);
+
+ sequence = track->parent.sequence = (MXFMetadataSequence *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
+ mxf_ul_set (&MXF_METADATA_BASE (sequence)->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+
+ memcpy (&sequence->data_definition, &cpad->writer->data_definition,
+ 16);
+
+ sequence->n_structural_components = 1;
+ sequence->structural_components =
+ g_new0 (MXFMetadataStructuralComponent *, 1);
+
+ clip = (MXFMetadataSourceClip *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
+ sequence->structural_components[0] =
+ (MXFMetadataStructuralComponent *) clip;
+ mxf_ul_set (&MXF_METADATA_BASE (clip)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (clip)->instance_uid, clip);
+
+ memcpy (&clip->parent.data_definition, &sequence->data_definition,
+ 16);
+ clip->start_position = 0;
+
+ cpad->source_package = p;
+ cpad->source_track = track;
+ cpad->descriptor->linked_track_id = n + 1;
+ if (p->parent.n_tracks == 1) {
+ p->descriptor = (MXFMetadataGenericDescriptor *) cpad->descriptor;
+ } else {
+ MXF_METADATA_MULTIPLE_DESCRIPTOR (p->descriptor)->
+ sub_descriptors[n] =
+ (MXFMetadataGenericDescriptor *) cpad->descriptor;
+ }
+
+ n++;
+ }
+ }
+ }
+
+ /* Material package */
+ {
+ MXFMetadataMaterialPackage *p;
+ MXFFraction min_edit_rate = { 0, 0 };
+ gdouble min_edit_rate_d = G_MAXDOUBLE;
+
+ cstorage->packages[0] = (MXFMetadataGenericPackage *)
+ gst_mini_object_new (MXF_TYPE_METADATA_MATERIAL_PACKAGE);
+ memcpy (&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
+ &mux->preface->primary_package_uid, 16);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
+ cstorage->packages[0]);
+ p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
+
+ mxf_umid_set (&p->package_uid);
+ p->name = g_strdup ("Material package");
+ memcpy (&p->package_creation_date, &mux->preface->last_modified_date,
+ sizeof (MXFTimestamp));
+ memcpy (&p->package_modified_date, &mux->preface->last_modified_date,
+ sizeof (MXFTimestamp));
+
+ p->n_tracks = g_slist_length (mux->collect->data) + 1;
+ p->tracks = g_new0 (MXFMetadataTrack *, p->n_tracks);
+
+ /* Tracks */
+ {
+ guint n;
+
+ n = 1;
+ /* Essence tracks */
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ MXFMetadataSourcePackage *source_package;
+ MXFMetadataTimelineTrack *track, *source_track;
+ MXFMetadataSequence *sequence;
+ MXFMetadataSourceClip *clip;
+
+ source_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
+ source_track =
+ MXF_METADATA_TIMELINE_TRACK (source_package->parent.tracks[n -
+ 1]);
+
+ p->tracks[n] = (MXFMetadataTrack *)
+ gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
+ track = (MXFMetadataTimelineTrack *) p->tracks[n];
+ mxf_ul_set (&MXF_METADATA_BASE (track)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (track)->instance_uid, track);
+
+ track->parent.track_id = n + 1;
+ track->parent.track_number = 0;
+
+ cpad->writer->get_edit_rate (cpad->descriptor,
+ GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
+ cpad->collect.buffer, source_package, source_track,
+ &track->edit_rate);
+
+ if (track->edit_rate.n != source_track->edit_rate.n ||
+ track->edit_rate.d != source_track->edit_rate.d) {
+ memcpy (&source_track->edit_rate, &track->edit_rate,
+ sizeof (MXFFraction));
+ }
+
+ if (track->edit_rate.d <= 0 || track->edit_rate.n <= 0) {
+ GST_ERROR_OBJECT (mux, "Invalid edit rate");
+ return GST_FLOW_ERROR;
+ }
+
+ if (min_edit_rate_d >
+ ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d)) {
+ min_edit_rate_d =
+ ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d);
+ memcpy (&min_edit_rate, &track->edit_rate, sizeof (MXFFraction));
+ }
+
+ sequence = track->parent.sequence = (MXFMetadataSequence *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
+ mxf_ul_set (&MXF_METADATA_BASE (sequence)->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+
+ memcpy (&sequence->data_definition, &cpad->writer->data_definition,
+ 16);
+ sequence->n_structural_components = 1;
+ sequence->structural_components =
+ g_new0 (MXFMetadataStructuralComponent *, 1);
+
+ clip = (MXFMetadataSourceClip *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
+ sequence->structural_components[0] =
+ (MXFMetadataStructuralComponent *) clip;
+ mxf_ul_set (&MXF_METADATA_BASE (clip)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (clip)->instance_uid, clip);
+
+ memcpy (&clip->parent.data_definition, &sequence->data_definition,
+ 16);
+ clip->start_position = 0;
+
+ memcpy (&clip->source_package_id, &cstorage->packages[1]->package_uid,
+ 32);
+ clip->source_track_id = n;
+
+ n++;
+ }
+
+ n = 0;
+ /* Timecode track */
+ {
+ MXFMetadataTimelineTrack *track;
+ MXFMetadataSequence *sequence;
+ MXFMetadataTimecodeComponent *component;
+
+ p->tracks[n] = (MXFMetadataTrack *)
+ gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
+ track = (MXFMetadataTimelineTrack *) p->tracks[n];
+ mxf_ul_set (&MXF_METADATA_BASE (track)->instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (track)->instance_uid, track);
+
+ track->parent.track_id = n + 1;
+ track->parent.track_number = 0;
+ track->parent.track_name = g_strdup ("Timecode track");
+ /* FIXME: Is this correct? */
+ memcpy (&track->edit_rate, &min_edit_rate, sizeof (MXFFraction));
+
+ sequence = track->parent.sequence = (MXFMetadataSequence *)
+ gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
+ mxf_ul_set (&MXF_METADATA_BASE (sequence)->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+
+ memcpy (&sequence->data_definition,
+ mxf_metadata_track_identifier_get
+ (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
+
+ sequence->n_structural_components = 1;
+ sequence->structural_components =
+ g_new0 (MXFMetadataStructuralComponent *, 1);
+
+ component = (MXFMetadataTimecodeComponent *)
+ gst_mini_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT);
+ sequence->structural_components[0] =
+ (MXFMetadataStructuralComponent *) component;
+ mxf_ul_set (&MXF_METADATA_BASE (component)->instance_uid,
+ mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (component)->instance_uid, component);
+
+ memcpy (&component->parent.data_definition,
+ &sequence->data_definition, 16);
+
+ component->start_timecode = 0;
+ component->rounded_timecode_base =
+ (((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d) +
+ 0.5);
+ /* TODO: drop frame */
+ }
+
+ memcpy (&mux->min_edit_rate, &min_edit_rate, sizeof (MXFFraction));
+ }
+ }
+
+ for (i = 0; i < cstorage->packages[1]->n_tracks; i++) {
+ MXFMetadataTrack *track = cstorage->packages[1]->tracks[i];
+ guint j;
+ guint32 templ;
+ guint8 n_type, n;
+
+ if ((track->track_number & 0x00ff00ff) != 0)
+ continue;
+
+ templ = track->track_number;
+ n_type = 0;
+
+ for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
+ MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
+
+ if (tmp->track_number == templ) {
+ n_type++;
+ }
+ }
+
+ n = 0;
+ for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
+ MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
+
+ if (tmp->track_number == templ) {
+ n++;
+ tmp->track_number |= (n_type << 16) | (n);
+ }
+ }
+ }
+
+ cstorage->n_essence_container_data = 1;
+ cstorage->essence_container_data =
+ g_new0 (MXFMetadataEssenceContainerData *, 1);
+ cstorage->essence_container_data[0] = (MXFMetadataEssenceContainerData *)
+ gst_mini_object_new (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA);
+ mxf_ul_set (&MXF_METADATA_BASE (cstorage->essence_container_data[0])->
+ instance_uid, mux->metadata);
+ g_hash_table_insert (mux->metadata,
+ &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
+ cstorage->essence_container_data[0]);
+
+ cstorage->essence_container_data[0]->linked_package =
+ MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
+ cstorage->essence_container_data[0]->index_sid = 0;
+ cstorage->essence_container_data[0]->body_sid = 1;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_mux_create_header_partition_pack (GstMXFMux * mux)
+{
+ GSList *l;
+ guint i = 0;
+
+ mxf_partition_pack_reset (&mux->partition);
+ mux->partition.type = MXF_PARTITION_PACK_HEADER;
+ mux->partition.closed = mux->partition.complete = FALSE;
+ mux->partition.major_version = 0x0001;
+ mux->partition.minor_version = 0x0002;
+ mux->partition.kag_size = 0;
+ mux->partition.this_partition = 0;
+ mux->partition.prev_partition = 0;
+ mux->partition.footer_partition = 0;
+ mux->partition.header_byte_count = 0;
+ mux->partition.index_byte_count = 0;
+ mux->partition.index_sid = 0;
+ mux->partition.body_offset = 0;
+ mux->partition.body_sid = 0;
+
+ memcpy (&mux->partition.operational_pattern,
+ &mux->preface->operational_pattern, 16);
+
+ mux->partition.n_essence_containers = g_slist_length (mux->collect->data);
+ mux->partition.essence_containers =
+ g_new0 (MXFUL, mux->partition.n_essence_containers);
+
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; j <= i; j++) {
+ if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
+ &mux->partition.essence_containers[j])) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ memcpy (&mux->partition.essence_containers[i],
+ &cpad->descriptor->essence_container, 16);
+ i++;
+ }
+ mux->partition.n_essence_containers = i;
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *buf;
+ GList *buffers = NULL;
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ GHashTableIter iter;
+#else
+ GList *values;
+#endif
+ MXFMetadataBase *m;
+ GList *l;
+ guint64 header_byte_count = 0;
+
+ buf =
+ mxf_metadata_base_to_buffer (MXF_METADATA_BASE (mux->preface),
+ &mux->primer);
+ header_byte_count += GST_BUFFER_SIZE (buf);
+ buffers = g_list_prepend (buffers, buf);
+
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ g_hash_table_iter_init (&iter, mux->metadata);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
+#else
+ values = g_hash_table_get_values (mux->metadata);
+ for (l = values; l; l = l->next) {
+ m = l->data;
+#endif
+ buf = mxf_metadata_base_to_buffer (m, &mux->primer);
+ header_byte_count += GST_BUFFER_SIZE (buf);
+ buffers = g_list_prepend (buffers, buf);
+ }
+
+#if !GLIB_CHECK_VERSION (2, 16, 0)
+ g_list_free (value);
+#endif
+
+ buffers = g_list_reverse (buffers);
+ buf = mxf_primer_pack_to_buffer (&mux->primer);
+ header_byte_count += GST_BUFFER_SIZE (buf);
+ buffers = g_list_prepend (buffers, buf);
+
+ mux->partition.header_byte_count = header_byte_count;
+ buf = mxf_partition_pack_to_buffer (&mux->partition);
+ if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (mux, "Failed pushing partition: %s",
+ gst_flow_get_name (ret));
+ g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (buffers);
+ return ret;
+ }
+
+ for (l = buffers; l; l = l->next) {
+ buf = l->data;
+ l->data = NULL;
+ if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
+ gst_flow_get_name (ret));
+ g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (buffers);
+ return ret;
+ }
+ }
+
+ g_list_free (buffers);
+
+ return ret;
+}
+
+static const guint8 _gc_essence_element_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x00,
+ 0x0d, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
+};
+
+static GstFlowReturn
+gst_mxf_mux_handle_buffer (GstMXFMux * mux, GstMXFMuxPad * cpad)
+{
+ GstBuffer *buf = NULL;
+ GstBuffer *outbuf = NULL;
+ GstBuffer *packet;
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint8 slen, ber[9];
+ gboolean flush =
+ (cpad->collect.abidata.ABI.eos && !cpad->have_complete_edit_unit
+ && cpad->collect.buffer == NULL);
+
+ if (cpad->have_complete_edit_unit) {
+ GST_DEBUG_OBJECT (cpad->collect.pad,
+ "Handling remaining buffer for track %u at position %" G_GINT64_FORMAT,
+ cpad->source_track->parent.track_id, cpad->pos);
+ buf = NULL;
+ } else if (!flush) {
+ buf = gst_collect_pads_pop (mux->collect, &cpad->collect);
+ }
+
+ if (buf) {
+ GST_DEBUG_OBJECT (cpad->collect.pad,
+ "Handling buffer of size %u for track %u at position %" G_GINT64_FORMAT,
+ GST_BUFFER_SIZE (buf), cpad->source_track->parent.track_id, cpad->pos);
+ } else {
+ flush = TRUE;
+ GST_DEBUG_OBJECT (cpad->collect.pad,
+ "Flushing for track %u at position %" G_GINT64_FORMAT,
+ cpad->source_track->parent.track_id, cpad->pos);
+ }
+
+ ret = cpad->write_func (buf, GST_PAD_CAPS (cpad->collect.pad),
+ cpad->mapping_data, cpad->adapter, &outbuf, flush);
+ if (ret != GST_FLOW_OK && ret != GST_FLOW_CUSTOM_SUCCESS) {
+ GST_ERROR_OBJECT (cpad->collect.pad,
+ "Failed handling buffer for track %u, reason %s",
+ cpad->source_track->parent.track_id, gst_flow_get_name (ret));
+ return ret;
+ }
+
+ if (ret == GST_FLOW_CUSTOM_SUCCESS) {
+ cpad->have_complete_edit_unit = TRUE;
+ ret = GST_FLOW_OK;
+ } else {
+ cpad->have_complete_edit_unit = FALSE;
+ }
+
+ buf = outbuf;
+ if (buf == NULL)
+ return ret;
+
+ slen = mxf_ber_encode_size (GST_BUFFER_SIZE (buf), ber);
+ packet = gst_buffer_new_and_alloc (16 + slen + GST_BUFFER_SIZE (buf));
+ memcpy (GST_BUFFER_DATA (packet), _gc_essence_element_ul, 16);
+ GST_BUFFER_DATA (packet)[7] = cpad->descriptor->essence_container.u[7];
+ GST_WRITE_UINT32_BE (&GST_BUFFER_DATA (packet)[12],
+ cpad->source_track->parent.track_number);
+ memcpy (&GST_BUFFER_DATA (packet)[16], ber, slen);
+ memcpy (&GST_BUFFER_DATA (packet)[16 + slen], GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+ gst_buffer_unref (buf);
+
+ GST_DEBUG_OBJECT (cpad->collect.pad, "Pushing buffer of size %u for track %u",
+ GST_BUFFER_SIZE (packet), cpad->source_track->parent.track_id);
+
+ if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (cpad->collect.pad,
+ "Failed pushing buffer for track %u, reason %s",
+ cpad->source_track->parent.track_id, gst_flow_get_name (ret));
+ return ret;
+ }
+
+ cpad->pos++;
+ cpad->last_timestamp =
+ gst_util_uint64_scale (GST_SECOND * cpad->pos,
+ cpad->source_track->edit_rate.d, cpad->source_track->edit_rate.n);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_mux_write_body_partition (GstMXFMux * mux)
+{
+ GstBuffer *buf;
+
+ mux->partition.type = MXF_PARTITION_PACK_BODY;
+ mux->partition.closed = mux->partition.complete = FALSE;
+ mux->partition.major_version = 0x0001;
+ mux->partition.minor_version = 0x0002;
+ mux->partition.kag_size = 0;
+ mux->partition.this_partition = mux->offset;
+ mux->partition.prev_partition = 0;
+ mux->partition.footer_partition = 0;
+ mux->partition.header_byte_count = 0;
+ mux->partition.index_byte_count = 0;
+ mux->partition.index_sid = 0;
+ mux->partition.body_offset = 0;
+ mux->partition.body_sid =
+ mux->preface->content_storage->essence_container_data[0]->body_sid;
+
+ buf = mxf_partition_pack_to_buffer (&mux->partition);
+ return gst_mxf_mux_push (mux, buf);
+}
+
+static GstFlowReturn
+gst_mxf_mux_handle_eos (GstMXFMux * mux)
+{
+ GSList *l;
+ gboolean have_data = FALSE;
+ GstBuffer *packet;
+
+ do {
+ GstMXFMuxPad *best = NULL;
+
+ have_data = FALSE;
+
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ GstClockTime next_gc_timestamp =
+ gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
+ mux->min_edit_rate.d, mux->min_edit_rate.n);
+
+ best = NULL;
+
+ if (cpad->have_complete_edit_unit ||
+ gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer) {
+ have_data = TRUE;
+ if (cpad->last_timestamp < next_gc_timestamp) {
+ best = cpad;
+ break;
+ }
+ } else if (have_data && !l->next) {
+ mux->last_gc_position++;
+ mux->last_gc_timestamp = next_gc_timestamp;
+ have_data = FALSE;
+ best = NULL;
+ break;
+ }
+ }
+
+ if (best) {
+ gst_mxf_mux_handle_buffer (mux, best);
+ have_data = TRUE;
+ }
+ } while (have_data);
+
+ mux->last_gc_position++;
+ mux->last_gc_timestamp =
+ gst_util_uint64_scale (mux->last_gc_position * GST_SECOND,
+ mux->min_edit_rate.d, mux->min_edit_rate.n);
+
+ /* Update essence track durations */
+ for (l = mux->collect->data; l; l = l->next) {
+ GstMXFMuxPad *cpad = l->data;
+ guint i;
+
+ /* Update durations */
+ cpad->source_track->parent.sequence->duration = cpad->pos;
+ MXF_METADATA_SOURCE_CLIP (cpad->source_track->parent.sequence->
+ structural_components[0])->parent.duration = cpad->pos;
+ for (i = 0; i < mux->preface->content_storage->packages[0]->n_tracks; i++) {
+ MXFMetadataTimelineTrack *track;
+
+ if (!MXF_IS_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
+ packages[0]->tracks[i])
+ || !MXF_IS_METADATA_SOURCE_CLIP (mux->preface->content_storage->
+ packages[0]->tracks[i]->sequence->structural_components[0]))
+ continue;
+
+ track =
+ MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
+ packages[0]->tracks[i]);
+ if (MXF_METADATA_SOURCE_CLIP (track->parent.sequence->
+ structural_components[0])->source_track_id ==
+ cpad->source_track->parent.track_id) {
+ track->parent.sequence->structural_components[0]->duration = cpad->pos;
+ track->parent.sequence->duration = cpad->pos;
+ }
+ }
+ }
+
+ /* Update timecode track duration */
+ {
+ MXFMetadataTimelineTrack *track =
+ MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
+ packages[0]->tracks[0]);
+ MXFMetadataSequence *sequence = track->parent.sequence;
+ MXFMetadataTimecodeComponent *component =
+ MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
+
+ sequence->duration = mux->last_gc_position;
+ component->parent.duration = mux->last_gc_position;
+ }
+
+ {
+ guint64 body_partition = mux->partition.this_partition;
+ guint32 body_sid = mux->partition.body_sid;
+ guint64 footer_partition = mux->offset;
+ GArray *rip;
+ GstFlowReturn ret;
+ MXFRandomIndexPackEntry entry;
+
+ mux->partition.type = MXF_PARTITION_PACK_FOOTER;
+ mux->partition.closed = TRUE;
+ mux->partition.complete = TRUE;
+ mux->partition.major_version = 0x0001;
+ mux->partition.minor_version = 0x0002;
+ mux->partition.kag_size = 0;
+ mux->partition.this_partition = mux->offset;
+ mux->partition.prev_partition = body_partition;
+ mux->partition.footer_partition = mux->offset;
+ mux->partition.header_byte_count = 0;
+ mux->partition.index_byte_count = 0;
+ mux->partition.index_sid = 0;
+ mux->partition.body_offset = 0;
+ mux->partition.body_sid = 0;
+
+ gst_mxf_mux_write_header_metadata (mux);
+
+ rip = g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), 3);
+ entry.offset = 0;
+ entry.body_sid = 0;
+ g_array_append_val (rip, entry);
+ entry.offset = body_partition;
+ entry.body_sid = body_sid;
+ g_array_append_val (rip, entry);
+ entry.offset = footer_partition;
+ entry.body_sid = 0;
+ g_array_append_val (rip, entry);
+
+ packet = mxf_random_index_pack_to_buffer (rip);
+ if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (mux, "Failed pushing random index pack");
+ }
+ g_array_free (rip, TRUE);
+
+ /* Rewrite header partition with updated values */
+ if (gst_pad_push_event (mux->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
+ 0))) {
+ mux->offset = 0;
+ mux->partition.type = MXF_PARTITION_PACK_HEADER;
+ mux->partition.closed = TRUE;
+ mux->partition.complete = TRUE;
+ mux->partition.major_version = 0x0001;
+ mux->partition.minor_version = 0x0002;
+ mux->partition.kag_size = 0;
+ mux->partition.this_partition = 0;
+ mux->partition.prev_partition = footer_partition;
+ mux->partition.footer_partition = footer_partition;
+ mux->partition.header_byte_count = 0;
+ mux->partition.index_byte_count = 0;
+ mux->partition.index_sid = 0;
+ mux->partition.body_offset = 0;
+ mux->partition.body_sid = 0;
+
+ ret = gst_mxf_mux_write_header_metadata (mux);
+ if (ret != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (mux, "Rewriting header partition failed");
+ return ret;
+ }
+ } else {
+ GST_WARNING_OBJECT (mux, "Can't rewrite header partition");
+ }
+ }
+
+ return GST_FLOW_OK;
+}
+
+static gint
+_sort_mux_pads (gconstpointer a, gconstpointer b)
+{
+ const GstMXFMuxPad *pa = a, *pb = b;
+ MXFMetadataTrackType ta =
+ mxf_metadata_track_identifier_parse (&pa->writer->data_definition);
+ MXFMetadataTrackType tb =
+ mxf_metadata_track_identifier_parse (&pb->writer->data_definition);
+
+ if (ta != tb)
+ return ta - tb;
+
+ return pa->source_track->parent.track_number -
+ pa->source_track->parent.track_number;
+}
+
+static GstFlowReturn
+gst_mxf_mux_collected (GstCollectPads * pads, gpointer user_data)
+{
+ GstMXFMux *mux = GST_MXF_MUX (user_data);
+ GstMXFMuxPad *best = NULL;
+ GstFlowReturn ret;
+ GSList *sl;
+ gboolean eos = TRUE;
+
+ if (mux->state == GST_MXF_MUX_STATE_ERROR) {
+ GST_ERROR_OBJECT (mux, "Had an error before -- returning");
+ return GST_FLOW_ERROR;
+ } else if (mux->state == GST_MXF_MUX_STATE_EOS) {
+ GST_WARNING_OBJECT (mux, "EOS");
+ return GST_FLOW_UNEXPECTED;
+ }
+
+ if (mux->state == GST_MXF_MUX_STATE_HEADER) {
+ if (mux->collect->data == NULL) {
+ GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
+ ("No input streams configured"));
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
+
+ if (gst_pad_push_event (mux->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
+ 0))) {
+ if ((ret = gst_mxf_mux_create_metadata (mux)) != GST_FLOW_OK)
+ goto error;
+
+ if ((ret = gst_mxf_mux_create_header_partition_pack (mux)) != GST_FLOW_OK)
+ goto error;
+
+ ret = gst_mxf_mux_write_header_metadata (mux);
+ } else {
+ ret = GST_FLOW_ERROR;
+ }
+
+ if (ret != GST_FLOW_OK)
+ goto error;
+
+ /* Sort pads, we will always write in that order */
+ mux->collect->data = g_slist_sort (mux->collect->data, _sort_mux_pads);
+
+ /* Write body partition */
+ ret = gst_mxf_mux_write_body_partition (mux);
+ if (ret != GST_FLOW_OK)
+ goto error;
+ mux->state = GST_MXF_MUX_STATE_DATA;
+ }
+
+ g_return_val_if_fail (g_hash_table_size (mux->metadata) > 0, GST_FLOW_ERROR);
+
+ do {
+ for (sl = mux->collect->data; sl; sl = sl->next) {
+ GstMXFMuxPad *cpad = sl->data;
+ GstClockTime next_gc_timestamp =
+ gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
+ mux->min_edit_rate.d, mux->min_edit_rate.n);
+
+ eos &= cpad->collect.abidata.ABI.eos;
+
+ if ((!cpad->collect.abidata.ABI.eos || cpad->have_complete_edit_unit ||
+ gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer)
+ && cpad->last_timestamp < next_gc_timestamp) {
+ best = cpad;
+ break;
+ } else if (!eos && !sl->next) {
+ mux->last_gc_position++;
+ mux->last_gc_timestamp = next_gc_timestamp;
+ eos = FALSE;
+ best = NULL;
+ break;
+ }
+ }
+ } while (!eos && best == NULL);
+
+ if (!eos && best) {
+ ret = gst_mxf_mux_handle_buffer (mux, best);
+ if (ret != GST_FLOW_OK)
+ goto error;
+ } else if (eos) {
+ GST_DEBUG_OBJECT (mux, "Handling EOS");
+
+ gst_mxf_mux_handle_eos (mux);
+ gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+ mux->state = GST_MXF_MUX_STATE_EOS;
+ return GST_FLOW_UNEXPECTED;
+ }
+
+ return GST_FLOW_OK;
+
+error:
+ {
+ mux->state = GST_MXF_MUX_STATE_ERROR;
+ gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+ return ret;
+ }
+}
+
+static GstStateChangeReturn
+gst_mxf_mux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstMXFMux *mux = GST_MXF_MUX (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_collect_pads_start (mux->collect);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_collect_pads_stop (mux->collect);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_mxf_mux_reset (mux);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/gst/mxf/mxfmux.h b/gst/mxf/mxfmux.h
new file mode 100644
index 00000000..81f232ad
--- /dev/null
+++ b/gst/mxf/mxfmux.h
@@ -0,0 +1,103 @@
+/* GStreamer
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef __MXF_MUX_H__
+#define __MXF_MUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstcollectpads.h>
+
+#include "mxfwrite.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MXF_MUX \
+ (gst_mxf_mux_get_type ())
+#define GST_MXF_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MXF_MUX, GstMXFMux))
+#define GST_MXF_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MXF_MUX, GstMXFMuxClass))
+#define GST_IS_MXF_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MXF_MUX))
+#define GST_IS_MXF_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MXF_MUX))
+
+typedef struct
+{
+ GstCollectData collect;
+
+ guint64 pos;
+ GstClockTime last_timestamp;
+
+ MXFMetadataFileDescriptor *descriptor;
+
+ GstAdapter *adapter;
+ gboolean have_complete_edit_unit;
+
+ gpointer mapping_data;
+ const MXFEssenceElementWriter *writer;
+ MXFEssenceElementWriteFunc write_func;
+
+ MXFMetadataSourcePackage *source_package;
+ MXFMetadataTimelineTrack *source_track;
+} GstMXFMuxPad;
+
+typedef enum
+{
+ GST_MXF_MUX_STATE_HEADER,
+ GST_MXF_MUX_STATE_DATA,
+ GST_MXF_MUX_STATE_EOS,
+ GST_MXF_MUX_STATE_ERROR
+} GstMXFMuxState;
+
+typedef struct _GstMXFMux {
+ GstElement element;
+
+ GstPad *srcpad;
+ GstCollectPads *collect;
+ GstPadEventFunction collect_event;
+
+ GstMXFMuxState state;
+ guint n_pads;
+
+ guint64 offset;
+
+ MXFPartitionPack partition;
+ MXFPrimerPack primer;
+
+ GHashTable *metadata;
+ MXFMetadataPreface *preface;
+
+ MXFFraction min_edit_rate;
+ guint64 last_gc_position;
+ GstClockTime last_gc_timestamp;
+
+ gchar *application;
+} GstMXFMux;
+
+typedef struct _GstMXFMuxClass {
+ GstElementClass parent;
+} GstMXFMuxClass;
+
+GType gst_mxf_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __MXF_MUX_H__ */
diff --git a/gst/mxf/mxfparse.c b/gst/mxf/mxfparse.c
index d4d52312..f0c0d0e5 100644
--- a/gst/mxf/mxfparse.c
+++ b/gst/mxf/mxfparse.c
@@ -29,61 +29,19 @@
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
-/* SMPTE 377M 3.3: A value of 0 for every field means unknown timestamp */
-static const MXFTimestamp mxf_timestamp_unknown = { 0, 0, 0, 0, 0, 0, 0 };
-
-static const MXFUMID umid_zero = { {0,} };
-static const MXFUL key_zero = { {0,} };
-
-/* UL common to all MXF UL */
-static const guint8 mxf_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
-
-/* SMPTE 377M 6.1 */
-static const guint8 partition_pack_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
- 0x01
-};
-
-/* SMPTE 336M */
-static const guint8 fill_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x02, 0x10,
- 0x01, 0x00, 0x00, 0x00
-};
-
-/* SMPTE 377M 8.1 */
-static const guint8 primer_pack_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
- 0x01, 0x05, 0x01, 0x00
-};
-
-/* SMPTE 377M 8.6 */
-static const guint8 metadata_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01,
- 0x01
-};
-
-static const guint8 random_index_pack_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
- 0x01, 0x11, 0x01, 0x00
-};
-
-static const guint8 index_table_segment_key[] =
- { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
- 0x01, 0x10, 0x01, 0x00
-};
-
gboolean
-mxf_is_mxf_packet (const MXFUL * key)
+mxf_is_mxf_packet (const MXFUL * ul)
{
- return (memcmp (key, mxf_key, 4) == 0);
+ return mxf_ul_is_subclass (MXF_UL (SMPTE), ul);
}
/* SMPTE 377M 6.1: Check if this is a valid partition pack */
gboolean
-mxf_is_partition_pack (const MXFUL * key)
+mxf_is_partition_pack (const MXFUL * ul)
{
- if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] >= 0x02
- && key->u[13] <= 0x04 && key->u[14] < 0x05 && key->u[15] == 0x00)
+ if (mxf_ul_is_subclass (MXF_UL (PARTITION_PACK), ul) &&
+ ul->u[13] >= 0x02 && ul->u[13] <= 0x04 &&
+ ul->u[14] < 0x05 && ul->u[15] == 0x00)
return TRUE;
return FALSE;
@@ -91,10 +49,9 @@ mxf_is_partition_pack (const MXFUL * key)
/* SMPTE 377M 6.2: header partition pack has byte 14 == 0x02 */
gboolean
-mxf_is_header_partition_pack (const MXFUL * key)
+mxf_is_header_partition_pack (const MXFUL * ul)
{
- if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x02 &&
- key->u[14] < 0x05 && key->u[15] == 0x00)
+ if (mxf_is_partition_pack (ul) && ul->u[13] == 0x02)
return TRUE;
return FALSE;
@@ -102,10 +59,9 @@ mxf_is_header_partition_pack (const MXFUL * key)
/* SMPTE 377M 6.3: body partition pack has byte 14 == 0x03 */
gboolean
-mxf_is_body_partition_pack (const MXFUL * key)
+mxf_is_body_partition_pack (const MXFUL * ul)
{
- if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x03 &&
- key->u[14] < 0x05 && key->u[15] == 0x00)
+ if (mxf_is_partition_pack (ul) && ul->u[13] == 0x03)
return TRUE;
return FALSE;
@@ -113,159 +69,92 @@ mxf_is_body_partition_pack (const MXFUL * key)
/* SMPTE 377M 6.4: footer partition pack has byte 14 == 0x04 */
gboolean
-mxf_is_footer_partition_pack (const MXFUL * key)
+mxf_is_footer_partition_pack (const MXFUL * ul)
{
- if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x04 &&
- key->u[14] < 0x05 && key->u[15] == 0x00)
+ if (mxf_is_partition_pack (ul) && ul->u[13] == 0x04)
return TRUE;
return FALSE;
}
gboolean
-mxf_is_fill (const MXFUL * key)
+mxf_is_fill (const MXFUL * ul)
{
- return (memcmp (key, fill_key, 16) == 0);
+ return (mxf_ul_is_subclass (MXF_UL (FILL), ul));
}
gboolean
-mxf_is_primer_pack (const MXFUL * key)
+mxf_is_primer_pack (const MXFUL * ul)
{
- return (memcmp (key, primer_pack_key, 16) == 0);
+ return (mxf_ul_is_subclass (MXF_UL (PRIMER_PACK), ul));
}
gboolean
-mxf_is_metadata (const MXFUL * key)
+mxf_is_metadata (const MXFUL * ul)
{
- return (memcmp (key, metadata_key, 13) == 0 && key->u[15] == 0x00);
+ return (mxf_ul_is_subclass (MXF_UL (METADATA), ul));
}
/* SMPTE 377M 8.7.3 */
gboolean
-mxf_is_descriptive_metadata (const MXFUL * key)
+mxf_is_descriptive_metadata (const MXFUL * ul)
{
- return (memcmp (key, mxf_key, 4) == 0 &&
- key->u[4] == 0x02 &&
- key->u[6] == 0x01 &&
- key->u[7] == 0x01 &&
- key->u[8] == 0x0d &&
- key->u[9] == 0x01 && key->u[10] == 0x04 && key->u[11] == 0x01);
+ return (mxf_ul_is_subclass (MXF_UL (DESCRIPTIVE_METADATA), ul));
}
gboolean
-mxf_is_random_index_pack (const MXFUL * key)
+mxf_is_random_index_pack (const MXFUL * ul)
{
- return (memcmp (key, random_index_pack_key, 16) == 0);
+ return (mxf_ul_is_subclass (MXF_UL (RANDOM_INDEX_PACK), ul));
}
gboolean
-mxf_is_index_table_segment (const MXFUL * key)
+mxf_is_index_table_segment (const MXFUL * ul)
{
- return (memcmp (key, index_table_segment_key, 16) == 0);
+ return (mxf_ul_is_subclass (MXF_UL (INDEX_TABLE_SEGMENT), ul));
}
/* SMPTE 379M 6.2.1 */
gboolean
-mxf_is_generic_container_system_item (const MXFUL * key)
+mxf_is_generic_container_system_item (const MXFUL * ul)
{
- return (memcmp (key, mxf_key, 4) == 0 && key->u[4] == 0x02
- && key->u[6] == 0x01 && key->u[8] == 0x0d && key->u[9] == 0x01
- && key->u[10] == 0x03 && key->u[11] == 0x01 && (key->u[12] == 0x04
- || key->u[12] == 0x14));
+ return (mxf_ul_is_subclass (MXF_UL (GENERIC_CONTAINER_SYSTEM_ITEM), ul) &&
+ (ul->u[12] == 0x04 || ul->u[12] == 0x14));
}
/* SMPTE 379M 7.1 */
gboolean
-mxf_is_generic_container_essence_element (const MXFUL * key)
+mxf_is_generic_container_essence_element (const MXFUL * ul)
{
- return (memcmp (key, mxf_key, 4) == 0 && key->u[4] == 0x01
- && key->u[5] == 0x02 && key->u[6] == 0x01 && key->u[8] == 0x0d
- && key->u[9] == 0x01 && key->u[10] == 0x03 && key->u[11] == 0x01
- && (key->u[12] == 0x05 || key->u[12] == 0x06 || key->u[12] == 0x07
- || key->u[12] == 0x15 || key->u[12] == 0x16 || key->u[12] == 0x17
- || key->u[12] == 0x18));
+ return (mxf_ul_is_subclass (MXF_UL (GENERIC_CONTAINER_ESSENCE_ELEMENT), ul)
+ && (ul->u[12] == 0x05 || ul->u[12] == 0x06
+ || ul->u[12] == 0x07 || ul->u[12] == 0x15
+ || ul->u[12] == 0x16 || ul->u[12] == 0x17 || ul->u[12] == 0x18));
}
/* SMPTE 379M 8 */
gboolean
-mxf_is_generic_container_essence_container_label (const MXFUL * key)
+mxf_is_generic_container_essence_container_label (const MXFUL * ul)
{
- return (key->u[0] == 0x06 &&
- key->u[1] == 0x0e &&
- key->u[2] == 0x2b &&
- key->u[3] == 0x34 &&
- key->u[4] == 0x04 &&
- key->u[5] == 0x01 &&
- key->u[6] == 0x01 &&
- key->u[8] == 0x0d &&
- key->u[9] == 0x01 &&
- key->u[10] == 0x03 &&
- key->u[11] == 0x01 && (key->u[12] == 0x01 || key->u[12] == 0x02));
+ return (mxf_ul_is_subclass (MXF_UL
+ (GENERIC_CONTAINER_ESSENCE_CONTAINER_LABEL), ul) && (ul->u[12] == 0x01
+ || ul->u[12] == 0x02));
}
/* Essence container label found in files generated by Avid */
-static const guint8 avid_essence_container_label[] = {
- 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0xff, 0x4b, 0x46, 0x41, 0x41, 0x00,
- 0x0d, 0x4d, 0x4f
-};
-
gboolean
-mxf_is_avid_essence_container_label (const MXFUL * key)
+mxf_is_avid_essence_container_label (const MXFUL * ul)
{
- return (memcmp (&key->u, avid_essence_container_label, 16) == 0);
+ return (mxf_ul_is_subclass (MXF_UL (AVID_ESSENCE_CONTAINER_ESSENCE_LABEL),
+ ul));
}
/* Essence element key found in files generated by Avid */
-static const guint8 avid_essence_element_ul[] = {
- 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, 0x0e, 0x04, 0x03, 0x01, 0x00,
- 0x00, 0x00, 0x00
-};
-
gboolean
-mxf_is_avid_essence_container_essence_element (const MXFUL * key)
+mxf_is_avid_essence_container_essence_element (const MXFUL * ul)
{
- return (memcmp (&key->u, avid_essence_element_ul, 12) == 0);
-}
-
-gboolean
-mxf_ul_is_equal (const MXFUL * a, const MXFUL * b)
-{
- return (memcmp (a, b, 16) == 0);
-}
-
-gboolean
-mxf_ul_is_zero (const MXFUL * key)
-{
- return (memcmp (key, &key_zero, 16) == 0);
-}
-
-guint
-mxf_ul_hash (const MXFUL * key)
-{
- guint32 ret = 0;
- guint i;
-
- for (i = 0; i < 4; i++)
- ret ^=
- (key->u[i * 4 + 0] << 24) | (key->u[i * 4 + 1] << 16) | (key->u[i * 4 +
- 2] << 8) | (key->u[i * 4 + 3] << 0);
-
- return ret;
-}
-
-gchar *
-mxf_ul_to_string (const MXFUL * key, gchar str[48])
-{
- g_return_val_if_fail (key != NULL, NULL);
- g_return_val_if_fail (str != NULL, NULL);
-
- g_snprintf (str, 48,
- "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
- key->u[0], key->u[1], key->u[2], key->u[3], key->u[4], key->u[5],
- key->u[6], key->u[7], key->u[8], key->u[9], key->u[10], key->u[11],
- key->u[12], key->u[13], key->u[14], key->u[15]);
-
- return str;
+ return (mxf_ul_is_subclass (MXF_UL (AVID_ESSENCE_CONTAINER_ESSENCE_ELEMENT),
+ ul));
}
gboolean
@@ -277,7 +166,9 @@ mxf_umid_is_equal (const MXFUMID * a, const MXFUMID * b)
gboolean
mxf_umid_is_zero (const MXFUMID * umid)
{
- return (memcmp (umid, &umid_zero, 32) == 0);
+ static const MXFUMID zero = { {0,} };
+
+ return (memcmp (umid, &zero, 32) == 0);
}
gchar *
@@ -362,10 +253,13 @@ mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, guint size)
return TRUE;
}
+/* SMPTE 377M 3.3: A value of 0 for every field means unknown timestamp */
gboolean
mxf_timestamp_is_unknown (const MXFTimestamp * a)
{
- return (memcmp (a, &mxf_timestamp_unknown, sizeof (MXFTimestamp)) == 0);
+ static const MXFTimestamp unknown = { 0, 0, 0, 0, 0, 0, 0 };
+
+ return (memcmp (a, &unknown, sizeof (MXFTimestamp)) == 0);
}
gint
@@ -469,54 +363,11 @@ mxf_product_version_parse (MXFProductVersion * product_version,
}
gboolean
-mxf_ul_array_parse (MXFUL ** array, guint32 * count, const guint8 * data,
- guint size)
+mxf_product_version_is_valid (const MXFProductVersion * version)
{
- guint32 element_count, element_size;
- guint i;
-
- g_return_val_if_fail (array != NULL, FALSE);
- g_return_val_if_fail (count != NULL, FALSE);
- g_return_val_if_fail (data != NULL, FALSE);
+ static const guint8 null[sizeof (MXFProductVersion)] = { 0, };
- if (size < 8)
- return FALSE;
-
- element_count = GST_READ_UINT32_BE (data);
- data += 4;
- size -= 4;
-
- if (element_count == 0) {
- *array = NULL;
- *count = 0;
- return TRUE;
- }
-
- element_size = GST_READ_UINT32_BE (data);
- data += 4;
- size -= 4;
-
- if (element_size != 16) {
- *array = NULL;
- *count = 0;
- return FALSE;
- }
-
- if (16 * element_count < size) {
- *array = NULL;
- *count = 0;
- return FALSE;
- }
-
- *array = g_new (MXFUL, element_count);
- *count = element_count;
-
- for (i = 0; i < element_count; i++) {
- memcpy (&((*array)[i]), data, 16);
- data += 16;
- }
-
- return TRUE;
+ return (memcmp (version, &null, sizeof (MXFProductVersion)) == 0);
}
/* SMPTE 377M 6.1, Table 2 */
@@ -1023,7 +874,12 @@ mxf_primer_pack_reset (MXFPrimerPack * pack)
if (pack->mappings)
g_hash_table_destroy (pack->mappings);
+ if (pack->reverse_mappings)
+ g_hash_table_destroy (pack->reverse_mappings);
+
memset (pack, 0, sizeof (MXFPrimerPack));
+
+ pack->next_free_tag = 0x8000;
}
/* structural metadata parsing */
@@ -1051,7 +907,10 @@ mxf_local_tag_parse (const guint8 * data, guint size, guint16 * tag,
void
mxf_local_tag_free (MXFLocalTag * tag)
{
- g_free (tag->data);
+ if (tag->g_slice)
+ g_slice_free1 (tag->size, tag->data);
+ else
+ g_free (tag->data);
g_slice_free (MXFLocalTag, tag);
}
@@ -1100,6 +959,32 @@ mxf_local_tag_add_to_hash_table (const MXFPrimerPack * primer,
return TRUE;
}
+gboolean
+mxf_local_tag_insert (MXFLocalTag * tag, GHashTable ** hash_table)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+ gchar str[48];
+#endif
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (hash_table != NULL, FALSE);
+
+ if (*hash_table == NULL)
+ *hash_table =
+ g_hash_table_new_full ((GHashFunc) mxf_ul_hash,
+ (GEqualFunc) mxf_ul_is_equal, (GDestroyNotify) NULL,
+ (GDestroyNotify) mxf_local_tag_free);
+
+ g_return_val_if_fail (*hash_table != NULL, FALSE);
+
+ GST_DEBUG ("Adding local tag 0x%04x with UL %s and size %u", tag,
+ mxf_ul_to_string (&tag->key, str), tag->size);
+
+ g_hash_table_insert (*hash_table, &tag->key, tag);
+
+ return TRUE;
+}
+
static GSList *_mxf_essence_element_handler_registry = NULL;
void
diff --git a/gst/mxf/mxfparse.h b/gst/mxf/mxfparse.h
index 5a5e630e..58d88d6b 100644
--- a/gst/mxf/mxfparse.h
+++ b/gst/mxf/mxfparse.h
@@ -25,6 +25,7 @@
#include <string.h>
#include "mxftypes.h"
+#include "mxful.h"
#include "mxfmetadata.h"
typedef GstFlowReturn (*MXFEssenceElementHandleFunc) (const MXFUL *key, GstBuffer *buffer, GstCaps *caps, MXFMetadataTimelineTrack *track, gpointer mapping_data, GstBuffer **outbuf);
@@ -34,11 +35,6 @@ typedef struct {
GstCaps * (*create_caps) (MXFMetadataTimelineTrack *track, GstTagList **tags, MXFEssenceElementHandleFunc *handler, gpointer *mapping_data);
} MXFEssenceElementHandler;
-gchar * mxf_ul_to_string (const MXFUL *ul, gchar str[48]);
-gboolean mxf_ul_is_equal (const MXFUL *a, const MXFUL *b);
-gboolean mxf_ul_is_zero (const MXFUL *ul);
-guint mxf_ul_hash (const MXFUL *ul);
-
gchar *mxf_umid_to_string (const MXFUMID * umid, gchar str[96]);
MXFUMID *mxf_umid_from_string (const gchar *str, MXFUMID * umid);
gboolean mxf_umid_is_equal (const MXFUMID *a, const MXFUMID *b);
@@ -72,6 +68,7 @@ gchar * mxf_utf16_to_utf8 (const guint8 * data, guint size);
gboolean mxf_product_version_parse (MXFProductVersion * product_version,
const guint8 * data, guint size);
+gboolean mxf_product_version_is_valid (const MXFProductVersion *version);
gboolean mxf_fraction_parse (MXFFraction *fraction, const guint8 *data, guint size);
gdouble mxf_fraction_to_double (const MXFFraction *fraction);
@@ -81,8 +78,6 @@ gboolean mxf_timestamp_is_unknown (const MXFTimestamp *a);
gint mxf_timestamp_compare (const MXFTimestamp *a, const MXFTimestamp *b);
gchar *mxf_timestamp_to_string (const MXFTimestamp *t, gchar str[32]);
-gboolean mxf_ul_array_parse (MXFUL **array, guint32 *count, const guint8 *data, guint size);
-
gboolean mxf_partition_pack_parse (const MXFUL *key, MXFPartitionPack *pack, const guint8 *data, guint size);
void mxf_partition_pack_reset (MXFPartitionPack *pack);
@@ -96,11 +91,12 @@ void mxf_index_table_segment_reset (MXFIndexTableSegment *segment);
gboolean mxf_local_tag_parse (const guint8 * data, guint size, guint16 * tag,
guint16 * tag_size, const guint8 ** tag_data);
-void gst_mxf_local_tag_free (MXFLocalTag *tag);
+void mxf_local_tag_free (MXFLocalTag *tag);
gboolean mxf_local_tag_add_to_hash_table (const MXFPrimerPack *primer,
guint16 tag, const guint8 *tag_data, guint16 tag_size,
GHashTable **hash_table);
+gboolean mxf_local_tag_insert (MXFLocalTag *tag, GHashTable **hash_table);
void mxf_essence_element_handler_register (const MXFEssenceElementHandler *handler);
const MXFEssenceElementHandler * mxf_essence_element_handler_find (const MXFMetadataTimelineTrack *track);
diff --git a/gst/mxf/mxftypes.h b/gst/mxf/mxftypes.h
index dcbbd28d..ffb40d9c 100644
--- a/gst/mxf/mxftypes.h
+++ b/gst/mxf/mxftypes.h
@@ -29,6 +29,10 @@ typedef struct {
guint8 u[16];
} MXFUL;
+typedef struct {
+ guint8 u[16];
+} MXFUUID;
+
/* SMPTE 377M 3.2 */
typedef struct {
guint8 u[32];
@@ -65,6 +69,8 @@ typedef struct {
MXFUL key;
guint16 size;
guint8 *data;
+
+ gboolean g_slice; /* TRUE if data was allocated by GSlice */
} MXFLocalTag;
/* SMPTE 377M 11.1 */
@@ -114,6 +120,8 @@ typedef struct {
typedef struct {
guint64 offset;
GHashTable *mappings;
+ GHashTable *reverse_mappings;
+ guint16 next_free_tag;
} MXFPrimerPack;
/* SMPTE 377M 10.2.3 */
diff --git a/gst/mxf/mxful.c b/gst/mxf/mxful.c
new file mode 100644
index 00000000..37624c53
--- /dev/null
+++ b/gst/mxf/mxful.c
@@ -0,0 +1,268 @@
+/* GStreamer
+ * Copyright (C) <2009> 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "mxful.h"
+
+const MXFUL _mxf_ul_table[] = {
+ /* SMPTE */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x00,}},
+ /* FILL, SMPTE 336M */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x03, 0x01, 0x02, 0x10, 0x01, 0x00,}},
+ /* PARTITION_PACK, SMPTE 377M 6.1 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x00,}},
+ /* PRIMER_PACK, SMPTE 377M 8.1 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0x00}},
+ /* METADATA, SMPTE 377M 8.6 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x00,}},
+ /* DESCRIPTIVE_METADATA, SMPTE 377M 8.7.3 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x00, 0x01, 0x01,
+ 0x0d, 0x01, 0x04, 0x01, 0x00,}},
+ /* RANDOM_INDEX_PACK, SMPTE 377M 11.1 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00}},
+ /* INDEX_TABLE_SEGMENT, SMPTE 377M 10.2.2 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x10, 0x01, 0x00}},
+ /* GENERIC_CONTAINER_SYSTEM_ITEM, SMPTE 379M 6.2.1 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x02, 0x00, 0x01, 0x00,
+ 0x0d, 0x01, 0x03, 0x01, 0x00}},
+ /* GENERIC_CONTAINER_ESSENCE_ELEMENT, SMPTE 379M 7.1 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x00,
+ 0x0d, 0x01, 0x03, 0x01, 0x00,}},
+ /* GENERIC_CONTAINER_ESSENCE_CONTAINER_LABEL, SMPTE 379M 8 */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x00,
+ 0x0d, 0x01, 0x03, 0x01, 0x00,}},
+ /* AVID_ESSENCE_CONTAINER_ESSENCE_ELEMENT, undocumented */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0e, 0x04, 0x03, 0x01, 0x00,}},
+ /* AVID_ESSENCE_CONTAINER_ESSENCE_LABEL, undocumented */
+ {{0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0xff,
+ 0x4b, 0x46, 0x41, 0x41, 0x00, 0x0d, 0x4d, 0x4f}},
+};
+
+gboolean
+mxf_ul_is_equal (const MXFUL * a, const MXFUL * b)
+{
+ guint i;
+
+ g_return_val_if_fail (a != NULL, FALSE);
+ g_return_val_if_fail (b != NULL, FALSE);
+
+ for (i = 0; i < 16; i++) {
+ /* registry version */
+ if (i == 7)
+ continue;
+
+ if (a->u[i] != b->u[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+mxf_ul_is_subclass (const MXFUL * class, const MXFUL * subclass)
+{
+ guint i;
+
+ g_return_val_if_fail (class != NULL, FALSE);
+ g_return_val_if_fail (subclass != NULL, FALSE);
+
+ for (i = 0; i < 16; i++) {
+ if (i == 7)
+ /* registry version */
+ continue;
+
+ if (class->u[i] != 0x00 && class->u[i] != subclass->u[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+mxf_ul_is_zero (const MXFUL * ul)
+{
+ static const guint8 zero[16] = { 0, };
+
+ g_return_val_if_fail (ul != NULL, FALSE);
+
+ return (memcmp (ul, &zero, 16) == 0);
+}
+
+gboolean
+mxf_ul_is_valid (const MXFUL * ul)
+{
+ guint i, j;
+
+ g_return_val_if_fail (ul != NULL, FALSE);
+
+ for (i = 0; i < 16; i++) {
+ if (ul->u[i] == 0x00) {
+ for (j = i; j < 16; j++) {
+ if (ul->u[j] != 0x00)
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ if (ul->u[i] > 0x7f)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+guint
+mxf_ul_hash (const MXFUL * ul)
+{
+ guint32 ret = 0;
+ guint i;
+
+ g_return_val_if_fail (ul != NULL, 0);
+
+ for (i = 0; i < 4; i++)
+ ret ^= (ul->u[i * 4 + 0] << 24) |
+ (ul->u[i * 4 + 1] << 16) |
+ (ul->u[i * 4 + 2] << 8) | (ul->u[i * 4 + 3] << 0);
+
+ return ret;
+}
+
+gchar *
+mxf_ul_to_string (const MXFUL * ul, gchar str[48])
+{
+ gchar *ret = str;
+
+ g_return_val_if_fail (ul != NULL, NULL);
+
+ if (ret == NULL)
+ ret = g_malloc (48);
+
+ g_snprintf (ret, 48,
+ "%02x.%02x.%02x.%02x."
+ "%02x.%02x.%02x.%02x."
+ "%02x.%02x.%02x.%02x."
+ "%02x.%02x.%02x.%02x",
+ ul->u[0], ul->u[1], ul->u[2], ul->u[3],
+ ul->u[4], ul->u[5], ul->u[6], ul->u[7],
+ ul->u[8], ul->u[9], ul->u[10], ul->u[11],
+ ul->u[12], ul->u[13], ul->u[14], ul->u[15]);
+
+ return ret;
+}
+
+MXFUL *
+mxf_ul_from_string (const gchar * str, MXFUL * ul)
+{
+ MXFUL *ret = ul;
+ gint len;
+ guint i, j;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ len = strlen (str);
+ if (len != 47) {
+ GST_ERROR ("Invalid UL string length %d, should be 47", len);
+ return NULL;
+ }
+
+ if (ret == NULL)
+ ret = g_new0 (MXFUL, 1);
+
+ memset (ret, 0, 16);
+
+ for (i = 0, j = 0; i < 16; i++) {
+ if (!g_ascii_isxdigit (str[j]) ||
+ !g_ascii_isxdigit (str[j + 1]) ||
+ (str[j + 2] != '.' && str[j + 2] != '\0')) {
+ GST_ERROR ("Invalid UL string '%s'", str);
+ if (ul == NULL)
+ g_free (ret);
+ return NULL;
+ }
+
+ ret->u[i] = (g_ascii_xdigit_value (str[j]) << 4) |
+ (g_ascii_xdigit_value (str[j + 1]));
+ j += 3;
+ }
+ return ret;
+}
+
+gboolean
+mxf_ul_array_parse (MXFUL ** array, guint32 * count, const guint8 * data,
+ guint size)
+{
+ guint32 element_count, element_size;
+ guint i;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (count != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ if (size < 8)
+ return FALSE;
+
+ element_count = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ if (element_count == 0) {
+ *array = NULL;
+ *count = 0;
+ return TRUE;
+ }
+
+ element_size = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ if (element_size != 16) {
+ *array = NULL;
+ *count = 0;
+ return FALSE;
+ }
+
+ if (16 * element_count < size) {
+ *array = NULL;
+ *count = 0;
+ return FALSE;
+ }
+
+ *array = g_new (MXFUL, element_count);
+ *count = element_count;
+
+ for (i = 0; i < element_count; i++) {
+ memcpy (&((*array)[i]), data, 16);
+ data += 16;
+ }
+
+ return TRUE;
+}
diff --git a/gst/mxf/mxful.h b/gst/mxf/mxful.h
new file mode 100644
index 00000000..b187229d
--- /dev/null
+++ b/gst/mxf/mxful.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <2009> 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.
+ */
+
+#ifndef __MXF_UL_H__
+#define __MXF_UL_H__
+
+#include <gst/gst.h>
+
+#include "mxftypes.h"
+
+typedef enum {
+ MXF_UL_SMPTE = 0,
+ MXF_UL_FILL,
+ MXF_UL_PARTITION_PACK,
+ MXF_UL_PRIMER_PACK,
+ MXF_UL_METADATA,
+ MXF_UL_DESCRIPTIVE_METADATA,
+ MXF_UL_RANDOM_INDEX_PACK,
+ MXF_UL_INDEX_TABLE_SEGMENT,
+ MXF_UL_GENERIC_CONTAINER_SYSTEM_ITEM,
+ MXF_UL_GENERIC_CONTAINER_ESSENCE_ELEMENT,
+ MXF_UL_GENERIC_CONTAINER_ESSENCE_CONTAINER_LABEL,
+ MXF_UL_AVID_ESSENCE_CONTAINER_ESSENCE_ELEMENT,
+ MXF_UL_AVID_ESSENCE_CONTAINER_ESSENCE_LABEL,
+ MXF_UL_MAX
+} MXFULId;
+
+extern const MXFUL _mxf_ul_table[MXF_UL_MAX];
+
+#define MXF_UL(id) (&_mxf_ul_table[MXF_UL_##id])
+
+gboolean mxf_ul_is_equal (const MXFUL *a, const MXFUL *b);
+gboolean mxf_ul_is_subclass (const MXFUL *class, const MXFUL *subclass);
+gboolean mxf_ul_is_zero (const MXFUL *ul);
+gboolean mxf_ul_is_valid (const MXFUL *ul);
+guint mxf_ul_hash (const MXFUL *ul);
+
+gchar * mxf_ul_to_string (const MXFUL *ul, gchar str[48]);
+MXFUL * mxf_ul_from_string (const gchar *str, MXFUL *ul);
+
+gboolean mxf_ul_array_parse (MXFUL **array, guint32 *count, const guint8 *data, guint size);
+
+#endif /* __MXF_UL_H__ */
diff --git a/gst/mxf/mxfup.c b/gst/mxf/mxfup.c
index ccc34ffd..a86a2c19 100644
--- a/gst/mxf/mxfup.c
+++ b/gst/mxf/mxfup.c
@@ -24,7 +24,6 @@
/* TODO:
* - Handle CDCI essence
* - Handle more formats with RGBA descriptor (4:4:4 / 4:4:4:4 YUV, RGB656, ...)
- * - Correctly transform for the GStreamer strides
* - Handle all the dimensions and other properties in the picture
* essence descriptors correctly according to S377M Annex E
* - Handle interlaced correctly, i.e. weave until we support one-field-per-buffer
@@ -40,12 +39,65 @@
#include <gst/video/video.h>
#include "mxfup.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
+static const struct
+{
+ const gchar *caps;
+ guint32 n_pixel_layout;
+ guint8 pixel_layout[10];
+ guint32 fourcc;
+} _rgba_mapping_table[] = {
+ {
+ GST_VIDEO_CAPS_RGB, 3, {
+ 'R', 8, 'G', 8, 'B', 8}, GST_MAKE_FOURCC ('R', 'G', 'B', ' ')}, {
+ GST_VIDEO_CAPS_BGR, 3, {
+ 'B', 8, 'G', 8, 'R', 8}, GST_MAKE_FOURCC ('B', 'G', 'R', ' ')}, {
+ GST_VIDEO_CAPS_YUV ("v308"), 3, {
+ 'Y', 8, 'U', 8, 'V', 8}, GST_MAKE_FOURCC ('v', '3', '0', '8')}, {
+ GST_VIDEO_CAPS_xRGB, 4, {
+ 'F', 8, 'R', 8, 'G', 8, 'B', 8}, GST_MAKE_FOURCC ('x', 'R', 'G', 'B')}, {
+ GST_VIDEO_CAPS_RGBx, 4, {
+ 'R', 8, 'G', 8, 'B', 8, 'F', 8}, GST_MAKE_FOURCC ('R', 'G', 'B', 'x')}, {
+ GST_VIDEO_CAPS_xBGR, 4, {
+ 'F', 8, 'B', 8, 'G', 8, 'R', 8}, GST_MAKE_FOURCC ('x', 'B', 'G', 'R')}, {
+ GST_VIDEO_CAPS_BGRx, 4, {
+ 'B', 8, 'G', 8, 'R', 8, 'F', 8}, GST_MAKE_FOURCC ('B', 'G', 'R', 'x')}, {
+ GST_VIDEO_CAPS_RGBA, 4, {
+ 'R', 8, 'G', 8, 'B', 8, 'A', 8}, GST_MAKE_FOURCC ('R', 'G', 'B', 'A')}, {
+ GST_VIDEO_CAPS_ARGB, 4, {
+ 'A', 8, 'R', 8, 'G', 8, 'B', 8}, GST_MAKE_FOURCC ('A', 'R', 'G', 'B')}, {
+ GST_VIDEO_CAPS_BGRA, 4, {
+ 'B', 8, 'G', 8, 'R', 8, 'A', 8}, GST_MAKE_FOURCC ('B', 'G', 'R', 'A')}, {
+ GST_VIDEO_CAPS_ABGR, 4, {
+ 'A', 8, 'B', 8, 'G', 8, 'R', 8}, GST_MAKE_FOURCC ('A', 'B', 'G', 'R')}, {
+ GST_VIDEO_CAPS_YUV ("AYUV"), 4, {
+ 'A', 8, 'Y', 8, 'U', 8, 'V', 8}, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')}
+};
+
+static const struct
+{
+ const gchar *caps;
+ guint bpp;
+ guint horizontal_subsampling;
+ guint vertical_subsampling;
+ gboolean reversed_byte_order;
+ guint32 fourcc;
+} _cdci_mapping_table[] = {
+ {
+ GST_VIDEO_CAPS_YUV ("YUY2"), 2, 1, 0, TRUE, GST_MAKE_FOURCC ('Y', 'U', 'Y',
+ '2')}, {
+GST_VIDEO_CAPS_YUV ("UYVY"), 2, 1, 0, FALSE, GST_MAKE_FOURCC ('U', 'Y', 'V',
+ 'Y')},};
+
typedef struct
{
+ guint32 fourcc; /* fourcc or RGB format specifier */
+ gint width, height;
+ guint bpp;
guint32 image_start_offset;
guint32 image_end_offset;
} MXFUPMappingData;
@@ -93,7 +145,6 @@ mxf_up_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
}
if (!data || (data->image_start_offset == 0 && data->image_end_offset == 0)) {
- *outbuf = buffer;
} else {
if (data->image_start_offset + data->image_end_offset
> GST_BUFFER_SIZE (buffer)) {
@@ -104,10 +155,38 @@ mxf_up_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
GST_BUFFER_DATA (buffer) += data->image_start_offset;
GST_BUFFER_SIZE (buffer) -= data->image_start_offset;
GST_BUFFER_SIZE (buffer) -= data->image_end_offset;
- *outbuf = buffer;
}
}
+ if (GST_BUFFER_SIZE (buffer) != data->bpp * data->width * data->height) {
+ GST_ERROR ("Invalid buffer size");
+ return GST_FLOW_ERROR;
+ }
+
+ if (data->bpp != 4
+ || GST_ROUND_UP_4 (data->width * data->bpp) != data->width * data->bpp) {
+ guint y;
+ GstBuffer *ret;
+ guint8 *indata, *outdata;
+
+ ret =
+ gst_buffer_new_and_alloc (GST_ROUND_UP_4 (data->width * data->bpp) *
+ data->height);
+ indata = GST_BUFFER_DATA (buffer);
+ outdata = GST_BUFFER_DATA (ret);
+
+ for (y = 0; y < data->height; y++) {
+ memcpy (outdata, indata, data->width * data->bpp);
+ outdata += GST_ROUND_UP_4 (data->width * data->bpp);
+ indata += data->width * data->bpp;
+ }
+
+ gst_buffer_unref (buffer);
+ *outbuf = ret;
+ } else {
+ *outbuf = buffer;
+ }
+
return GST_FLOW_OK;
}
@@ -117,85 +196,91 @@ mxf_up_rgba_create_caps (MXFMetadataTimelineTrack * track,
MXFEssenceElementHandleFunc * handler, gpointer * mapping_data)
{
GstCaps *caps = NULL;
+ guint i;
+ guint32 fourcc;
+ guint bpp;
if (!d->pixel_layout) {
GST_ERROR ("No pixel layout");
return NULL;
}
- if (d->n_pixel_layout == 3) {
- if (d->pixel_layout[0] == 'R' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'B' && d->pixel_layout[1] == 8
- && d->pixel_layout[3] == 8 && d->pixel_layout[5] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB);
- } else if (d->pixel_layout[0] == 'B' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'R' && d->pixel_layout[1] == 8
- && d->pixel_layout[3] == 8 && d->pixel_layout[5] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_BGR);
- } else {
- GST_ERROR ("Unsupport 3 component pixel layout");
- return NULL;
- }
- } else if (d->n_pixel_layout == 4) {
- if (d->pixel_layout[0] == 'R' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'B' && d->pixel_layout[6] == 'F'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBx);
- } else if (d->pixel_layout[0] == 'B' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'R' && d->pixel_layout[6] == 'F'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_BGRx);
- } else if (d->pixel_layout[0] == 'F' && d->pixel_layout[2] == 'R'
- && d->pixel_layout[4] == 'G' && d->pixel_layout[6] == 'B'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_xRGB);
- } else if (d->pixel_layout[0] == 'F' && d->pixel_layout[2] == 'B'
- && d->pixel_layout[4] == 'G' && d->pixel_layout[6] == 'R'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_xBGR);
- } else if (d->pixel_layout[0] == 'A' && d->pixel_layout[2] == 'R'
- && d->pixel_layout[4] == 'G' && d->pixel_layout[6] == 'B'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_ARGB);
- } else if (d->pixel_layout[0] == 'A' && d->pixel_layout[2] == 'B'
- && d->pixel_layout[4] == 'G' && d->pixel_layout[6] == 'R'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_ABGR);
- } else if (d->pixel_layout[0] == 'R' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'B' && d->pixel_layout[6] == 'A'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA);
- } else if (d->pixel_layout[0] == 'B' && d->pixel_layout[2] == 'G'
- && d->pixel_layout[4] == 'R' && d->pixel_layout[6] == 'A'
- && d->pixel_layout[1] == 8 && d->pixel_layout[3] == 8
- && d->pixel_layout[5] == 8 && d->pixel_layout[7] == 8) {
- caps = gst_caps_from_string (GST_VIDEO_CAPS_BGRA);
- } else {
- GST_ERROR ("Unsupport 4 component pixel layout");
- return NULL;
+ for (i = 0; i < G_N_ELEMENTS (_rgba_mapping_table); i++) {
+ if (d->n_pixel_layout != _rgba_mapping_table[i].n_pixel_layout)
+ continue;
+
+ if (memcmp (d->pixel_layout, &_rgba_mapping_table[i].pixel_layout,
+ _rgba_mapping_table[i].n_pixel_layout * 2) == 0) {
+ caps = gst_caps_from_string (_rgba_mapping_table[i].caps);
+ fourcc = _rgba_mapping_table[i].fourcc;
+ bpp = _rgba_mapping_table[i].n_pixel_layout;
+ break;
}
+ }
+
+ if (caps) {
+ MXFUPMappingData *data = g_new0 (MXFUPMappingData, 1);
+
+ mxf_metadata_generic_picture_essence_descriptor_set_caps (&d->parent, caps);
+
+ data->width = d->parent.stored_width;
+ data->height = d->parent.stored_height;
+ data->fourcc = fourcc;
+ data->bpp = bpp;
+ data->image_start_offset =
+ ((MXFMetadataGenericPictureEssenceDescriptor *) d)->image_start_offset;
+ data->image_end_offset =
+ ((MXFMetadataGenericPictureEssenceDescriptor *) d)->image_end_offset;
+
+ *mapping_data = data;
} else {
- GST_ERROR ("Pixel layouts with %u components not supported yet",
- d->n_pixel_layout);
- return NULL;
+ GST_WARNING ("Unsupported pixel layout");
+ }
+
+ return caps;
+}
+
+static GstCaps *
+mxf_up_cdci_create_caps (MXFMetadataTimelineTrack * track,
+ MXFMetadataCDCIPictureEssenceDescriptor * d, GstTagList ** tags,
+ MXFEssenceElementHandleFunc * handler, gpointer * mapping_data)
+{
+ GstCaps *caps = NULL;
+ guint i;
+ guint32 fourcc;
+ guint bpp;
+
+ for (i = 0; i < G_N_ELEMENTS (_cdci_mapping_table); i++) {
+ if (_cdci_mapping_table[i].horizontal_subsampling ==
+ d->horizontal_subsampling
+ && _cdci_mapping_table[i].vertical_subsampling ==
+ d->vertical_subsampling
+ && _cdci_mapping_table[i].reversed_byte_order ==
+ d->reversed_byte_order) {
+ caps = gst_caps_from_string (_cdci_mapping_table[i].caps);
+ fourcc = _cdci_mapping_table[i].fourcc;
+ bpp = _cdci_mapping_table[i].bpp;
+ break;
+ }
}
if (caps) {
MXFUPMappingData *data = g_new0 (MXFUPMappingData, 1);
+ mxf_metadata_generic_picture_essence_descriptor_set_caps (&d->parent, caps);
+
+ data->width = d->parent.stored_width;
+ data->height = d->parent.stored_height;
+ data->fourcc = fourcc;
+ data->bpp = bpp;
data->image_start_offset =
((MXFMetadataGenericPictureEssenceDescriptor *) d)->image_start_offset;
data->image_end_offset =
((MXFMetadataGenericPictureEssenceDescriptor *) d)->image_end_offset;
*mapping_data = data;
+ } else {
+ GST_WARNING ("Unsupported CDCI format");
}
return caps;
@@ -247,15 +332,12 @@ mxf_up_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
if (r) {
caps = mxf_up_rgba_create_caps (track, r, tags, handler, mapping_data);
+ } else if (c) {
+ caps = mxf_up_cdci_create_caps (track, c, tags, handler, mapping_data);
} else {
- GST_ERROR ("CDCI uncompressed picture essence not supported yet");
return NULL;
}
- if (caps) {
- mxf_metadata_generic_picture_essence_descriptor_set_caps (p, caps);
- }
-
return caps;
}
@@ -264,8 +346,241 @@ static const MXFEssenceElementHandler mxf_up_essence_element_handler = {
mxf_up_create_caps
};
+static GstFlowReturn
+mxf_up_write_func (GstBuffer * buffer, GstCaps * caps, gpointer mapping_data,
+ GstAdapter * adapter, GstBuffer ** outbuf, gboolean flush)
+{
+ MXFUPMappingData *data = mapping_data;
+
+ if (!buffer)
+ return GST_FLOW_OK;
+
+ if (GST_BUFFER_SIZE (buffer) !=
+ GST_ROUND_UP_4 (data->bpp * data->width) * data->height) {
+ GST_ERROR ("Invalid buffer size");
+ return GST_FLOW_ERROR;
+ }
+
+ if (data->bpp != 4
+ || GST_ROUND_UP_4 (data->width * data->bpp) != data->width * data->bpp) {
+ guint y;
+ GstBuffer *ret;
+ guint8 *indata, *outdata;
+
+ ret = gst_buffer_new_and_alloc (data->width * data->bpp * data->height);
+ indata = GST_BUFFER_DATA (buffer);
+ outdata = GST_BUFFER_DATA (ret);
+
+ for (y = 0; y < data->height; y++) {
+ memcpy (outdata, indata, data->width * data->bpp);
+ indata += GST_ROUND_UP_4 (data->width * data->bpp);
+ outdata += data->width * data->bpp;
+ }
+
+ gst_buffer_unref (buffer);
+
+ *outbuf = ret;
+ } else {
+ *outbuf = buffer;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static const guint8 up_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0D, 0x01, 0x03, 0x01, 0x02, 0x05, 0x7F, 0x01
+};
+
+static MXFMetadataFileDescriptor *
+mxf_up_get_rgba_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataRGBAPictureEssenceDescriptor *ret;
+ guint i;
+ GstCaps *tmp, *intersection;
+ MXFUPMappingData *md = g_new0 (MXFUPMappingData, 1);
+
+ *mapping_data = md;
+
+ ret = (MXFMetadataRGBAPictureEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR);
+
+ for (i = 0; i < G_N_ELEMENTS (_rgba_mapping_table); i++) {
+ tmp = gst_caps_from_string (_rgba_mapping_table[i].caps);
+ intersection = gst_caps_intersect (caps, tmp);
+ gst_caps_unref (tmp);
+
+ if (!gst_caps_is_empty (intersection)) {
+ gst_caps_unref (intersection);
+ ret->n_pixel_layout = _rgba_mapping_table[i].n_pixel_layout;
+ ret->pixel_layout = g_new0 (guint8, ret->n_pixel_layout * 2);
+ md->fourcc = _rgba_mapping_table[i].fourcc;
+ md->bpp = _rgba_mapping_table[i].n_pixel_layout;
+ memcpy (ret->pixel_layout, _rgba_mapping_table[i].pixel_layout,
+ ret->n_pixel_layout * 2);
+ break;
+ }
+ gst_caps_unref (intersection);
+ }
+
+ if (md->fourcc == 0) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+
+ memcpy (&ret->parent.parent.essence_container, &up_essence_container_ul, 16);
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ md->width = ret->parent.stored_width;
+ md->height = ret->parent.stored_height;
+
+ *handler = mxf_up_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static MXFMetadataFileDescriptor *
+mxf_up_get_cdci_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataCDCIPictureEssenceDescriptor *ret;
+ guint i;
+ GstCaps *tmp, *intersection;
+ MXFUPMappingData *md = g_new0 (MXFUPMappingData, 1);
+
+ *mapping_data = md;
+
+ ret = (MXFMetadataCDCIPictureEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR);
+
+ for (i = 0; i < G_N_ELEMENTS (_cdci_mapping_table); i++) {
+ tmp = gst_caps_from_string (_cdci_mapping_table[i].caps);
+ intersection = gst_caps_intersect (caps, tmp);
+ gst_caps_unref (tmp);
+
+ if (!gst_caps_is_empty (intersection)) {
+ gst_caps_unref (intersection);
+ ret->horizontal_subsampling =
+ _cdci_mapping_table[i].horizontal_subsampling;
+ ret->vertical_subsampling = _cdci_mapping_table[i].vertical_subsampling;
+ ret->reversed_byte_order = _cdci_mapping_table[i].reversed_byte_order;
+ md->fourcc = _cdci_mapping_table[i].fourcc;
+ md->bpp = _cdci_mapping_table[i].bpp;
+ break;
+ }
+ gst_caps_unref (intersection);
+ }
+
+ if (md->fourcc == 0) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ memcpy (&ret->parent.parent.essence_container, &up_essence_container_ul, 16);
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ md->width = ret->parent.stored_width;
+ md->height = ret->parent.stored_height;
+
+ *handler = mxf_up_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static MXFMetadataFileDescriptor *
+mxf_up_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ GstStructure *s;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "video/x-raw-rgb") == 0) {
+ return mxf_up_get_rgba_descriptor (tmpl, caps, handler, mapping_data);
+ } else if (strcmp (gst_structure_get_name (s), "video/x-raw-yuv") == 0) {
+ guint32 fourcc;
+
+ if (!gst_structure_get_fourcc (s, "format", &fourcc))
+ return NULL;
+
+ if (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V') ||
+ fourcc == GST_MAKE_FOURCC ('v', '3', '0', '8'))
+ return mxf_up_get_rgba_descriptor (tmpl, caps, handler, mapping_data);
+
+ return mxf_up_get_cdci_descriptor (tmpl, caps, handler, mapping_data);
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+mxf_up_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_up_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ edit_rate->n = a->sample_rate.n;
+ edit_rate->d = a->sample_rate.d;
+}
+
+static guint32
+mxf_up_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x15 << 24) | (0x02 << 8);
+}
+
+static MXFEssenceElementWriter mxf_up_essence_element_writer = {
+ mxf_up_get_descriptor,
+ mxf_up_update_descriptor,
+ mxf_up_get_edit_rate,
+ mxf_up_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
void
mxf_up_init (void)
{
mxf_essence_element_handler_register (&mxf_up_essence_element_handler);
+
+ mxf_up_essence_element_writer.pad_template =
+ gst_pad_template_new ("up_video_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string (GST_VIDEO_CAPS_RGB "; "
+ GST_VIDEO_CAPS_BGR "; "
+ GST_VIDEO_CAPS_RGBx "; "
+ GST_VIDEO_CAPS_xRGB "; "
+ GST_VIDEO_CAPS_BGRx "; "
+ GST_VIDEO_CAPS_xBGR "; "
+ GST_VIDEO_CAPS_ARGB "; "
+ GST_VIDEO_CAPS_RGBA "; "
+ GST_VIDEO_CAPS_ABGR "; "
+ GST_VIDEO_CAPS_BGRA "; "
+ GST_VIDEO_CAPS_YUV ("AYUV") "; "
+ GST_VIDEO_CAPS_YUV ("v308") "; "
+ GST_VIDEO_CAPS_YUV ("UYVY") "; " GST_VIDEO_CAPS_YUV ("YUY2")));
+
+ memcpy (&mxf_up_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_PICTURE_ESSENCE),
+ 16);
+ mxf_essence_element_writer_register (&mxf_up_essence_element_writer);
}
diff --git a/gst/mxf/mxfvc3.c b/gst/mxf/mxfvc3.c
index e0f9b804..3e94f378 100644
--- a/gst/mxf/mxfvc3.c
+++ b/gst/mxf/mxfvc3.c
@@ -26,9 +26,11 @@
#endif
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <string.h>
#include "mxfvc3.h"
+#include "mxfwrite.h"
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -154,8 +156,93 @@ static const MXFEssenceElementHandler mxf_vc3_essence_element_handler = {
mxf_vc3_create_caps
};
+static GstFlowReturn
+mxf_vc3_write_func (GstBuffer * buffer, GstCaps * caps, gpointer mapping_data,
+ GstAdapter * adapter, GstBuffer ** outbuf, gboolean flush)
+{
+ *outbuf = buffer;
+ return GST_FLOW_OK;
+}
+
+/* FIXME: In which version was this added? Byte 7, assuming version 10 */
+static const guint8 vc3_essence_container_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0A,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x11, 0x01, 0x00
+};
+
+static MXFMetadataFileDescriptor *
+mxf_vc3_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps,
+ MXFEssenceElementWriteFunc * handler, gpointer * mapping_data)
+{
+ MXFMetadataCDCIPictureEssenceDescriptor *ret;
+ GstStructure *s;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (strcmp (gst_structure_get_name (s), "video/x-dnxhd") != 0) {
+ GST_ERROR ("Invalid caps %" GST_PTR_FORMAT, caps);
+ return NULL;
+ }
+
+ ret = (MXFMetadataCDCIPictureEssenceDescriptor *)
+ gst_mini_object_new (MXF_TYPE_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR);
+
+ memcpy (&ret->parent.parent.essence_container, &vc3_essence_container_ul, 16);
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret->parent,
+ caps)) {
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (ret));
+ return NULL;
+ }
+
+ *handler = mxf_vc3_write_func;
+
+ return (MXFMetadataFileDescriptor *) ret;
+}
+
+static void
+mxf_vc3_update_descriptor (MXFMetadataFileDescriptor * d, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf)
+{
+ return;
+}
+
+static void
+mxf_vc3_get_edit_rate (MXFMetadataFileDescriptor * a, GstCaps * caps,
+ gpointer mapping_data, GstBuffer * buf, MXFMetadataSourcePackage * package,
+ MXFMetadataTimelineTrack * track, MXFFraction * edit_rate)
+{
+ edit_rate->n = a->sample_rate.n;
+ edit_rate->d = a->sample_rate.d;
+}
+
+static guint32
+mxf_vc3_get_track_number_template (MXFMetadataFileDescriptor * a,
+ GstCaps * caps, gpointer mapping_data)
+{
+ return (0x15 << 24) | (0x05 << 8);
+}
+
+static MXFEssenceElementWriter mxf_vc3_essence_element_writer = {
+ mxf_vc3_get_descriptor,
+ mxf_vc3_update_descriptor,
+ mxf_vc3_get_edit_rate,
+ mxf_vc3_get_track_number_template,
+ NULL,
+ {{0,}}
+};
+
void
mxf_vc3_init (void)
{
mxf_essence_element_handler_register (&mxf_vc3_essence_element_handler);
+
+ mxf_vc3_essence_element_writer.pad_template =
+ gst_pad_template_new ("vc3_video_sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+ gst_caps_from_string ("video/x-dnxhd, width = " GST_VIDEO_SIZE_RANGE
+ ", height = " GST_VIDEO_SIZE_RANGE ", framerate = "
+ GST_VIDEO_FPS_RANGE));
+ memcpy (&mxf_vc3_essence_element_writer.data_definition,
+ mxf_metadata_track_identifier_get (MXF_METADATA_TRACK_PICTURE_ESSENCE),
+ 16);
+ mxf_essence_element_writer_register (&mxf_vc3_essence_element_writer);
}
diff --git a/gst/mxf/mxfwrite.c b/gst/mxf/mxfwrite.c
new file mode 100644
index 00000000..c2c15bba
--- /dev/null
+++ b/gst/mxf/mxfwrite.c
@@ -0,0 +1,567 @@
+/* GStreamer
+ * Copyright (C) 2009 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "mxfwrite.h"
+
+GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
+#define GST_CAT_DEFAULT mxf_debug
+
+static GList *_essence_element_writer_registry = NULL;
+static GPtrArray *_essence_element_writer_pad_templates = NULL;
+
+void
+mxf_essence_element_writer_register (const MXFEssenceElementWriter * writer)
+{
+ _essence_element_writer_registry =
+ g_list_prepend (_essence_element_writer_registry, (gpointer) writer);
+
+ if (!_essence_element_writer_pad_templates)
+ _essence_element_writer_pad_templates = g_ptr_array_new ();
+
+ if (_essence_element_writer_pad_templates->len > 0 &&
+ g_ptr_array_index (_essence_element_writer_pad_templates,
+ _essence_element_writer_pad_templates->len - 1) == NULL)
+ g_ptr_array_remove_index (_essence_element_writer_pad_templates,
+ _essence_element_writer_pad_templates->len - 1);
+
+ g_ptr_array_add (_essence_element_writer_pad_templates,
+ (gpointer) writer->pad_template);
+}
+
+const GstPadTemplate **
+mxf_essence_element_writer_get_pad_templates (void)
+{
+ if (!_essence_element_writer_pad_templates
+ || _essence_element_writer_pad_templates->len == 0)
+ return NULL;
+
+ if (g_ptr_array_index (_essence_element_writer_pad_templates,
+ _essence_element_writer_pad_templates->len - 1))
+ g_ptr_array_add (_essence_element_writer_pad_templates, NULL);
+
+ return (const GstPadTemplate **) _essence_element_writer_pad_templates->pdata;
+}
+
+const MXFEssenceElementWriter *
+mxf_essence_element_writer_find (const GstPadTemplate * templ)
+{
+ GList *l = _essence_element_writer_registry;
+
+ for (; l; l = l->next) {
+ MXFEssenceElementWriter *writer = l->data;
+
+ if (writer->pad_template == templ)
+ return writer;
+ }
+
+ return NULL;
+}
+
+void
+mxf_ul_set (MXFUL * ul, GHashTable * hashtable)
+{
+ guint i;
+
+next_try:
+ for (i = 0; i < 4; i++)
+ GST_WRITE_UINT32_BE (&ul->u[i * 4], g_random_int ());
+
+ if (hashtable && g_hash_table_lookup_extended (hashtable, ul, NULL, NULL))
+ goto next_try;
+}
+
+void
+mxf_umid_set (MXFUMID * umid)
+{
+ guint i;
+ guint32 tmp;
+
+ /* SMPTE S330M 5.1.1:
+ * UMID Identifier
+ */
+ umid->u[0] = 0x06;
+ umid->u[1] = 0x0a;
+ umid->u[2] = 0x2b;
+ umid->u[3] = 0x34;
+ umid->u[4] = 0x01;
+ umid->u[5] = 0x01;
+ umid->u[6] = 0x01;
+ umid->u[7] = 0x05; /* version, see RP210 */
+ umid->u[8] = 0x01;
+ umid->u[9] = 0x01;
+ umid->u[10] = 0x0d; /* mixed group of components in a single container */
+
+ /* - UUID/UL method for material number
+ * - 24 bit PRG for instance number
+ */
+ umid->u[11] = 0x20 | 0x02;
+
+ /* Length of remaining data */
+ umid->u[12] = 0x13;
+
+ /* Instance number */
+ tmp = g_random_int ();
+ umid->u[13] = (tmp >> 24) & 0xff;
+ umid->u[14] = (tmp >> 16) & 0xff;
+ umid->u[15] = (tmp >> 8) & 0xff;
+
+ /* Material number: ISO UUID Version 4 */
+ for (i = 16; i < 32; i += 4)
+ GST_WRITE_UINT32_BE (&umid->u[i], g_random_int ());
+
+ umid->u[16 + 6] &= 0x0f;
+ umid->u[16 + 6] |= 0x40;
+
+ umid->u[16 + 8] &= 0x3f;
+ umid->u[16 + 8] |= 0x80;
+}
+
+void
+mxf_timestamp_set_now (MXFTimestamp * timestamp)
+{
+ GTimeVal tv;
+ time_t t;
+ struct tm *tm;
+
+#ifdef HAVE_GMTIME_R
+ struct tm tm_;
+#endif
+
+ g_get_current_time (&tv);
+ t = (time_t) tv.tv_sec;
+
+#ifdef HAVE_GMTIME_R
+ tm = gmtime_r (&t, &tm_);
+#else
+ tm = gmtime (&t);
+#endif
+
+ timestamp->year = tm->tm_year + 1900;
+ timestamp->month = tm->tm_mon;
+ timestamp->day = tm->tm_mday;
+ timestamp->hour = tm->tm_hour;
+ timestamp->minute = tm->tm_min;
+ timestamp->second = tm->tm_sec;
+ timestamp->msecond = tv.tv_usec / 1000;
+}
+
+static guint8 mxf_op_identification_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01
+};
+
+void
+mxf_op_set_atom (MXFUL * ul, gboolean single_sourceclip,
+ gboolean single_essence_track)
+{
+ memcpy (&ul->u, &mxf_op_identification_ul, 12);
+ ul->u[12] = 0x10;
+ ul->u[13] = 0;
+
+ if (!single_sourceclip)
+ ul->u[13] |= 0x80;
+
+ if (!single_essence_track)
+ ul->u[13] |= 0x40;
+
+ ul->u[14] = 0;
+ ul->u[15] = 0;
+}
+
+void
+mxf_op_set_generalized (MXFUL * ul, MXFOperationalPattern pattern,
+ gboolean internal_essence, gboolean streamable, gboolean single_track)
+{
+ g_return_if_fail (pattern >= MXF_OP_1a);
+
+ memcpy (&ul->u, &mxf_op_identification_ul, 12);
+
+ if (pattern == MXF_OP_1a || pattern == MXF_OP_1b || pattern == MXF_OP_1c)
+ ul->u[12] = 0x01;
+ else if (pattern == MXF_OP_2a || pattern == MXF_OP_2b || pattern == MXF_OP_2c)
+ ul->u[12] = 0x02;
+ else if (pattern == MXF_OP_3a || pattern == MXF_OP_3b || pattern == MXF_OP_3c)
+ ul->u[12] = 0x03;
+
+ if (pattern == MXF_OP_1a || pattern == MXF_OP_2a || pattern == MXF_OP_3a)
+ ul->u[13] = 0x01;
+ else if (pattern == MXF_OP_1b || pattern == MXF_OP_2b || pattern == MXF_OP_3b)
+ ul->u[13] = 0x02;
+ else if (pattern == MXF_OP_1c || pattern == MXF_OP_2c || pattern == MXF_OP_3c)
+ ul->u[13] = 0x02;
+
+ ul->u[14] = 0x80;
+ if (!internal_essence)
+ ul->u[14] |= 0x40;
+ if (!streamable)
+ ul->u[14] |= 0x20;
+ if (!single_track)
+ ul->u[14] |= 0x10;
+
+ ul->u[15] = 0;
+}
+
+static void
+_mxf_mapping_ul_free (MXFUL * ul)
+{
+ g_slice_free (MXFUL, ul);
+}
+
+guint16
+mxf_primer_pack_add_mapping (MXFPrimerPack * primer, guint16 local_tag,
+ const MXFUL * ul)
+{
+ MXFUL *uid;
+#ifndef GST_DISABLE_GST_DEBUG
+ gchar str[48];
+#endif
+
+ if (primer->mappings == NULL) {
+ primer->mappings = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL, (GDestroyNotify) _mxf_mapping_ul_free);
+ }
+
+ if (primer->reverse_mappings == NULL) {
+ primer->reverse_mappings = g_hash_table_new_full ((GHashFunc) mxf_ul_hash,
+ (GEqualFunc) mxf_ul_is_equal, (GDestroyNotify) _mxf_mapping_ul_free,
+ (GDestroyNotify) NULL);
+ }
+
+ if (primer->next_free_tag == 0xffff && local_tag == 0) {
+ GST_ERROR ("Used too many dynamic tags");
+ return 0;
+ }
+
+ if (local_tag == 0) {
+ guint16 tmp;
+
+ tmp = GPOINTER_TO_UINT (g_hash_table_lookup (primer->reverse_mappings, ul));
+ if (tmp == 0) {
+ local_tag = primer->next_free_tag;
+ primer->next_free_tag++;
+ }
+ } else {
+ if (g_hash_table_lookup (primer->mappings, GUINT_TO_POINTER (local_tag)))
+ return local_tag;
+ }
+
+ g_assert (local_tag != 0);
+
+ uid = g_slice_new (MXFUL);
+ memcpy (uid, ul, 16);
+
+ GST_DEBUG ("Adding mapping = 0x%04x -> %s", local_tag,
+ mxf_ul_to_string (uid, str));
+ g_hash_table_insert (primer->mappings, GUINT_TO_POINTER (local_tag), uid);
+ uid = g_slice_dup (MXFUL, uid);
+ g_hash_table_insert (primer->reverse_mappings, uid,
+ GUINT_TO_POINTER (local_tag));
+
+ return local_tag;
+}
+
+guint
+mxf_ber_encode_size (guint size, guint8 ber[9])
+{
+ guint8 slen, i;
+ guint8 tmp[8];
+
+ memset (ber, 0, 9);
+
+ if (size <= 127) {
+ ber[0] = size;
+ return 1;
+ } else if (size > G_MAXUINT) {
+ return 0;
+ }
+
+ slen = 0;
+ while (size > 0) {
+ tmp[slen] = size & 0xff;
+ size >>= 8;
+ slen++;
+ }
+
+ ber[0] = 0x80 | slen;
+ for (i = 0; i < slen; i++) {
+ ber[i + 1] = tmp[slen - i - 1];
+ }
+
+ return slen + 1;
+}
+
+void
+mxf_timestamp_write (const MXFTimestamp * timestamp, guint8 * data)
+{
+ GST_WRITE_UINT16_BE (data, timestamp->year);
+ GST_WRITE_UINT8 (data + 2, timestamp->month);
+ GST_WRITE_UINT8 (data + 3, timestamp->day);
+ GST_WRITE_UINT8 (data + 4, timestamp->hour);
+ GST_WRITE_UINT8 (data + 5, timestamp->minute);
+ GST_WRITE_UINT8 (data + 6, timestamp->second);
+ GST_WRITE_UINT8 (data + 7, (timestamp->msecond * 256) / 1000);
+}
+
+guint8 *
+mxf_utf8_to_utf16 (const gchar * str, guint16 * size)
+{
+ guint8 *ret;
+ GError *error = NULL;
+ gsize s;
+
+ g_return_val_if_fail (size != NULL, NULL);
+
+ if (str == NULL) {
+ *size = 0;
+ return NULL;
+ }
+
+ ret = (guint8 *)
+ g_convert_with_fallback (str, -1, "UTF-16BE", "UTF-8", "*", NULL, &s,
+ &error);
+
+ if (ret == NULL) {
+ GST_WARNING ("UTF-16-BE to UTF-8 conversion failed: %s", error->message);
+ g_error_free (error);
+ *size = 0;
+ return NULL;
+ }
+
+ *size = s;
+ return (guint8 *) ret;
+}
+
+void
+mxf_product_version_write (const MXFProductVersion * version, guint8 * data)
+{
+ GST_WRITE_UINT16_BE (data, version->major);
+ GST_WRITE_UINT16_BE (data + 2, version->minor);
+ GST_WRITE_UINT16_BE (data + 4, version->patch);
+ GST_WRITE_UINT16_BE (data + 6, version->build);
+ GST_WRITE_UINT16_BE (data + 8, version->release);
+}
+
+GstBuffer *
+mxf_partition_pack_to_buffer (const MXFPartitionPack * pack)
+{
+ static const guint8 partition_pack_ul[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01
+ };
+ guint slen;
+ guint8 ber[9];
+ GstBuffer *ret;
+ guint8 *data;
+ guint i;
+ guint size =
+ 8 + 16 * pack->n_essence_containers + 16 + 4 + 8 + 4 + 8 + 8 + 8 + 8 + 8 +
+ 4 + 2 + 2;
+
+ slen = mxf_ber_encode_size (size, ber);
+
+ ret = gst_buffer_new_and_alloc (16 + slen + size);
+ memcpy (GST_BUFFER_DATA (ret), &partition_pack_ul, 13);
+ if (pack->type == MXF_PARTITION_PACK_HEADER)
+ GST_BUFFER_DATA (ret)[13] = 0x02;
+ else if (pack->type == MXF_PARTITION_PACK_BODY)
+ GST_BUFFER_DATA (ret)[13] = 0x03;
+ else if (pack->type == MXF_PARTITION_PACK_FOOTER)
+ GST_BUFFER_DATA (ret)[13] = 0x04;
+ GST_BUFFER_DATA (ret)[14] = 0;
+ if (pack->complete)
+ GST_BUFFER_DATA (ret)[14] |= 0x02;
+ if (pack->closed)
+ GST_BUFFER_DATA (ret)[14] |= 0x01;
+ GST_BUFFER_DATA (ret)[14] += 1;
+ GST_BUFFER_DATA (ret)[15] = 0;
+ memcpy (GST_BUFFER_DATA (ret) + 16, &ber, slen);
+
+ data = GST_BUFFER_DATA (ret) + 16 + slen;
+
+ GST_WRITE_UINT16_BE (data, pack->major_version);
+ GST_WRITE_UINT16_BE (data + 2, pack->minor_version);
+ data += 4;
+
+ GST_WRITE_UINT32_BE (data, pack->kag_size);
+ data += 4;
+
+ GST_WRITE_UINT64_BE (data, pack->this_partition);
+ data += 8;
+
+ GST_WRITE_UINT64_BE (data, pack->prev_partition);
+ data += 8;
+
+ GST_WRITE_UINT64_BE (data, pack->footer_partition);
+ data += 8;
+
+ GST_WRITE_UINT64_BE (data, pack->header_byte_count);
+ data += 8;
+
+ GST_WRITE_UINT64_BE (data, pack->index_byte_count);
+ data += 8;
+
+ GST_WRITE_UINT32_BE (data, pack->index_sid);
+ data += 4;
+
+ GST_WRITE_UINT64_BE (data, pack->body_offset);
+ data += 8;
+
+ GST_WRITE_UINT32_BE (data, pack->body_sid);
+ data += 4;
+
+ memcpy (data, &pack->operational_pattern, 16);
+ data += 16;
+
+ GST_WRITE_UINT32_BE (data, pack->n_essence_containers);
+ GST_WRITE_UINT32_BE (data + 4, 16);
+ data += 8;
+
+ for (i = 0; i < pack->n_essence_containers; i++)
+ memcpy (data + 16 * i, &pack->essence_containers[i], 16);
+
+ return ret;
+}
+
+GstBuffer *
+mxf_primer_pack_to_buffer (const MXFPrimerPack * pack)
+{
+ static const guint8 primer_pack_ul[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
+ 0x01, 0x05, 0x01, 0x00
+ };
+ guint slen;
+ guint8 ber[9];
+ GstBuffer *ret;
+ guint n;
+ guint8 *data;
+
+ if (pack->mappings)
+ n = g_hash_table_size (pack->mappings);
+ else
+ n = 0;
+
+ slen = mxf_ber_encode_size (8 + 18 * n, ber);
+
+ ret = gst_buffer_new_and_alloc (16 + slen + 8 + 18 * n);
+ memcpy (GST_BUFFER_DATA (ret), &primer_pack_ul, 16);
+ memcpy (GST_BUFFER_DATA (ret) + 16, &ber, slen);
+
+ data = GST_BUFFER_DATA (ret) + 16 + slen;
+
+ GST_WRITE_UINT32_BE (data, n);
+ GST_WRITE_UINT32_BE (data + 4, 18);
+ data += 8;
+
+ if (pack->mappings) {
+ guint16 local_tag;
+ MXFUL *ul;
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ GHashTableIter iter;
+
+ g_hash_table_iter_init (&iter, pack->mappings);
+#else
+ GList *l, *values;
+
+ keys = g_hash_table_get_keys (pack->mappings);
+#endif
+
+#if GLIB_CHECK_VERSION (2, 16, 0)
+ while (g_hash_table_iter_next (&iter, (gpointer) & local_tag,
+ (gpointer) & ul)) {
+#else
+ for (l = keys l; l = l->next) {
+ local_tag = GPOINTER_TO_GUINT (l->data);
+ ul = g_hash_table_lookup (pack->mappings, GUINT_TO_POINTER (local_tag));
+#endif
+ GST_WRITE_UINT16_BE (data, local_tag);
+ memcpy (data + 2, ul, 16);
+ data += 18;
+ }
+
+#if !GLIB_CHECK_VERSION (2, 16, 0)
+ g_list_free (keys);
+#endif
+ }
+
+ return ret;
+}
+
+GstBuffer *
+mxf_fill_new (guint size)
+{
+ static const guint8 fill_ul[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x03, 0x01, 0x02, 0x10, 0x01, 0x00, 0x00, 0x00
+ };
+ GstBuffer *ret;
+ guint slen;
+ guint8 ber[9];
+
+ slen = mxf_ber_encode_size (size, ber);
+
+ ret = gst_buffer_new_and_alloc (16 + slen + size);
+ memcpy (GST_BUFFER_DATA (ret), &fill_ul, 16);
+ memcpy (GST_BUFFER_DATA (ret) + 16, &ber, slen);
+ memset (GST_BUFFER_DATA (ret) + slen, 0, size);
+
+ return ret;
+}
+
+static const guint8 random_index_pack_ul[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00
+};
+
+GstBuffer *
+mxf_random_index_pack_to_buffer (const GArray * array)
+{
+ MXFRandomIndexPackEntry *entry;
+ guint i;
+ GstBuffer *ret;
+ guint8 slen, ber[9];
+ guint size;
+ guint8 *data;
+
+ if (array->len == 0)
+ return NULL;
+
+ size = array->len * 12 + 4;
+ slen = mxf_ber_encode_size (size, ber);
+ ret = gst_buffer_new_and_alloc (16 + slen + size);
+ memcpy (GST_BUFFER_DATA (ret), random_index_pack_ul, 16);
+ memcpy (GST_BUFFER_DATA (ret) + 16, ber, slen);
+
+ data = GST_BUFFER_DATA (ret) + 16 + slen;
+
+ for (i = 0; i < array->len; i++) {
+ entry = &g_array_index (array, MXFRandomIndexPackEntry, i);
+ GST_WRITE_UINT32_BE (data, entry->body_sid);
+ GST_WRITE_UINT64_BE (data + 4, entry->offset);
+ data += 12;
+ }
+ GST_WRITE_UINT32_BE (data, GST_BUFFER_SIZE (ret));
+
+ return ret;
+}
diff --git a/gst/mxf/mxfwrite.h b/gst/mxf/mxfwrite.h
new file mode 100644
index 00000000..4ebca925
--- /dev/null
+++ b/gst/mxf/mxfwrite.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) 2009 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.
+ */
+
+/* Handling of the basic MXF types */
+
+#ifndef __MXF_WRITE_H__
+#define __MXF_WRITE_H__
+
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include "mxfmetadata.h"
+#include "mxftypes.h"
+#include "mxfparse.h"
+
+typedef GstFlowReturn (*MXFEssenceElementWriteFunc) (GstBuffer *buffer, GstCaps *caps, gpointer mapping_data, GstAdapter *adapter, GstBuffer **outbuf, gboolean flush);
+
+typedef struct {
+ MXFMetadataFileDescriptor * (*get_descriptor) (GstPadTemplate *tmpl, GstCaps *caps, MXFEssenceElementWriteFunc *handler, gpointer *mapping_data);
+ void (*update_descriptor) (MXFMetadataFileDescriptor *d, GstCaps *caps, gpointer mapping_data, GstBuffer *buf);
+ void (*get_edit_rate) (MXFMetadataFileDescriptor *a, GstCaps *caps, gpointer mapping_data, GstBuffer *buf, MXFMetadataSourcePackage *package, MXFMetadataTimelineTrack *track, MXFFraction *edit_rate);
+ guint32 (*get_track_number_template) (MXFMetadataFileDescriptor *a, GstCaps *caps, gpointer mapping_data);
+ const GstPadTemplate *pad_template;
+ MXFUL data_definition;
+} MXFEssenceElementWriter;
+
+typedef enum {
+ MXF_OP_UNKNOWN = 0,
+ MXF_OP_ATOM,
+ MXF_OP_1a,
+ MXF_OP_1b,
+ MXF_OP_1c,
+ MXF_OP_2a,
+ MXF_OP_2b,
+ MXF_OP_2c,
+ MXF_OP_3a,
+ MXF_OP_3b,
+ MXF_OP_3c,
+} MXFOperationalPattern;
+
+void mxf_essence_element_writer_register (const MXFEssenceElementWriter *writer);
+const GstPadTemplate ** mxf_essence_element_writer_get_pad_templates (void);
+const MXFEssenceElementWriter *mxf_essence_element_writer_find (const GstPadTemplate *templ);
+
+void mxf_ul_set (MXFUL *ul, GHashTable *hashtable);
+void mxf_umid_set (MXFUMID *umid);
+
+void mxf_timestamp_set_now (MXFTimestamp *timestamp);
+void mxf_timestamp_write (const MXFTimestamp *timestamp, guint8 *data);
+
+void mxf_op_set_atom (MXFUL *ul, gboolean single_sourceclip, gboolean single_essence_track);
+void mxf_op_set_generalized (MXFUL *ul, MXFOperationalPattern pattern, gboolean internal_essence, gboolean streamable, gboolean single_track);
+
+guint16 mxf_primer_pack_add_mapping (MXFPrimerPack *primer, guint16 local_tag, const MXFUL *ul);
+
+guint mxf_ber_encode_size (guint size, guint8 ber[9]);
+
+guint8 * mxf_utf8_to_utf16 (const gchar *str, guint16 *size);
+
+void mxf_product_version_write (const MXFProductVersion *version, guint8 *data);
+
+GstBuffer * mxf_partition_pack_to_buffer (const MXFPartitionPack *pack);
+GstBuffer * mxf_primer_pack_to_buffer (const MXFPrimerPack *pack);
+GstBuffer * mxf_fill_new (guint size);
+
+GstBuffer * mxf_random_index_pack_to_buffer (const GArray *array);
+
+#endif /* __MXF_WRITE_H__ */