📄 mxf.c
字号:
/* * MXF demuxer. * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *//* * References * SMPTE 336M KLV Data Encoding Protocol Using Key-Length-Value * SMPTE 377M MXF File Format Specifications * SMPTE 378M Operational Pattern 1a * SMPTE 379M MXF Generic Container * SMPTE 381M Mapping MPEG Streams into the MXF Generic Container * SMPTE 382M Mapping AES3 and Broadcast Wave Audio into the MXF Generic Container * SMPTE 383M Mapping DV-DIF Data to the MXF Generic Container * * Principle * Search for Track numbers which will identify essence element KLV packets. * Search for SourcePackage which define tracks which contains Track numbers. * Material Package contains tracks with reference to SourcePackage tracks. * Search for Descriptors (Picture, Sound) which contains codec info and parameters. * Assign Descriptors to correct Tracks. * * Metadata reading functions read Local Tags, get InstanceUID(0x3C0A) then add MetaDataSet to MXFContext. * Metadata parsing resolves Strong References to objects. * * Simple demuxer, only OP1A supported and some files might not work at all. * Only tracks with associated descriptors will be decoded. "Highly Desirable" SMPTE 377M D.1 *///#define DEBUG#include "avformat.h"#include "aes.h"#include "bytestream.h"typedef uint8_t UID[16];enum MXFMetadataSetType { AnyType, MaterialPackage, SourcePackage, SourceClip, TimecodeComponent, Sequence, MultipleDescriptor, Descriptor, Track, CryptoContext,};typedef struct { UID uid; enum MXFMetadataSetType type; UID context_uid; UID source_container_ul;} MXFCryptoContext;typedef struct { UID uid; enum MXFMetadataSetType type; UID source_package_uid; UID data_definition_ul; int64_t duration; int64_t start_position; int source_track_id;} MXFStructuralComponent;typedef struct { UID uid; enum MXFMetadataSetType type; UID data_definition_ul; UID *structural_components_refs; int structural_components_count; int64_t duration;} MXFSequence;typedef struct { UID uid; enum MXFMetadataSetType type; MXFSequence *sequence; /* mandatory, and only one */ UID sequence_ref; int track_id; uint8_t track_number[4]; AVRational edit_rate;} MXFTrack;typedef struct { UID uid; enum MXFMetadataSetType type; UID essence_container_ul; UID essence_codec_ul; AVRational sample_rate; AVRational aspect_ratio; int width; int height; int channels; int bits_per_sample; UID *sub_descriptors_refs; int sub_descriptors_count; int linked_track_id; uint8_t *extradata; int extradata_size;} MXFDescriptor;typedef struct { UID uid; enum MXFMetadataSetType type; UID package_uid; UID *tracks_refs; int tracks_count; MXFDescriptor *descriptor; /* only one */ UID descriptor_ref;} MXFPackage;typedef struct { UID uid; enum MXFMetadataSetType type;} MXFMetadataSet;typedef struct { UID *packages_refs; int packages_count; MXFMetadataSet **metadata_sets; int metadata_sets_count; AVFormatContext *fc; struct AVAES *aesc;} MXFContext;typedef struct { UID key; offset_t offset; uint64_t length;} KLVPacket;enum MXFWrappingScheme { Frame, Clip,};typedef struct { UID uid; enum CodecID id; enum MXFWrappingScheme wrapping;} MXFCodecUL;typedef struct { UID uid; enum CodecType type;} MXFDataDefinitionUL;typedef struct { const UID key; int (*read)(); int ctx_size; enum MXFMetadataSetType type;} MXFMetadataReadTableEntry;/* partial keys to match */static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 };static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 };static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 };/* complete keys to match */static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 };static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 };#define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))#define PRINT_KEY(pc, s, x) dprintf(pc, "%s %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", s, \ (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15])static int64_t klv_decode_ber_length(ByteIOContext *pb){ uint64_t size = get_byte(pb); if (size & 0x80) { /* long form */ int bytes_num = size & 0x7f; /* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */ if (bytes_num > 8) return -1; size = 0; while (bytes_num--) size = size << 8 | get_byte(pb); } return size;}static int mxf_read_sync(ByteIOContext *pb, const uint8_t *key, unsigned size){ int i, b; for (i = 0; i < size && !url_feof(pb); i++) { b = get_byte(pb); if (b == key[0]) i = 0; else if (b != key[i]) i = -1; } return i == size;}static int klv_read_packet(KLVPacket *klv, ByteIOContext *pb){ if (!mxf_read_sync(pb, mxf_klv_key, 4)) return -1; klv->offset = url_ftell(pb) - 4; memcpy(klv->key, mxf_klv_key, 4); get_buffer(pb, klv->key + 4, 12); klv->length = klv_decode_ber_length(pb); return klv->length == -1 ? -1 : 0;}static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv){ int i; for (i = 0; i < s->nb_streams; i++) { MXFTrack *track = s->streams[i]->priv_data; /* SMPTE 379M 7.3 */ if (!memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number))) return i; } /* return 0 if only one stream, for OP Atom files with 0 as track number */ return s->nb_streams == 1 ? 0 : -1;}/* XXX: use AVBitStreamFilter */static int mxf_get_d10_aes3_packet(ByteIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length){ uint8_t buffer[61444]; uint8_t *buf_ptr, *end_ptr, *data_ptr; int i; if (length > 61444) /* worst case PAL 1920 samples 8 channels */ return -1; get_buffer(pb, buffer, length); av_new_packet(pkt, length); data_ptr = pkt->data; end_ptr = buffer + length; buf_ptr = buffer + 4; /* skip SMPTE 331M header */ for (; buf_ptr < end_ptr; ) { for (i = 0; i < st->codec->channels; i++) { uint32_t sample = bytestream_get_le32(&buf_ptr); if (st->codec->bits_per_sample == 24) bytestream_put_le24(&data_ptr, (sample >> 4) & 0xffffff); else bytestream_put_le16(&data_ptr, (sample >> 12) & 0xffff); } buf_ptr += 32 - st->codec->channels*4; // always 8 channels stored SMPTE 331M } pkt->size = data_ptr - pkt->data; return 0;}static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv){ static const uint8_t checkv[16] = {0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b}; MXFContext *mxf = s->priv_data; ByteIOContext *pb = &s->pb; offset_t end = url_ftell(pb) + klv->length; uint64_t size; uint64_t orig_size; uint64_t plaintext_size; uint8_t ivec[16]; uint8_t tmpbuf[16]; int index; if (!mxf->aesc && s->key && s->keylen == 16) { mxf->aesc = av_malloc(av_aes_size); av_aes_init(mxf->aesc, s->key, 128, 1); } // crypto context url_fskip(pb, klv_decode_ber_length(pb)); // plaintext offset klv_decode_ber_length(pb); plaintext_size = get_be64(pb); // source klv key klv_decode_ber_length(pb); get_buffer(pb, klv->key, 16); if (!IS_KLV_KEY(klv, mxf_essence_element_key)) return -1; index = mxf_get_stream_index(s, klv); if (index < 0) return -1; // source size klv_decode_ber_length(pb); orig_size = get_be64(pb); if (orig_size < plaintext_size) return -1; // enc. code size = klv_decode_ber_length(pb); if (size < 32 || size - 32 < orig_size) return -1; get_buffer(pb, ivec, 16); get_buffer(pb, tmpbuf, 16); if (mxf->aesc) av_aes_crypt(mxf->aesc, tmpbuf, tmpbuf, 1, ivec, 1); if (memcmp(tmpbuf, checkv, 16)) av_log(s, AV_LOG_ERROR, "probably incorrect decryption key\n"); size -= 32; av_get_packet(pb, pkt, size); size -= plaintext_size; if (mxf->aesc) av_aes_crypt(mxf->aesc, &pkt->data[plaintext_size], &pkt->data[plaintext_size], size >> 4, ivec, 1); pkt->size = orig_size; pkt->stream_index = index; url_fskip(pb, end - url_ftell(pb)); return 0;}static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt){ KLVPacket klv; while (!url_feof(&s->pb)) { if (klv_read_packet(&klv, &s->pb) < 0) return -1;#ifdef DEBUG PRINT_KEY(s, "read packet", klv.key);#endif if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { int res = mxf_decrypt_triplet(s, pkt, &klv); if (res < 0) { av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); return -1; } return 0; } if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) { int index = mxf_get_stream_index(s, &klv); if (index < 0) { av_log(s, AV_LOG_ERROR, "error getting stream index\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -