mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
Merge branch 'mxfmux'
This commit is contained in:
commit
6f62242c5f
24 changed files with 6868 additions and 296 deletions
|
@ -45,7 +45,7 @@ AC_LIBTOOL_WIN32_DLL
|
|||
AM_PROG_LIBTOOL
|
||||
|
||||
dnl *** required versions of GStreamer stuff ***
|
||||
GST_REQ=0.10.22
|
||||
GST_REQ=0.10.22.1
|
||||
GSTPB_REQ=0.10.22
|
||||
|
||||
dnl *** autotools stuff ****
|
||||
|
@ -160,6 +160,10 @@ fi
|
|||
AM_CONDITIONAL(HAVE_GCC_ASM, test "x$HAVE_GCC_ASM" = "xyes")
|
||||
|
||||
dnl *** checks for library functions ***
|
||||
AC_CHECK_FUNCS([gmtime_r])
|
||||
|
||||
dnl *** checks for headers ***
|
||||
AC_CHECK_HEADERS([sys/utsname.h])
|
||||
|
||||
dnl *** checks for dependency libraries ***
|
||||
|
||||
|
|
|
@ -62,9 +62,11 @@ static GstStaticPadTemplate gst_jasper_enc_src_template =
|
|||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("image/x-j2c, "
|
||||
GST_STATIC_CAPS ("image/x-j2c, width = " GST_VIDEO_SIZE_RANGE ", height = "
|
||||
GST_VIDEO_SIZE_RANGE ", fourcc = (GstFourcc) { sRGB, sYUV },"
|
||||
"framerate = " GST_VIDEO_FPS_RANGE ", " "fields = (int) 1; "
|
||||
"image/x-jpc, "
|
||||
"image/x-jpc, width = " GST_VIDEO_SIZE_RANGE ", height = "
|
||||
GST_VIDEO_SIZE_RANGE ", fourcc = (GstFourcc) { sRGB, sYUV },"
|
||||
"framerate = " GST_VIDEO_FPS_RANGE ", " "fields = (int) 1; "
|
||||
"image/jp2")
|
||||
);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
1429
gst/mxf/mxfmux.c
Normal file
1429
gst/mxf/mxfmux.c
Normal file
File diff suppressed because it is too large
Load diff
103
gst/mxf/mxfmux.h
Normal file
103
gst/mxf/mxfmux.h
Normal file
|
@ -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__ */
|
|
@ -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;
|
||||
static const guint8 null[sizeof (MXFProductVersion)] = { 0, };
|
||||
|
||||
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;
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
268
gst/mxf/mxful.c
Normal file
268
gst/mxf/mxful.c
Normal file
|
@ -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;
|
||||
}
|
59
gst/mxf/mxful.h
Normal file
59
gst/mxf/mxful.h
Normal file
|
@ -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__ */
|
453
gst/mxf/mxfup.c
453
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;
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
} else {
|
||||
GST_ERROR ("Pixel layouts with %u components not supported yet",
|
||||
d->n_pixel_layout);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
567
gst/mxf/mxfwrite.c
Normal file
567
gst/mxf/mxfwrite.c
Normal file
|
@ -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;
|
||||
}
|
85
gst/mxf/mxfwrite.h
Normal file
85
gst/mxf/mxfwrite.h
Normal file
|
@ -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__ */
|
Loading…
Reference in a new issue