gstreamer/gst/mxf/mxfparse.c
Sebastian Dröge f336a478ba gst/mxf/: Use guint instead of guint64 or gsize for all buffer sizes and use correct format strings for them. Only lo...
Original commit message from CVS:
* gst/mxf/mxfaes-bwf.c:
(mxf_metadata_wave_audio_essence_descriptor_parse):
* gst/mxf/mxfaes-bwf.h:
* gst/mxf/mxfdemux.c: (gst_mxf_demux_pull_range),
(gst_mxf_demux_pull_klv_packet),
(gst_mxf_demux_parse_footer_metadata),
(gst_mxf_demux_handle_klv_packet),
(gst_mxf_demux_pull_and_handle_klv_packet), (gst_mxf_demux_chain):
* gst/mxf/mxfmpeg.c: (mxf_metadata_mpeg_video_descriptor_parse):
* gst/mxf/mxfmpeg.h:
* gst/mxf/mxfparse.c: (mxf_timestamp_parse), (mxf_fraction_parse),
(mxf_utf16_to_utf8), (mxf_product_version_parse),
(mxf_partition_pack_parse), (mxf_primer_pack_parse),
(mxf_local_tag_parse), (mxf_metadata_preface_parse),
(mxf_metadata_identification_parse),
(mxf_metadata_content_storage_parse),
(mxf_metadata_essence_container_data_parse),
(mxf_metadata_generic_package_parse), (mxf_metadata_track_parse),
(mxf_metadata_sequence_parse),
(mxf_metadata_structural_component_parse),
(mxf_metadata_generic_descriptor_parse),
(mxf_metadata_file_descriptor_parse),
(mxf_metadata_generic_sound_essence_descriptor_parse),
(mxf_metadata_generic_picture_essence_descriptor_parse),
(mxf_metadata_cdci_picture_essence_descriptor_parse),
(mxf_metadata_multiple_descriptor_parse),
(mxf_metadata_locator_parse):
* gst/mxf/mxfparse.h:
Use guint instead of guint64 or gsize for all buffer sizes and
use correct format strings for them. Only local tag set sizes
are still guint16 as they can't be larger.
Only allow KLV packets of sizes below 1<<32 as GStreamer only uses
guint for buffer sizes. The MXF standard allows packet sizes up
to 1<<64.
2008-11-22 14:42:08 +00:00

2693 lines
79 KiB
C

/* GStreamer
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <string.h>
#include "mxfparse.h"
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 };
/* FIXME: are zero UMID/UL invalid? Should be in SMPTE 298M, 330M or 336M */
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)
{
return (memcmp (key, mxf_key, 4) == 0);
}
/* SMPTE 377M 6.1: Check if this is a valid partition pack */
gboolean
mxf_is_partition_pack (const MXFUL * key)
{
if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] >= 0x02
&& key->u[13] <= 0x04 && key->u[14] < 0x05 && key->u[15] == 0x00)
return TRUE;
return FALSE;
}
/* SMPTE 377M 6.2: header partition pack has byte 14 == 0x02 */
gboolean
mxf_is_header_partition_pack (const MXFUL * key)
{
if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x02 &&
key->u[14] < 0x05 && key->u[15] == 0x00)
return TRUE;
return FALSE;
}
/* SMPTE 377M 6.3: body partition pack has byte 14 == 0x03 */
gboolean
mxf_is_body_partition_pack (const MXFUL * key)
{
if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x03 &&
key->u[14] < 0x05 && key->u[15] == 0x00)
return TRUE;
return FALSE;
}
/* SMPTE 377M 6.4: footer partition pack has byte 14 == 0x04 */
gboolean
mxf_is_footer_partition_pack (const MXFUL * key)
{
if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x04 &&
key->u[14] < 0x05 && key->u[15] == 0x00)
return TRUE;
return FALSE;
}
gboolean
mxf_is_fill (const MXFUL * key)
{
return (memcmp (key, fill_key, 16) == 0);
}
gboolean
mxf_is_primer_pack (const MXFUL * key)
{
return (memcmp (key, primer_pack_key, 16) == 0);
}
gboolean
mxf_is_metadata (const MXFUL * key)
{
return (memcmp (key, metadata_key, 13) == 0 && key->u[15] == 0x00);
}
gboolean
mxf_is_random_index_pack (const MXFUL * key)
{
return (memcmp (key, random_index_pack_key, 16) == 0);
}
gboolean
mxf_is_index_table_segment (const MXFUL * key)
{
return (memcmp (key, index_table_segment_key, 16) == 0);
}
/* SMPTE 379M 6.2.1 */
gboolean
mxf_is_generic_container_system_item (const MXFUL * key)
{
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));
}
/* SMPTE 379M 7.1 */
gboolean
mxf_is_generic_container_essence_element (const MXFUL * key)
{
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));
}
/* SMPTE 379M 8 */
gboolean
mxf_is_generic_container_essence_container_label (const MXFUL * key)
{
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));
}
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);
}
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;
}
gboolean
mxf_umid_is_equal (const MXFUMID * a, const MXFUMID * b)
{
return (memcmp (a, b, 32) == 0);
}
gboolean
mxf_umid_is_zero (const MXFUMID * umid)
{
return (memcmp (umid, &umid_zero, 32) == 0);
}
gchar *
mxf_umid_to_string (const MXFUMID * key, gchar str[96])
{
g_return_val_if_fail (key != NULL, NULL);
g_return_val_if_fail (str != NULL, NULL);
g_snprintf (str, 96,
"%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x."
"%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],
key->u[16],
key->u[17],
key->u[18],
key->u[19],
key->u[20],
key->u[21],
key->u[22],
key->u[23],
key->u[24],
key->u[25],
key->u[26], key->u[27], key->u[28], key->u[29], key->u[30], key->u[31]
);
return str;
}
static guint
gst_mxf_ul_hash (const MXFUL * key)
{
guint32 ret = 0;
gint 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;
}
static gboolean
gst_mxf_ul_equal (const MXFUL * a, const MXFUL * b)
{
return (memcmp (a, b, 16) == 0);
}
gboolean
mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, guint size)
{
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (timestamp != NULL, FALSE);
memset (timestamp, 0, sizeof (MXFTimestamp));
if (size < 8)
return FALSE;
timestamp->year = GST_READ_UINT16_BE (data);
timestamp->month = GST_READ_UINT8 (data + 2);
timestamp->day = GST_READ_UINT8 (data + 3);
timestamp->hour = GST_READ_UINT8 (data + 4);
timestamp->minute = GST_READ_UINT8 (data + 5);
timestamp->second = GST_READ_UINT8 (data + 6);
timestamp->quarter_msecond = GST_READ_UINT8 (data + 7);
return TRUE;
}
gboolean
mxf_timestamp_is_unknown (const MXFTimestamp * a)
{
return (memcmp (a, &mxf_timestamp_unknown, sizeof (MXFTimestamp)) == 0);
}
gint
mxf_timestamp_compare (const MXFTimestamp * a, const MXFTimestamp * b)
{
gint diff;
if ((diff = a->year - b->year) != 0)
return diff;
else if ((diff = a->month - b->month) != 0)
return diff;
else if ((diff = a->day - b->day) != 0)
return diff;
else if ((diff = a->hour - b->hour) != 0)
return diff;
else if ((diff = a->minute - b->minute) != 0)
return diff;
else if ((diff = a->second - b->second) != 0)
return diff;
else if ((diff = a->quarter_msecond - b->quarter_msecond) != 0)
return diff;
else
return 0;
}
gboolean
mxf_fraction_parse (MXFFraction * fraction, const guint8 * data, guint size)
{
g_return_val_if_fail (fraction != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
memset (fraction, 0, sizeof (MXFFraction));
if (size < 8)
return FALSE;
fraction->n = GST_READ_UINT32_BE (data);
fraction->d = GST_READ_UINT32_BE (data + 4);
return TRUE;
}
gchar *
mxf_utf16_to_utf8 (const guint8 * data, guint size)
{
gchar *ret;
GError *error = NULL;
ret =
g_convert ((const gchar *) data, size, "UTF-8", "UTF-16BE", NULL, NULL,
&error);
if (ret == NULL) {
GST_WARNING ("UTF-16-BE to UTF-8 conversion failed: %s", error->message);
g_error_free (error);
return NULL;
}
return ret;
}
gboolean
mxf_product_version_parse (MXFProductVersion * product_version,
const guint8 * data, guint size)
{
g_return_val_if_fail (product_version != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
memset (product_version, 0, sizeof (MXFProductVersion));
if (size < 10)
return FALSE;
product_version->major = GST_READ_UINT16_BE (data);
product_version->minor = GST_READ_UINT16_BE (data + 2);
product_version->patch = GST_READ_UINT16_BE (data + 4);
product_version->build = GST_READ_UINT16_BE (data + 6);
product_version->release = GST_READ_UINT16_BE (data + 8);
return TRUE;
}
/* SMPTE 377M 6.1, Table 2 */
gboolean
mxf_partition_pack_parse (const MXFUL * key, MXFPartitionPack * pack,
const guint8 * data, guint size)
{
gint i;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (size >= 84, FALSE);
memset (pack, 0, sizeof (MXFPartitionPack));
if (key->u[13] == 0x02)
pack->type = MXF_PARTITION_PACK_HEADER;
else if (key->u[13] == 0x03)
pack->type = MXF_PARTITION_PACK_BODY;
else if (key->u[13] == 0x04)
pack->type = MXF_PARTITION_PACK_FOOTER;
pack->closed = (key->u[14] == 0x02 || key->u[14] == 0x04);
pack->complete = (key->u[14] == 0x03 || key->u[14] == 0x04);
pack->major_version = GST_READ_UINT16_BE (data);
if (pack->major_version != 1)
goto error;
data += 2;
size -= 2;
pack->minor_version = GST_READ_UINT16_BE (data);
data += 2;
size -= 2;
pack->kag_size = GST_READ_UINT32_BE (data);
data += 4;
size -= 4;
pack->this_partition = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->prev_partition = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->footer_partition = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->header_byte_count = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->index_byte_count = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->index_sid = GST_READ_UINT32_BE (data);
data += 4;
size -= 4;
pack->body_offset = GST_READ_UINT64_BE (data);
data += 8;
size -= 8;
pack->body_sid = GST_READ_UINT32_BE (data);
data += 4;
size -= 4;
memcpy (&pack->operational_pattern, data, 16);
data += 16;
size -= 16;
pack->n_essence_containers = GST_READ_UINT32_BE (data);
data += 4;
size -= 4;
if (GST_READ_UINT32_BE (data) != 16)
goto error;
data += 4;
size -= 4;
if (size < 16 * pack->n_essence_containers)
goto error;
if (pack->n_essence_containers) {
pack->essence_containers = g_new (MXFUL, pack->n_essence_containers);
for (i = 0; i < pack->n_essence_containers; i++)
memcpy (&pack->essence_containers[i], data + i * 16, 16);
}
pack->valid = TRUE;
GST_DEBUG ("Parsed partition pack: \n"
" type = %s, closed = %s, complete = %s\n"
" MXF version = %u.%u\n"
" KAG size = %u\n"
" this partition offset = %" G_GUINT64_FORMAT "\n"
" previous partition offset = %" G_GUINT64_FORMAT "\n"
" footer partition offset = %" G_GUINT64_FORMAT "\n"
" header size = %" G_GUINT64_FORMAT "\n"
" index sid = %u, size %" G_GUINT64_FORMAT "\n"
" body sid = %u, offset %" G_GUINT64_FORMAT "\n"
" operational pattern = %s\n"
" number of essence containers = %u",
(pack->type == MXF_PARTITION_PACK_HEADER) ? "header" : (pack->type ==
MXF_PARTITION_PACK_BODY) ? "body" : "footer",
(pack->closed) ? "yes" : "no", (pack->complete) ? "yes" : "no",
pack->major_version, pack->minor_version, pack->kag_size,
pack->this_partition, pack->prev_partition, pack->footer_partition,
pack->header_byte_count, pack->index_sid, pack->index_byte_count,
pack->body_sid, pack->body_offset,
mxf_ul_to_string (&pack->operational_pattern, str),
pack->n_essence_containers);
for (i = 0; i < pack->n_essence_containers; i++) {
GST_DEBUG (" essence container %d = %s", i,
mxf_ul_to_string (&pack->essence_containers[i], str));
}
return TRUE;
error:
GST_ERROR ("Invalid partition pack");
mxf_partition_pack_reset (pack);
return FALSE;
}
void
mxf_partition_pack_reset (MXFPartitionPack * pack)
{
g_return_if_fail (pack != NULL);
g_free (pack->essence_containers);
memset (pack, 0, sizeof (MXFPartitionPack));
}
/* SMPTE 377M 8.2 Table 1 and 2 */
static void
_mxf_mapping_ul_free (MXFUL * ul)
{
g_slice_free (MXFUL, ul);
}
gboolean
mxf_primer_pack_parse (const MXFUL * key, MXFPrimerPack * pack,
const guint8 * data, guint size)
{
gint i;
guint32 n;
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (size >= 8, FALSE);
memset (pack, 0, sizeof (MXFPrimerPack));
pack->mappings =
g_hash_table_new_full (g_direct_hash, g_direct_equal,
(GDestroyNotify) NULL, (GDestroyNotify) _mxf_mapping_ul_free);
n = GST_READ_UINT32_BE (data);
data += 4;
if (GST_READ_UINT32_BE (data) != 18)
goto error;
data += 4;
if (size < 8 + n * 18)
goto error;
GST_DEBUG ("Parsed primer pack:");
for (i = 0; i < n; i++) {
guint local_tag;
gchar str[48];
MXFUL *uid;
local_tag = GST_READ_UINT16_BE (data);
data += 2;
if (g_hash_table_lookup (pack->mappings, GUINT_TO_POINTER (local_tag)))
continue;
uid = g_slice_new (MXFUL);
memcpy (uid, data, 16);
data += 16;
g_hash_table_insert (pack->mappings, GUINT_TO_POINTER (local_tag), uid);
GST_DEBUG (" Adding primer pack association: 0x%04x -> %s", local_tag,
mxf_ul_to_string (uid, str));
}
pack->valid = TRUE;
return TRUE;
error:
GST_DEBUG ("Invalid primer pack");
mxf_primer_pack_reset (pack);
return FALSE;
}
void
mxf_primer_pack_reset (MXFPrimerPack * pack)
{
g_return_if_fail (pack != NULL);
if (pack->mappings)
g_hash_table_destroy (pack->mappings);
memset (pack, 0, sizeof (MXFPrimerPack));
}
/* structural metadata parsing */
gboolean
mxf_local_tag_parse (const guint8 * data, guint size, guint16 * tag,
guint16 * tag_size, const guint8 ** tag_data)
{
g_return_val_if_fail (data != NULL, FALSE);
if (size < 4)
return FALSE;
*tag = GST_READ_UINT16_BE (data);
*tag_size = GST_READ_UINT16_BE (data + 2);
if (size < 4 + *tag_size)
return FALSE;
*tag_data = data + 4;
return TRUE;
}
void
gst_mxf_local_tag_free (MXFLocalTag * tag)
{
g_free (tag->data);
g_slice_free (MXFLocalTag, tag);
}
gboolean
gst_metadata_add_custom_tag (const MXFPrimerPack * primer,
guint16 tag, const guint8 * tag_data, guint16 tag_size,
GHashTable ** hash_table)
{
MXFLocalTag *local_tag;
MXFUL *key;
g_return_val_if_fail (primer != NULL, FALSE);
g_return_val_if_fail (tag_data != NULL, FALSE);
g_return_val_if_fail (hash_table != NULL, FALSE);
g_return_val_if_fail (primer->mappings != NULL, FALSE);
if (*hash_table == NULL)
*hash_table =
g_hash_table_new_full ((GHashFunc) gst_mxf_ul_hash,
(GEqualFunc) gst_mxf_ul_equal, (GDestroyNotify) NULL,
(GDestroyNotify) gst_mxf_local_tag_free);
g_return_val_if_fail (*hash_table != NULL, FALSE);
key = (MXFUL *) g_hash_table_lookup (primer->mappings,
GUINT_TO_POINTER (((guint) tag)));
if (key) {
gchar str[48];
GST_DEBUG ("Adding local tag 0x%04x with UL %s and size %u", tag,
mxf_ul_to_string (key, str), tag_size);
local_tag = g_slice_new (MXFLocalTag);
memcpy (&local_tag->key, key, sizeof (MXFUL));
local_tag->size = tag_size;
local_tag->data = g_memdup (tag_data, tag_size);
g_hash_table_insert (*hash_table, &local_tag->key, local_tag);
} else {
GST_WARNING ("Local tag with no entry in primer pack: 0x%04x", tag);
}
return TRUE;
}
/* All following defined in SMPTE 377M Annex A, B, C, D */
gboolean
mxf_metadata_preface_parse (const MXFUL * key,
MXFMetadataPreface * preface, const MXFPrimerPack * primer,
const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (preface, 0, sizeof (MXFMetadataPreface));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&preface->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&preface->generation_uid, tag_data, 16);
break;
case 0x3b02:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_timestamp_parse (&preface->last_modified_date, tag_data,
tag_size))
goto error;
break;
case 0x3b05:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 2)
goto error;
preface->version = GST_READ_UINT16_BE (tag_data);
break;
case 0x3b07:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
preface->object_model_version = GST_READ_UINT32_BE (tag_data);
break;
case 0x3b08:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&preface->primary_package_uid, tag_data, 16);
break;
case 0x3b06:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
preface->n_identifications = len;
preface->identifications_uids = g_new (MXFUL, len);
for (i = 0; i < len; i++)
memcpy (&preface->identifications_uids[i], tag_data + 8 + i * 16, 16);
break;
}
case 0x3b03:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&preface->content_storage_uid, tag_data, 16);
break;
case 0x3b09:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&preface->operational_pattern, tag_data, 16);
break;
case 0x3b0a:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
preface->n_essence_containers = len;
preface->essence_containers = g_new (MXFUL, len);
for (i = 0; i < len; i++)
memcpy (&preface->essence_containers[i], tag_data + 8 + i * 16, 16);
break;
}
case 0x3b0b:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
preface->n_dm_schemes = len;
preface->dm_schemes = g_new (MXFUL, len);
for (i = 0; i < len; i++)
memcpy (&preface->dm_schemes[i], tag_data + 8 + i * 16, 16);
break;
}
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&preface->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed preface:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&preface->instance_uid,
str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&preface->generation_uid, str));
GST_DEBUG (" last modified date = %d/%u/%u %u:%u:%u.%u",
preface->last_modified_date.year, preface->last_modified_date.month,
preface->last_modified_date.day, preface->last_modified_date.hour,
preface->last_modified_date.minute, preface->last_modified_date.second,
(preface->last_modified_date.quarter_msecond * 1000) / 256);
GST_DEBUG (" version = %u.%u", (preface->version >> 8),
(preface->version & 0x0f));
GST_DEBUG (" object model version = %u", preface->object_model_version);
GST_DEBUG (" primary package = %s",
mxf_ul_to_string (&preface->primary_package_uid, str));
GST_DEBUG (" content storage = %s",
mxf_ul_to_string (&preface->content_storage_uid, str));
GST_DEBUG (" operational pattern = %s",
mxf_ul_to_string (&preface->operational_pattern, str));
GST_DEBUG (" number of identifications = %u", preface->n_identifications);
GST_DEBUG (" number of essence containers = %u",
preface->n_essence_containers);
GST_DEBUG (" number of DM schemes = %u", preface->n_dm_schemes);
for (i = 0; i < preface->n_identifications; i++)
GST_DEBUG (" identification %d = %s", i,
mxf_ul_to_string (&preface->identifications_uids[i], str));
for (i = 0; i < preface->n_essence_containers; i++)
GST_DEBUG (" essence container %d = %s", i,
mxf_ul_to_string (&preface->essence_containers[i], str));
for (i = 0; i < preface->n_dm_schemes; i++)
GST_DEBUG (" DM schemes %d = %s", i,
mxf_ul_to_string (&preface->dm_schemes[i], str));
return TRUE;
error:
GST_ERROR ("Invalid preface");
mxf_metadata_preface_reset (preface);
return FALSE;
}
void
mxf_metadata_preface_reset (MXFMetadataPreface * preface)
{
g_return_if_fail (preface != NULL);
g_free (preface->identifications_uids);
g_free (preface->identifications);
g_free (preface->essence_containers);
g_free (preface->dm_schemes);
if (preface->other_tags)
g_hash_table_destroy (preface->other_tags);
memset (preface, 0, sizeof (MXFMetadataPreface));
}
gboolean
mxf_metadata_identification_parse (const MXFUL * key,
MXFMetadataIdentification * identification,
const MXFPrimerPack * primer, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (identification, 0, sizeof (MXFMetadataIdentification));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&identification->instance_uid, tag_data, 16);
break;
case 0x3c09:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&identification->generation_uid, tag_data, 16);
break;
case 0x3c01:
GST_WRITE_UINT16_BE (data, 0x0000);
identification->company_name = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
case 0x3c02:
GST_WRITE_UINT16_BE (data, 0x0000);
identification->product_name = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
case 0x3c03:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 10)
goto error;
if (!mxf_product_version_parse (&identification->product_version,
tag_data, tag_size))
goto error;
break;
case 0x3c04:
GST_WRITE_UINT16_BE (data, 0x0000);
identification->version_string = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
case 0x3c05:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&identification->product_uid, tag_data, 16);
break;
case 0x3c06:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
if (!mxf_timestamp_parse (&identification->modification_date, tag_data,
tag_size))
goto error;
break;
case 0x3c07:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 10)
goto error;
if (!mxf_product_version_parse (&identification->toolkit_version,
tag_data, tag_size))
goto error;
break;
case 0x3c08:
GST_WRITE_UINT16_BE (data, 0x0000);
identification->platform = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&identification->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed identification:");
GST_DEBUG (" instance uid = %s",
mxf_ul_to_string (&identification->instance_uid, str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&identification->generation_uid, str));
GST_DEBUG (" company name = %s",
GST_STR_NULL (identification->company_name));
GST_DEBUG (" product version = %u.%u.%u.%u.%u",
identification->product_version.major,
identification->product_version.minor,
identification->product_version.patch,
identification->product_version.build,
identification->product_version.release);
GST_DEBUG (" version string = %s",
GST_STR_NULL (identification->version_string));
GST_DEBUG (" product uid = %s",
mxf_ul_to_string (&identification->product_uid, str));
GST_DEBUG (" modification date = %d/%u/%u %u:%u:%u.%u",
identification->modification_date.year,
identification->modification_date.month,
identification->modification_date.day,
identification->modification_date.hour,
identification->modification_date.minute,
identification->modification_date.second,
(identification->modification_date.quarter_msecond * 1000) / 256);
GST_DEBUG (" toolkit version = %u.%u.%u.%u.%u",
identification->toolkit_version.major,
identification->toolkit_version.minor,
identification->toolkit_version.patch,
identification->toolkit_version.build,
identification->toolkit_version.release);
GST_DEBUG (" platform = %s", GST_STR_NULL (identification->platform));
return TRUE;
error:
GST_ERROR ("Invalid identification");
mxf_metadata_identification_reset (identification);
return FALSE;
}
void mxf_metadata_identification_reset
(MXFMetadataIdentification * identification)
{
g_return_if_fail (identification != NULL);
g_free (identification->company_name);
g_free (identification->product_name);
g_free (identification->version_string);
g_free (identification->platform);
if (identification->other_tags)
g_hash_table_destroy (identification->other_tags);
memset (identification, 0, sizeof (MXFMetadataIdentification));
}
gboolean
mxf_metadata_content_storage_parse (const MXFUL * key,
MXFMetadataContentStorage * content_storage,
const MXFPrimerPack * primer, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (content_storage, 0, sizeof (MXFMetadataContentStorage));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&content_storage->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&content_storage->generation_uid, tag_data, 16);
break;
case 0x1901:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
content_storage->packages_uids = g_new (MXFUL, len);
content_storage->n_packages = len;
for (i = 0; i < len; i++)
memcpy (&content_storage->packages_uids[i], tag_data + 8 + i * 16,
16);
break;
}
case 0x1902:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
content_storage->essence_container_data_uids = g_new (MXFUL, len);
content_storage->n_essence_container_data = len;
for (i = 0; i < len; i++)
memcpy (&content_storage->essence_container_data_uids[i],
tag_data + 8 + i * 16, 16);
break;
}
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&content_storage->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed content storage:");
GST_DEBUG (" instance uid = %s",
mxf_ul_to_string (&content_storage->instance_uid, str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&content_storage->generation_uid, str));
GST_DEBUG (" number of packages = %u", content_storage->n_packages);
GST_DEBUG (" number of essence container data = %u",
content_storage->n_essence_container_data);
for (i = 0; i < content_storage->n_packages; i++)
GST_DEBUG (" package %i = %s", i,
mxf_ul_to_string (&content_storage->packages_uids[i], str));
for (i = 0; i < content_storage->n_packages; i++)
GST_DEBUG (" essence container data %i = %s", i,
mxf_ul_to_string (&content_storage->essence_container_data_uids[i],
str));
return TRUE;
error:
GST_ERROR ("Invalid content storage");
mxf_metadata_content_storage_reset (content_storage);
return FALSE;
}
void mxf_metadata_content_storage_reset
(MXFMetadataContentStorage * content_storage)
{
g_return_if_fail (content_storage != NULL);
g_free (content_storage->packages);
g_free (content_storage->packages_uids);
g_free (content_storage->essence_container_data);
g_free (content_storage->essence_container_data_uids);
if (content_storage->other_tags)
g_hash_table_destroy (content_storage->other_tags);
memset (content_storage, 0, sizeof (MXFMetadataContentStorage));
}
gboolean
mxf_metadata_essence_container_data_parse (const MXFUL * key,
MXFMetadataEssenceContainerData * essence_container_data,
const MXFPrimerPack * primer, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[96];
g_return_val_if_fail (data != NULL, FALSE);
memset (essence_container_data, 0, sizeof (MXFMetadataEssenceContainerData));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&essence_container_data->instance_uid, tag_data, 16);
break;
case 0x2701:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 32)
goto error;
memcpy (&essence_container_data->linked_package_uid, tag_data, 32);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&essence_container_data->generation_uid, tag_data, 16);
break;
case 0x3f06:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
essence_container_data->index_sid = GST_READ_UINT32_BE (tag_data);
break;
case 0x3f07:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
essence_container_data->body_sid = GST_READ_UINT32_BE (tag_data);
break;
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&essence_container_data->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed essence container data:");
GST_DEBUG (" instance uid = %s",
mxf_ul_to_string (&essence_container_data->instance_uid, str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&essence_container_data->generation_uid, str));
GST_DEBUG (" linked package = %s",
mxf_umid_to_string (&essence_container_data->linked_package_uid, str));
GST_DEBUG (" index sid = %u", essence_container_data->index_sid);
GST_DEBUG (" body sid = %u", essence_container_data->body_sid);
return TRUE;
error:
GST_ERROR ("Invalid essence container data");
mxf_metadata_essence_container_data_reset (essence_container_data);
return FALSE;
}
void mxf_metadata_essence_container_data_reset
(MXFMetadataEssenceContainerData * essence_container_data)
{
g_return_if_fail (essence_container_data != NULL);
if (essence_container_data->other_tags)
g_hash_table_destroy (essence_container_data->other_tags);
memset (essence_container_data, 0, sizeof (MXFMetadataEssenceContainerData));
}
gboolean
mxf_metadata_generic_package_parse (const MXFUL * key,
MXFMetadataGenericPackage * generic_package,
const MXFPrimerPack * primer, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[96];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (generic_package, 0, sizeof (MXFMetadataGenericPackage));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&generic_package->instance_uid, tag_data, 16);
break;
case 0x4401:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 32)
goto error;
memcpy (&generic_package->package_uid, tag_data, 32);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&generic_package->generation_uid, tag_data, 16);
break;
case 0x4402:
generic_package->name = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
case 0x4405:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_timestamp_parse (&generic_package->package_creation_date,
tag_data, tag_size))
goto error;
break;
case 0x4404:
if (!mxf_timestamp_parse (&generic_package->package_modified_date,
tag_data, tag_size))
goto error;
break;
case 0x4403:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
generic_package->tracks_uids = g_new (MXFUL, len);
generic_package->n_tracks = len;
for (i = 0; i < len; i++)
memcpy (&generic_package->tracks_uids[i], tag_data + 8 + i * 16, 16);
break;
}
case 0x4701:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
generic_package->n_descriptors = 1;
memcpy (&generic_package->descriptors_uid, tag_data, 16);
break;
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&generic_package->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed package:");
GST_DEBUG (" instance uid = %s",
mxf_ul_to_string (&generic_package->instance_uid, str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&generic_package->generation_uid, str));
GST_DEBUG (" UMID = %s", mxf_umid_to_string (&generic_package->package_uid,
str));
GST_DEBUG (" name = %s", GST_STR_NULL (generic_package->name));
GST_DEBUG (" creation date = %d/%u/%u %u:%u:%u.%u",
generic_package->package_creation_date.year,
generic_package->package_creation_date.month,
generic_package->package_creation_date.day,
generic_package->package_creation_date.hour,
generic_package->package_creation_date.minute,
generic_package->package_creation_date.second,
(generic_package->package_creation_date.quarter_msecond * 1000) / 256);
GST_DEBUG (" modification date = %d/%u/%u %u:%u:%u.%u",
generic_package->package_modified_date.year,
generic_package->package_modified_date.month,
generic_package->package_modified_date.day,
generic_package->package_modified_date.hour,
generic_package->package_modified_date.minute,
generic_package->package_modified_date.second,
(generic_package->package_modified_date.quarter_msecond * 1000) / 256);
GST_DEBUG (" descriptor = %s",
mxf_ul_to_string (&generic_package->descriptors_uid, str));
GST_DEBUG (" number of tracks = %u", generic_package->n_tracks);
for (i = 0; i < generic_package->n_tracks; i++)
GST_DEBUG (" track %d = %s", i,
mxf_ul_to_string (&generic_package->tracks_uids[i], str));
return TRUE;
error:
GST_ERROR ("Invalid package");
mxf_metadata_generic_package_reset (generic_package);
return FALSE;
}
void mxf_metadata_generic_package_reset
(MXFMetadataGenericPackage * generic_package)
{
g_return_if_fail (generic_package != NULL);
g_free (generic_package->name);
g_free (generic_package->tracks_uids);
g_free (generic_package->tracks);
if (generic_package->other_tags)
g_hash_table_destroy (generic_package->other_tags);
g_free (generic_package->descriptors);
memset (generic_package, 0, sizeof (MXFMetadataGenericPackage));
}
gboolean
mxf_metadata_track_parse (const MXFUL * key,
MXFMetadataTrack * track, const MXFPrimerPack * primer,
const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (track, 0, sizeof (MXFMetadataTrack));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&track->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&track->generation_uid, tag_data, 16);
break;
case 0x4801:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
track->track_id = GST_READ_UINT32_BE (tag_data);
break;
case 0x4804:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
track->track_number = GST_READ_UINT32_BE (tag_data);
break;
case 0x4802:
GST_WRITE_UINT16_BE (data, 0x0000);
track->track_name = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
case 0x4b01:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_fraction_parse (&track->edit_rate, tag_data, tag_size))
goto error;
break;
case 0x4b02:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
track->origin = GST_READ_UINT64_BE (tag_data);
break;
case 0x4803:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&track->sequence_uid, tag_data, 16);
break;
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&track->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed track:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&track->instance_uid,
str));
GST_DEBUG (" generation uid = %s", mxf_ul_to_string (&track->generation_uid,
str));
GST_DEBUG (" track id = %u", track->track_id);
GST_DEBUG (" track number = %u", track->track_number);
GST_DEBUG (" track name = %s", GST_STR_NULL (track->track_name));
GST_DEBUG (" edit rate = %d/%d", track->edit_rate.n, track->edit_rate.d);
GST_DEBUG (" origin = %" G_GINT64_FORMAT, track->origin);
GST_DEBUG (" sequence uid = %s", mxf_ul_to_string (&track->sequence_uid,
str));
return TRUE;
error:
GST_ERROR ("Invalid track");
mxf_metadata_track_reset (track);
return FALSE;
}
void
mxf_metadata_track_reset (MXFMetadataTrack * track)
{
g_return_if_fail (track != NULL);
g_free (track->track_name);
if (track->descriptor)
g_free (track->descriptor);
if (track->other_tags)
g_hash_table_destroy (track->other_tags);
memset (track, 0, sizeof (MXFMetadataTrack));
}
/* SMPTE RP224 */
static const struct
{
guint8 ul[16];
MXFMetadataTrackType type;
} mxf_metadata_track_identifier[] = {
{ {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
0x01, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00},
MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_TIMECODE_12M_ACTIVE}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
0x03, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_TIMECODE_309M}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
0x10, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_METADATA}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
0x01, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_PICTURE_ESSENCE}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_SOUND_ESSENCE}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
0x03, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_DATA_ESSENCE}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03,
0x01, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_AUXILIARY_DATA}, { {
0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03,
0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_PARSED_TEXT}
};
MXFMetadataTrackType
mxf_metadata_track_identifier_parse (const MXFUL * track_identifier)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (mxf_metadata_track_identifier); i++)
if (memcmp (&mxf_metadata_track_identifier[i].ul, &track_identifier->u,
16) == 0)
return mxf_metadata_track_identifier[i].type;
return MXF_METADATA_TRACK_UNKNOWN;
}
gboolean
mxf_metadata_sequence_parse (const MXFUL * key,
MXFMetadataSequence * sequence, const MXFPrimerPack * primer,
const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (sequence, 0, sizeof (MXFMetadataSequence));
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&sequence->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&sequence->generation_uid, tag_data, 16);
break;
case 0x0201:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&sequence->data_definition, tag_data, 16);
break;
case 0x0202:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
sequence->duration = GST_READ_UINT64_BE (tag_data);
break;
case 0x1001:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
break;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
if (tag_size < 8 + len * 16)
goto error;
sequence->structural_components_uids = g_new (MXFUL, len);
sequence->n_structural_components = len;
for (i = 0; i < len; i++)
memcpy (&sequence->structural_components_uids[i],
tag_data + 8 + i * 16, 16);
break;
}
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&sequence->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed sequence:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&sequence->instance_uid,
str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&sequence->generation_uid, str));
GST_DEBUG (" data definition = %s",
mxf_ul_to_string (&sequence->data_definition, str));
GST_DEBUG (" duration = %" G_GINT64_FORMAT, sequence->duration);
GST_DEBUG (" number of structural components = %u",
sequence->n_structural_components);
for (i = 0; i < sequence->n_structural_components; i++)
GST_DEBUG (" structural component %d = %s", i,
mxf_ul_to_string (&sequence->structural_components_uids[i], str));
return TRUE;
error:
GST_ERROR ("Invalid sequence");
mxf_metadata_sequence_reset (sequence);
return FALSE;
}
void
mxf_metadata_sequence_reset (MXFMetadataSequence * sequence)
{
g_return_if_fail (sequence != NULL);
g_free (sequence->structural_components_uids);
g_free (sequence->structural_components);
if (sequence->other_tags)
g_hash_table_destroy (sequence->other_tags);
memset (sequence, 0, sizeof (MXFMetadataSequence));
}
gboolean
mxf_metadata_structural_component_parse (const MXFUL * key,
MXFMetadataStructuralComponent * component,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[96];
g_return_val_if_fail (data != NULL, FALSE);
memset (component, 0, sizeof (MXFMetadataStructuralComponent));
component->type = type;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&component->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&component->generation_uid, tag_data, 16);
break;
case 0x0201:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&component->data_definition, tag_data, 16);
break;
case 0x0202:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
component->duration = GST_READ_UINT64_BE (tag_data);
break;
/* Timecode component specifics */
case 0x1502:
if (type != MXF_METADATA_TIMECODE_COMPONENT)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 2)
goto error;
component->timecode_component.rounded_timecode_base =
GST_READ_UINT16_BE (tag_data);
break;
case 0x1501:
if (type != MXF_METADATA_TIMECODE_COMPONENT)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
component->timecode_component.start_timecode =
GST_READ_UINT64_BE (tag_data);
break;
case 0x1503:
if (type != MXF_METADATA_TIMECODE_COMPONENT)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
component->timecode_component.drop_frame =
(GST_READ_UINT8 (tag_data) != 0);
break;
/* Source clip specifics */
case 0x1201:
if (type != MXF_METADATA_SOURCE_CLIP)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
component->source_clip.start_position = GST_READ_UINT64_BE (tag_data);
break;
case 0x1101:
if (type != MXF_METADATA_SOURCE_CLIP)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 32)
goto error;
memcpy (&component->source_clip.source_package_id, tag_data, 32);
break;
case 0x1102:
if (type != MXF_METADATA_SOURCE_CLIP)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
component->source_clip.source_track_id = GST_READ_UINT32_BE (tag_data);
break;
DFLT:
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&component->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed structural component:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&component->instance_uid,
str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&component->generation_uid, str));
GST_DEBUG (" type = %s",
(component->type ==
MXF_METADATA_TIMECODE_COMPONENT) ? "timecode component" :
"source clip");
GST_DEBUG (" data definition = %s",
mxf_ul_to_string (&component->data_definition, str));
GST_DEBUG (" duration = %" G_GINT64_FORMAT, component->duration);
if (component->type == MXF_METADATA_TIMECODE_COMPONENT) {
GST_DEBUG (" start timecode = %" G_GINT64_FORMAT,
component->timecode_component.start_timecode);
GST_DEBUG (" rounded timecode base = %u",
component->timecode_component.rounded_timecode_base);
GST_DEBUG (" drop frame = %s",
(component->timecode_component.drop_frame) ? "yes" : "no");
} else {
GST_DEBUG (" start position = %" G_GINT64_FORMAT,
component->source_clip.start_position);
GST_DEBUG (" source package id = %s",
mxf_umid_to_string (&component->source_clip.source_package_id, str));
GST_DEBUG (" source track id = %u",
component->source_clip.source_track_id);
}
return TRUE;
error:
GST_ERROR ("Invalid structural component");
mxf_metadata_structural_component_reset (component);
return FALSE;
}
void mxf_metadata_structural_component_reset
(MXFMetadataStructuralComponent * component)
{
g_return_if_fail (component != NULL);
if (component->other_tags)
g_hash_table_destroy (component->other_tags);
memset (component, 0, sizeof (MXFMetadataStructuralComponent));
}
gboolean
mxf_metadata_generic_descriptor_parse (const MXFUL * key,
MXFMetadataGenericDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataGenericDescriptor));
descriptor->type = type;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->generation_uid, tag_data, 16);
break;
case 0x2f01:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
goto next;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
descriptor->locators_uids = g_new (MXFUL, len);
descriptor->n_locators = len;
for (i = 0; i < len; i++)
memcpy (&descriptor->locators_uids[i], tag_data + 8 + i * 16, 16);
break;
}
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed generic descriptor:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&descriptor->instance_uid,
str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&descriptor->generation_uid, str));
GST_DEBUG (" type = %u", descriptor->type);
GST_DEBUG (" number of locators = %u", descriptor->n_locators);
for (i = 0; i < descriptor->n_locators; i++)
GST_DEBUG (" locator %d = %s", i,
mxf_ul_to_string (&descriptor->locators_uids[i], str));
return TRUE;
error:
GST_ERROR ("Invalid generic descriptor");
mxf_metadata_generic_descriptor_reset (descriptor);
return FALSE;
}
void mxf_metadata_generic_descriptor_reset
(MXFMetadataGenericDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
switch (descriptor->type) {
case MXF_METADATA_FILE_DESCRIPTOR:
break;
}
if (descriptor->locators_uids)
g_free (descriptor->locators_uids);
if (descriptor->locators)
g_free (descriptor->locators);
if (descriptor->other_tags)
g_hash_table_destroy (descriptor->other_tags);
memset (descriptor, 0, sizeof (MXFMetadataGenericDescriptor));
}
gboolean
mxf_metadata_file_descriptor_parse (const MXFUL * key,
MXFMetadataFileDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataFileDescriptor));
if (!mxf_metadata_generic_descriptor_parse (key,
(MXFMetadataGenericDescriptor *) descriptor, primer, type, data,
size))
goto error;
descriptor->parent.is_file_descriptor = TRUE;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3006:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->linked_track_id = GST_READ_UINT32_BE (tag_data);
break;
case 0x3001:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_fraction_parse (&descriptor->sample_rate, tag_data, tag_size))
goto error;
break;
case 0x3002:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 8)
goto error;
descriptor->container_duration = GST_READ_UINT64_BE (tag_data);
break;
case 0x3004:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->essence_container, tag_data, 16);
break;
case 0x3005:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->codec, tag_data, 16);
break;
default:
if (type != MXF_METADATA_FILE_DESCRIPTOR)
goto next;
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed file descriptor:");
GST_DEBUG (" linked track id = %u", descriptor->linked_track_id);
GST_DEBUG (" sample rate = %d/%d", descriptor->sample_rate.n,
descriptor->sample_rate.d);
GST_DEBUG (" container duration = %" G_GINT64_FORMAT,
descriptor->container_duration);
GST_DEBUG (" essence container = %s",
mxf_ul_to_string (&descriptor->essence_container, str));
GST_DEBUG (" codec = %s", mxf_ul_to_string (&descriptor->codec, str));
return TRUE;
error:
GST_ERROR ("Invalid file descriptor");
mxf_metadata_file_descriptor_reset (descriptor);
return FALSE;
}
void
mxf_metadata_file_descriptor_reset (MXFMetadataFileDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
mxf_metadata_generic_descriptor_reset ((MXFMetadataGenericDescriptor *)
descriptor);
memset (descriptor, 0, sizeof (MXFMetadataFileDescriptor));
}
gboolean
mxf_metadata_generic_sound_essence_descriptor_parse (const MXFUL * key,
MXFMetadataGenericSoundEssenceDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataGenericSoundEssenceDescriptor));
if (!mxf_metadata_file_descriptor_parse (key,
(MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
goto error;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3d03:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_fraction_parse (&descriptor->audio_sampling_rate, tag_data,
tag_size))
goto error;
break;
case 0x3d02:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->locked = (GST_READ_UINT8 (tag_data) != 0);
break;
case 0x3d04:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->audio_ref_level = GST_READ_UINT8 (tag_data);
break;
case 0x3d05:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->electro_spatial_formulation = GST_READ_UINT8 (tag_data);
break;
case 0x3d07:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->channel_count = GST_READ_UINT32_BE (tag_data);
break;
case 0x3d01:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->quantization_bits = GST_READ_UINT32_BE (tag_data);
break;
case 0x3d0c:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->dial_norm = GST_READ_UINT8 (tag_data);
break;
case 0x3d06:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->sound_essence_compression, tag_data, 16);
break;
default:
if (type != MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR)
goto next;
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed generic sound essence descriptor:");
GST_DEBUG (" audio sampling rate = %d/%d", descriptor->audio_sampling_rate.n,
descriptor->audio_sampling_rate.d);
GST_DEBUG (" locked = %s", (descriptor->locked) ? "yes" : "no");
GST_DEBUG (" audio ref level = %d", descriptor->audio_ref_level);
GST_DEBUG (" electro spatial formulation = %u",
descriptor->electro_spatial_formulation);
GST_DEBUG (" channel count = %u", descriptor->channel_count);
GST_DEBUG (" quantization bits = %u", descriptor->quantization_bits);
GST_DEBUG (" dial norm = %d", descriptor->dial_norm);
GST_DEBUG (" sound essence compression = %s",
mxf_ul_to_string (&descriptor->sound_essence_compression, str));
return TRUE;
error:
GST_ERROR ("Invalid generic sound essence descriptor");
mxf_metadata_generic_sound_essence_descriptor_reset (descriptor);
return FALSE;
}
void mxf_metadata_generic_sound_essence_descriptor_reset
(MXFMetadataGenericSoundEssenceDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
memset (descriptor, 0, sizeof (MXFMetadataGenericSoundEssenceDescriptor));
}
gboolean
mxf_metadata_generic_picture_essence_descriptor_parse (const MXFUL * key,
MXFMetadataGenericPictureEssenceDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataGenericPictureEssenceDescriptor));
if (!mxf_metadata_file_descriptor_parse (key,
(MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
goto error;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3215:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->signal_standard = GST_READ_UINT8 (tag_data);
break;
case 0x320c:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->frame_layout = GST_READ_UINT8 (tag_data);
break;
case 0x3203:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->stored_width = GST_READ_UINT32_BE (tag_data);
break;
case 0x3202:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->stored_height = GST_READ_UINT32_BE (tag_data);
break;
case 0x3216:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->stored_f2_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3205:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->sampled_width = GST_READ_UINT32_BE (tag_data);
break;
case 0x3204:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->sampled_height = GST_READ_UINT32_BE (tag_data);
break;
case 0x3206:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->sampled_x_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3207:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->sampled_y_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3208:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->display_height = GST_READ_UINT32_BE (tag_data);
break;
case 0x3209:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->display_width = GST_READ_UINT32_BE (tag_data);
break;
case 0x320a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->display_x_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x320b:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->display_y_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3217:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->display_f2_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x320e:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!mxf_fraction_parse (&descriptor->aspect_ratio, tag_data, tag_size))
goto error;
break;
case 0x3218:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->active_format_descriptor = GST_READ_UINT8 (tag_data);
break;
case 0x320d:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
if (GST_READ_UINT32_BE (tag_data) == 0)
goto next;
if (GST_READ_UINT32_BE (tag_data) != 2 &&
GST_READ_UINT32_BE (tag_data + 4) != 4)
goto error;
if (tag_size != 16)
goto error;
descriptor->video_line_map[0] = GST_READ_UINT32_BE (tag_data + 8);
descriptor->video_line_map[1] = GST_READ_UINT32_BE (tag_data + 12);
break;
case 0x320f:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->alpha_transparency = GST_READ_UINT8 (tag_data);
break;
case 0x3210:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->capture_gamma, tag_data, 16);
break;
case 0x3211:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->image_alignment_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3213:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->image_start_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3214:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->image_end_offset = GST_READ_UINT32_BE (tag_data);
break;
case 0x3212:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->field_dominance = GST_READ_UINT8 (tag_data);
break;
case 0x3201:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&descriptor->picture_essence_coding, tag_data, 16);
break;
default:
if (type != MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR)
goto next;
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed generic picture essence descriptor:");
GST_DEBUG (" signal standard = %u", descriptor->signal_standard);
GST_DEBUG (" frame layout = %u", descriptor->frame_layout);
GST_DEBUG (" stored size = %ux%u (f2 = %d)", descriptor->stored_width,
descriptor->stored_height, descriptor->stored_f2_offset);
GST_DEBUG (" sampled size = %ux%u (offset = %d x %d)",
descriptor->sampled_width, descriptor->sampled_height,
descriptor->sampled_x_offset, descriptor->sampled_y_offset);
GST_DEBUG (" display size = %ux%u (f2 = %d, offset = %d x %d)",
descriptor->display_height, descriptor->display_width,
descriptor->display_x_offset, descriptor->display_y_offset,
descriptor->display_f2_offset);
GST_DEBUG (" aspect ratio = %d/%d", descriptor->aspect_ratio.n,
descriptor->aspect_ratio.d);
GST_DEBUG (" active format descriptor = %u",
descriptor->active_format_descriptor);
GST_DEBUG (" video line map = {%i, %i}", descriptor->video_line_map[0],
descriptor->video_line_map[1]);
GST_DEBUG (" alpha transparency = %u", descriptor->alpha_transparency);
GST_DEBUG (" capture gamma = %s",
mxf_ul_to_string (&descriptor->capture_gamma, str));
GST_DEBUG (" image alignment offset = %u",
descriptor->image_alignment_offset);
GST_DEBUG (" image start offset = %u", descriptor->image_start_offset);
GST_DEBUG (" image end offset = %u", descriptor->image_end_offset);
GST_DEBUG (" field dominance = %u", descriptor->field_dominance);
GST_DEBUG (" picture essence coding = %s",
mxf_ul_to_string (&descriptor->picture_essence_coding, str));
return TRUE;
error:
GST_ERROR ("Invalid generic picture essence descriptor");
mxf_metadata_generic_picture_essence_descriptor_reset (descriptor);
return FALSE;
}
void mxf_metadata_generic_picture_essence_descriptor_reset
(MXFMetadataGenericPictureEssenceDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
memset (descriptor, 0, sizeof (MXFMetadataGenericPictureEssenceDescriptor));
}
gboolean
mxf_metadata_cdci_picture_essence_descriptor_parse (const MXFUL * key,
MXFMetadataCDCIPictureEssenceDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
if (!mxf_metadata_generic_picture_essence_descriptor_parse (key,
(MXFMetadataGenericPictureEssenceDescriptor *) descriptor, primer,
type, data, size))
goto error;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3301:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->component_depth = GST_READ_UINT32_BE (tag_data);
break;
case 0x3302:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->horizontal_subsampling = GST_READ_UINT32_BE (tag_data);
break;
case 0x3308:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->vertical_subsampling = GST_READ_UINT32_BE (tag_data);
break;
case 0x3303:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->color_siting = GST_READ_UINT8 (tag_data);
break;
case 0x330b:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 1)
goto error;
descriptor->reversed_byte_order = GST_READ_UINT8 (tag_data);
break;
case 0x3307:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 2)
goto error;
descriptor->padding_bits = GST_READ_UINT16_BE (tag_data);
break;
case 0x3309:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->alpha_sample_depth = GST_READ_UINT32_BE (tag_data);
break;
case 0x3304:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->black_ref_level = GST_READ_UINT32_BE (tag_data);
break;
case 0x3305:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->white_ref_level = GST_READ_UINT32_BE (tag_data);
break;
case 0x3306:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 4)
goto error;
descriptor->color_range = GST_READ_UINT32_BE (tag_data);
break;
default:
if (type != MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR)
goto next;
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed CDCI picture essence descriptor:");
GST_DEBUG (" component depth = %u", descriptor->component_depth);
GST_DEBUG (" horizontal subsampling = %u",
descriptor->horizontal_subsampling);
GST_DEBUG (" vertical subsampling = %u", descriptor->vertical_subsampling);
GST_DEBUG (" color siting = %u", descriptor->color_siting);
GST_DEBUG (" reversed byte order = %s",
(descriptor->reversed_byte_order) ? "yes" : "no");
GST_DEBUG (" padding bits = %d", descriptor->padding_bits);
GST_DEBUG (" alpha sample depth = %u", descriptor->alpha_sample_depth);
GST_DEBUG (" black ref level = %u", descriptor->black_ref_level);
GST_DEBUG (" white ref level = %u", descriptor->white_ref_level);
GST_DEBUG (" color range = %u", descriptor->color_range);
return TRUE;
error:
GST_ERROR ("Invalid CDCI picture essence descriptor");
mxf_metadata_cdci_picture_essence_descriptor_reset (descriptor);
return FALSE;
}
void mxf_metadata_cdci_picture_essence_descriptor_reset
(MXFMetadataCDCIPictureEssenceDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
mxf_metadata_generic_picture_essence_descriptor_reset (
(MXFMetadataGenericPictureEssenceDescriptor *) descriptor);
memset (descriptor, 0, sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
}
gboolean
mxf_metadata_multiple_descriptor_parse (const MXFUL * key,
MXFMetadataMultipleDescriptor * descriptor,
const MXFPrimerPack * primer, guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
gint i;
g_return_val_if_fail (data != NULL, FALSE);
memset (descriptor, 0, sizeof (MXFMetadataMultipleDescriptor));
if (!mxf_metadata_file_descriptor_parse (key,
(MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
goto error;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3f01:{
guint32 len;
guint i;
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size < 8)
goto error;
len = GST_READ_UINT32_BE (tag_data);
if (len == 0)
goto next;
if (GST_READ_UINT32_BE (tag_data + 4) != 16)
goto error;
descriptor->n_sub_descriptors = len;
descriptor->sub_descriptors_uids = g_new0 (MXFUL, len);
for (i = 0; i < len; i++)
memcpy (&descriptor->sub_descriptors_uids[i], tag_data + 8 + i * 16,
16);
break;
}
default:
if (type != MXF_METADATA_MULTIPLE_DESCRIPTOR)
goto next;
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed multiple descriptor:");
GST_DEBUG (" number of sub descriptors = %u", descriptor->n_sub_descriptors);
for (i = 0; i < descriptor->n_sub_descriptors; i++)
GST_DEBUG (" sub descriptor %d = %s", i,
mxf_ul_to_string (&descriptor->sub_descriptors_uids[i], str));
return TRUE;
error:
GST_ERROR ("Invalid multiple descriptor");
mxf_metadata_multiple_descriptor_reset (descriptor);
return FALSE;
}
void mxf_metadata_multiple_descriptor_reset
(MXFMetadataMultipleDescriptor * descriptor)
{
g_return_if_fail (descriptor != NULL);
g_free (descriptor->sub_descriptors_uids);
g_free (descriptor->sub_descriptors);
mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
memset (descriptor, 0, sizeof (MXFMetadataMultipleDescriptor));
}
gboolean
mxf_metadata_locator_parse (const MXFUL * key,
MXFMetadataLocator * locator, const MXFPrimerPack * primer,
guint16 type, const guint8 * data, guint size)
{
guint16 tag, tag_size;
const guint8 *tag_data;
gchar str[48];
g_return_val_if_fail (data != NULL, FALSE);
memset (locator, 0, sizeof (MXFMetadataLocator));
locator->type = type;
while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
if (tag_size == 0 || tag == 0x0000)
goto next;
switch (tag) {
case 0x3c0a:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&locator->instance_uid, tag_data, 16);
break;
case 0x0102:
GST_WRITE_UINT16_BE (data, 0x0000);
if (tag_size != 16)
goto error;
memcpy (&locator->generation_uid, tag_data, 16);
break;
case 0x4101:
if (type != MXF_METADATA_TEXT_LOCATOR
&& type != MXF_METADATA_NETWORK_LOCATOR)
goto DFLT;
GST_WRITE_UINT16_BE (data, 0x0000);
locator->location = mxf_utf16_to_utf8 (tag_data, tag_size);
break;
DFLT:
default:
GST_WRITE_UINT16_BE (data, 0x0000);
if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
&locator->other_tags))
goto error;
break;
}
next:
data += 4 + tag_size;
size -= 4 + tag_size;
}
GST_DEBUG ("Parsed locator:");
GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&locator->instance_uid,
str));
GST_DEBUG (" generation uid = %s",
mxf_ul_to_string (&locator->generation_uid, str));
GST_DEBUG (" location = %s", GST_STR_NULL (locator->location));
return TRUE;
error:
GST_ERROR ("Invalid locator");
mxf_metadata_locator_reset (locator);
return FALSE;
}
void
mxf_metadata_locator_reset (MXFMetadataLocator * locator)
{
g_return_if_fail (locator != NULL);
if (locator->location)
g_free (locator->location);
if (locator->other_tags)
g_hash_table_destroy (locator->other_tags);
memset (locator, 0, sizeof (MXFMetadataLocator));
}