2008-08-14 21:48:02 +00:00
/*
* MXF muxer
* Copyright (c) 2008 GUCAS, Zhentan Feng <spyfeng at gmail dot com>
2009-01-31 09:54:59 +00:00
* Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
2008-08-14 21:48:02 +00:00
*
* 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
2015-09-09 02:49:49 +02:00
*/
/*
2015-09-07 18:52:38 +02:00
* signal_standard, color_siting and klv_fill_key version fixes sponsored by NOA GmbH
2008-08-14 21:48:02 +00:00
*/
/*
* References
* SMPTE 336M KLV Data Encoding Protocol Using Key-Length-Value
* SMPTE 377M MXF File Format Specifications
* SMPTE 379M MXF Generic Container
* SMPTE 381M Mapping MPEG Streams into the MXF Generic Container
2014-09-30 14:16:52 +02:00
* SMPTE 422M Mapping JPEG 2000 Codestreams into the MXF Generic Container
2008-08-14 21:48:02 +00:00
* SMPTE RP210: SMPTE Metadata Dictionary
* SMPTE RP224: Registry of SMPTE Universal Labels
*/
2013-04-22 04:50:45 +02:00
#include <inttypes.h>
2009-02-02 23:37:03 +00:00
#include <math.h>
2009-02-05 20:15:18 +00:00
#include <time.h>
2009-02-02 23:37:03 +00:00
2011-07-06 16:35:12 +02:00
#include "libavutil/opt.h"
2009-03-11 06:15:00 +00:00
#include "libavutil/random_seed.h"
2012-01-16 14:19:37 +01:00
#include "libavutil/timecode.h"
2012-07-12 23:16:24 +02:00
#include "libavutil/avassert.h"
2015-05-16 19:59:18 +02:00
#include "libavutil/pixdesc.h"
2014-10-24 10:46:36 +03:00
#include "libavutil/time_internal.h"
2009-02-08 04:42:38 +00:00
#include "libavcodec/bytestream.h"
2012-05-29 00:45:41 +02:00
#include "libavcodec/dnxhddata.h"
2014-10-28 22:38:22 +00:00
#include "libavcodec/h264.h"
#include "libavcodec/internal.h"
2009-02-08 04:31:44 +00:00
#include "audiointerleave.h"
2009-02-08 04:42:38 +00:00
#include "avformat.h"
2013-07-15 17:39:55 +00:00
#include "avio_internal.h"
2011-07-13 12:21:00 +01:00
#include "internal.h"
2008-08-18 18:11:00 +00:00
#include "mxf.h"
2012-05-26 18:09:47 +02:00
#include "config.h"
2008-08-18 18:11:00 +00:00
2011-01-25 22:03:28 +00:00
extern AVOutputFormat ff_mxf_d10_muxer ;
2015-01-28 19:44:21 -08:00
extern AVOutputFormat ff_mxf_opatom_muxer ;
2009-02-13 07:28:20 +00:00
2009-02-10 09:02:29 +00:00
#define EDIT_UNITS_PER_BODY 250
2009-02-07 02:13:23 +00:00
#define KAG_SIZE 512
2009-02-02 10:03:38 +00:00
2014-09-22 09:19:33 +02:00
typedef struct MXFLocalTagPair {
2008-08-18 18:11:00 +00:00
int local_tag ;
UID uid ;
} MXFLocalTagPair ;
2014-09-22 09:19:33 +02:00
typedef struct MXFIndexEntry {
2009-02-02 10:03:38 +00:00
uint8_t flags ;
uint64_t offset ;
2009-02-08 09:39:19 +00:00
unsigned slice_offset ; ///< offset of audio slice
2010-07-02 08:35:47 +00:00
uint16_t temporal_ref ;
2009-02-02 10:03:38 +00:00
} MXFIndexEntry ;
2014-09-22 09:19:33 +02:00
typedef struct MXFStreamContext {
2009-01-31 06:18:25 +00:00
AudioInterleaveContext aic ;
2008-08-19 12:36:17 +00:00
UID track_essence_element_key ;
2009-06-30 07:43:32 +00:00
int index ; ///< index in mxf_essence_container_uls table
2008-08-31 02:41:31 +00:00
const UID * codec_ul ;
2009-06-30 07:43:32 +00:00
int order ; ///< interleaving order if dts are equal
2011-10-05 14:12:42 +02:00
int interlaced ; ///< whether picture is interlaced
2012-05-27 14:21:41 +02:00
int field_dominance ; ///< tff=1, bff=2
2012-05-29 00:45:41 +02:00
int component_depth ;
2015-05-19 01:11:09 +02:00
int color_siting ;
2015-05-24 02:43:26 +02:00
int signal_standard ;
2015-05-16 20:02:01 +02:00
int h_chroma_sub_sample ;
2009-02-02 10:03:38 +00:00
int temporal_reordering ;
2009-02-16 12:48:45 +00:00
AVRational aspect_ratio ; ///< display aspect ratio
2009-06-30 07:41:40 +00:00
int closed_gop ; ///< gop is closed, used in mpeg-2 frame parsing
2013-09-09 10:02:12 +02:00
int video_bit_rate ;
2008-08-19 12:36:17 +00:00
} MXFStreamContext ;
2014-09-22 09:19:33 +02:00
typedef struct MXFContainerEssenceEntry {
2008-08-31 01:33:28 +00:00
UID container_ul ;
UID element_ul ;
2008-08-31 02:41:31 +00:00
UID codec_ul ;
2010-07-24 12:58:28 +00:00
void ( * write_desc )( AVFormatContext * , AVStream * );
2008-08-31 04:20:47 +00:00
} MXFContainerEssenceEntry ;
2008-08-31 01:33:28 +00:00
2009-02-02 10:54:10 +00:00
static const struct {
2012-08-05 11:11:04 +02:00
enum AVCodecID id ;
2009-02-02 10:54:10 +00:00
int index ;
} mxf_essence_mappings [] = {
2012-08-05 11:11:04 +02:00
{ AV_CODEC_ID_MPEG2VIDEO , 0 },
{ AV_CODEC_ID_PCM_S24LE , 1 },
{ AV_CODEC_ID_PCM_S16LE , 1 },
2012-08-07 22:45:46 +02:00
{ AV_CODEC_ID_DVVIDEO , 15 },
{ AV_CODEC_ID_DNXHD , 24 },
2014-09-30 14:16:52 +02:00
{ AV_CODEC_ID_JPEG2000 , 34 },
2014-10-28 22:38:22 +00:00
{ AV_CODEC_ID_H264 , 35 },
2012-08-05 11:11:04 +02:00
{ AV_CODEC_ID_NONE }
2009-02-02 10:54:10 +00:00
};
2008-08-31 04:07:41 +00:00
static void mxf_write_wav_desc ( AVFormatContext * s , AVStream * st );
2009-01-31 07:02:20 +00:00
static void mxf_write_aes3_desc ( AVFormatContext * s , AVStream * st );
2008-08-31 04:07:41 +00:00
static void mxf_write_mpegvideo_desc ( AVFormatContext * s , AVStream * st );
2009-02-13 07:28:20 +00:00
static void mxf_write_cdci_desc ( AVFormatContext * s , AVStream * st );
static void mxf_write_generic_sound_desc ( AVFormatContext * s , AVStream * st );
2008-08-31 04:07:41 +00:00
2008-08-31 04:20:47 +00:00
static const MXFContainerEssenceEntry mxf_essence_container_uls [] = {
2008-08-31 01:33:28 +00:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x60 , 0x01 },
2008-08-31 02:41:31 +00:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2008-08-31 04:07:41 +00:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 },
2009-02-02 10:54:10 +00:00
mxf_write_mpegvideo_desc },
2009-01-31 07:02:20 +00:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x06 , 0x03 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x16 , 0x01 , 0x03 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
2009-02-02 10:54:10 +00:00
mxf_write_aes3_desc },
2008-08-31 01:33:28 +00:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x06 , 0x01 , 0x00 },
2008-08-31 02:41:31 +00:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x16 , 0x01 , 0x01 , 0x00 },
2008-08-31 04:07:41 +00:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
2009-02-02 10:54:10 +00:00
mxf_write_wav_desc },
2009-02-13 07:28:20 +00:00
// D-10 625/50 PAL 50mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x01 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
// D-10 525/60 NTSC 50mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x02 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x02 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x02 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
// D-10 625/50 PAL 40mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x03 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x03 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x03 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
// D-10 525/60 NTSC 40mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x04 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x04 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x04 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
// D-10 625/50 PAL 30mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x05 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x05 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x05 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
// D-10 525/60 NTSC 30mb/s
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x06 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x05 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x06 },
mxf_write_cdci_desc },
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x06 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x06 , 0x01 , 0x10 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 },
mxf_write_generic_sound_desc },
2013-01-04 19:12:08 +00:00
// DV Unknown
2012-05-26 18:09:47 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x7F , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 },
mxf_write_cdci_desc },
// DV25 525/60
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x40 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x01 , 0x00 },
mxf_write_cdci_desc },
// DV25 625/50
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x41 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 },
mxf_write_cdci_desc },
// DV50 525/60
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x50 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x03 , 0x00 },
mxf_write_cdci_desc },
// DV50 625/50
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x51 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x04 , 0x00 },
mxf_write_cdci_desc },
// DV100 1080/60
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x60 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x05 , 0x00 },
mxf_write_cdci_desc },
// DV100 1080/50
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x61 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x06 , 0x00 },
mxf_write_cdci_desc },
// DV100 720/60
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x62 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x07 , 0x00 },
mxf_write_cdci_desc },
// DV100 720/50
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x63 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x18 , 0x01 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x08 , 0x00 },
mxf_write_cdci_desc },
2012-05-29 00:45:41 +02:00
// DNxHD 1080p 10bit high
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x01 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 1080p 8bit medium
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x03 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 1080p 8bit high
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x04 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 1080i 10bit high
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x07 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 1080i 8bit medium
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x08 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 1080i 8bit high
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x09 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 720p 10bit
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x10 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 720p 8bit high
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x11 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 720p 8bit medium
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x12 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
// DNxHD 720p 8bit low
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x11 , 0x01 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
2012-07-09 19:29:42 +02:00
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x13 , 0x00 , 0x00 },
2012-05-29 00:45:41 +02:00
mxf_write_cdci_desc },
2014-09-30 14:16:52 +02:00
// JPEG2000
{ { 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x07 , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x0c , 0x01 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x08 , 0x00 },
{ 0x06 , 0x0e , 0x2b , 0x34 , 0x04 , 0x01 , 0x01 , 0x07 , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x01 , 0x01 , 0x00 },
mxf_write_cdci_desc },
2014-10-28 22:38:22 +00:00
// H.264
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x10 , 0x60 , 0x01 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 },
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 },
mxf_write_mpegvideo_desc },
2008-08-31 01:33:28 +00:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 },
2008-08-31 02:41:31 +00:00
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 },
2008-08-31 04:07:41 +00:00
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 },
2009-02-02 10:54:10 +00:00
NULL },
2008-08-31 01:33:28 +00:00
};
2008-08-19 12:36:17 +00:00
typedef struct MXFContext {
2011-07-06 16:35:12 +02:00
AVClass * av_class ;
2008-08-31 03:36:25 +00:00
int64_t footer_partition_offset ;
2008-08-19 12:36:17 +00:00
int essence_container_count ;
2009-01-31 06:18:25 +00:00
AVRational time_base ;
2009-01-31 06:32:12 +00:00
int header_written ;
2009-02-02 10:03:38 +00:00
MXFIndexEntry * index_entries ;
unsigned edit_units_count ;
2009-02-05 20:15:18 +00:00
uint64_t timestamp ; ///< timestamp, as year(16),month(8),day(8),hour(8),minutes(8),msec/4(8)
2009-02-08 09:39:19 +00:00
uint8_t slice_count ; ///< index slice count minus 1 (1 if no audio, 0 otherwise)
2009-02-10 09:02:29 +00:00
int last_indexed_edit_unit ;
uint64_t * body_partition_offset ;
unsigned body_partitions_count ;
int last_key_index ; ///< index of last key frame
2009-02-11 07:18:00 +00:00
uint64_t duration ;
2012-01-16 14:19:37 +01:00
AVTimecode tc ; ///< timecode context
2009-02-11 07:18:00 +00:00
AVStream * timecode_track ;
int timecode_base ; ///< rounded time code base (25 or 30)
2009-02-13 07:28:20 +00:00
int edit_unit_byte_count ; ///< fixed edit unit byte count
2009-02-13 22:38:05 +00:00
uint64_t body_offset ;
2009-03-11 06:15:00 +00:00
uint32_t instance_number ;
uint8_t umid [ 16 ]; ///< unique material identifier
2014-06-25 10:29:30 +00:00
int channel_count ;
2015-06-06 03:06:12 +02:00
int signal_standard ;
2015-03-14 17:59:50 -07:00
uint32_t tagged_value_count ;
2015-04-11 17:18:13 -07:00
AVRational audio_edit_rate ;
2008-08-19 12:36:17 +00:00
} MXFContext ;
2008-08-19 22:01:57 +00:00
2008-08-18 18:11:00 +00:00
static const uint8_t uuid_base [] = { 0xAD , 0xAB , 0x44 , 0x24 , 0x2f , 0x25 , 0x4d , 0xc7 , 0x92 , 0xff , 0x29 , 0xbd };
2009-03-11 06:15:00 +00:00
static const uint8_t umid_ul [] = { 0x06 , 0x0A , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x01 , 0x01 , 0x0D , 0x00 , 0x13 };
2008-08-18 18:11:00 +00:00
/**
* complete key for operation pattern, partitions, and primer pack
*/
2009-02-18 07:13:57 +00:00
static const uint8_t op1a_ul [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 , 0x09 , 0x00 };
2015-01-28 19:44:21 -08:00
static const uint8_t opatom_ul [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0D , 0x01 , 0x02 , 0x01 , 0x10 , 0x03 , 0x00 , 0x00 };
2009-02-02 20:29:31 +00:00
static const uint8_t footer_partition_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x04 , 0x04 , 0x00 }; // ClosedComplete
static const uint8_t primer_pack_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x05 , 0x01 , 0x00 };
static const uint8_t index_table_segment_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x02 , 0x01 , 0x01 , 0x10 , 0x01 , 0x00 };
static const uint8_t random_index_pack_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x11 , 0x01 , 0x00 };
2008-08-31 03:06:38 +00:00
static const uint8_t header_open_partition_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x01 , 0x00 }; // OpenIncomplete
static const uint8_t header_closed_partition_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x04 , 0x00 }; // ClosedComplete
2015-05-29 23:53:52 +02:00
static const uint8_t klv_fill_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x01 , 0x02 , 0x10 , 0x01 , 0x00 , 0x00 , 0x00 };
2009-02-10 09:02:29 +00:00
static const uint8_t body_partition_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x02 , 0x01 , 0x01 , 0x03 , 0x04 , 0x00 }; // ClosedComplete
2008-08-31 03:06:38 +00:00
2008-08-19 22:01:57 +00:00
/**
* partial key for header metadata
*/
static const uint8_t header_metadata_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0D , 0x01 , 0x01 , 0x01 , 0x01 };
2009-02-02 20:29:31 +00:00
static const uint8_t multiple_desc_ul [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x7F , 0x01 , 0x00 };
2008-08-19 22:01:57 +00:00
2008-08-22 04:12:52 +00:00
/**
* SMPTE RP210 http://www.smpte-ra.org/mdd/index.html
*/
static const MXFLocalTagPair mxf_local_tag_batch [] = {
// preface set
{ 0x3C0A , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x15 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Instance UID */
{ 0x3B02 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x10 , 0x02 , 0x04 , 0x00 , 0x00 }}, /* Last Modified Date */
{ 0x3B05 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x01 , 0x02 , 0x01 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Version */
{ 0x3B06 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x04 , 0x00 , 0x00 }}, /* Identifications reference */
{ 0x3B03 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x02 , 0x01 , 0x00 , 0x00 }}, /* Content Storage reference */
{ 0x3B09 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x01 , 0x02 , 0x02 , 0x03 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Operational Pattern UL */
{ 0x3B0A , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x01 , 0x02 , 0x02 , 0x10 , 0x02 , 0x01 , 0x00 , 0x00 }}, /* Essence Containers UL batch */
{ 0x3B0B , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x01 , 0x02 , 0x02 , 0x10 , 0x02 , 0x02 , 0x00 , 0x00 }}, /* DM Schemes UL batch */
// Identification
{ 0x3C09 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* This Generation UID */
{ 0x3C01 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x02 , 0x01 , 0x00 , 0x00 }}, /* Company Name */
{ 0x3C02 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x03 , 0x01 , 0x00 , 0x00 }}, /* Product Name */
2008-08-29 16:56:36 +00:00
{ 0x3C04 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x05 , 0x01 , 0x00 , 0x00 }}, /* Version String */
2008-08-22 04:12:52 +00:00
{ 0x3C05 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x07 , 0x00 , 0x00 , 0x00 }}, /* Product ID */
{ 0x3C06 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x10 , 0x02 , 0x03 , 0x00 , 0x00 }}, /* Modification Date */
// Content Storage
{ 0x1901 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x05 , 0x01 , 0x00 , 0x00 }}, /* Package strong reference batch */
2009-01-23 20:57:12 +00:00
{ 0x1902 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x05 , 0x02 , 0x00 , 0x00 }}, /* Package strong reference batch */
2008-08-22 04:12:52 +00:00
// Essence Container Data
{ 0x2701 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x06 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Linked Package UID */
{ 0x3F07 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x03 , 0x04 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* BodySID */
// Package
{ 0x4401 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x15 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Package UID */
{ 0x4405 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x10 , 0x01 , 0x03 , 0x00 , 0x00 }}, /* Package Creation Date */
{ 0x4404 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x10 , 0x02 , 0x05 , 0x00 , 0x00 }}, /* Package Modified Date */
2015-03-21 16:45:27 -07:00
{ 0x4402 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Package Name */
2008-08-22 04:12:52 +00:00
{ 0x4403 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x05 , 0x00 , 0x00 }}, /* Tracks Strong reference array */
2015-03-14 17:59:50 -07:00
{ 0x4406 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x02 , 0x01 , 0x02 , 0x0C , 0x00 , 0x00 , 0x00 }}, /* User Comments */
2008-08-22 04:12:52 +00:00
{ 0x4701 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x02 , 0x03 , 0x00 , 0x00 }}, /* Descriptor */
// Track
{ 0x4801 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x01 , 0x07 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Track ID */
2008-08-31 01:34:26 +00:00
{ 0x4804 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x01 , 0x04 , 0x01 , 0x03 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Track Number */
2008-08-22 04:12:52 +00:00
{ 0x4B01 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x30 , 0x04 , 0x05 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Edit Rate */
{ 0x4B02 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x03 , 0x01 , 0x03 , 0x00 , 0x00 }}, /* Origin */
{ 0x4803 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x02 , 0x04 , 0x00 , 0x00 }}, /* Sequence reference */
// Sequence
{ 0x0201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x07 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Data Definition UL */
{ 0x0202 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x02 , 0x01 , 0x01 , 0x03 , 0x00 , 0x00 }}, /* Duration */
{ 0x1001 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x09 , 0x00 , 0x00 }}, /* Structural Components reference array */
// Source Clip
2009-02-10 05:22:38 +00:00
{ 0x1201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 }}, /* Start position */
2008-08-22 04:12:52 +00:00
{ 0x1101 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x03 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* SourcePackageID */
{ 0x1102 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x03 , 0x02 , 0x00 , 0x00 , 0x00 }}, /* SourceTrackID */
2009-02-11 07:18:00 +00:00
// Timecode Component
{ 0x1501 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x03 , 0x01 , 0x05 , 0x00 , 0x00 }}, /* Start Time Code */
{ 0x1502 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x04 , 0x01 , 0x01 , 0x02 , 0x06 , 0x00 , 0x00 }}, /* Rounded Time Code Base */
{ 0x1503 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x01 , 0x01 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Drop Frame */
2015-03-14 17:59:50 -07:00
// Tagged Value
{ 0x5001 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x02 , 0x01 , 0x02 , 0x09 , 0x01 , 0x00 , 0x00 }}, /* Name */
{ 0x5003 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x02 , 0x01 , 0x02 , 0x0A , 0x01 , 0x00 , 0x00 }}, /* Value */
2008-08-29 17:04:18 +00:00
// File Descriptor
{ 0x3F01 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x0B , 0x00 , 0x00 }}, /* Sub Descriptors reference array */
2008-08-22 04:12:52 +00:00
{ 0x3006 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x06 , 0x01 , 0x01 , 0x03 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Linked Track ID */
{ 0x3001 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x06 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* SampleRate */
2015-03-21 16:45:27 -07:00
{ 0x3002 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x06 , 0x01 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* ContainerDuration */
2008-08-29 17:04:18 +00:00
{ 0x3004 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x00 , 0x00 }}, /* Essence Container */
// Generic Picture Essence Descriptor
2009-01-31 09:08:01 +00:00
{ 0x320C , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 }}, /* Frame Layout */
2009-02-10 05:22:38 +00:00
{ 0x320D , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x03 , 0x02 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Video Line Map */
2008-08-29 17:04:18 +00:00
{ 0x3203 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 }}, /* Stored Width */
{ 0x3202 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Stored Height */
2009-02-02 03:35:09 +00:00
{ 0x3209 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0C , 0x00 , 0x00 , 0x00 }}, /* Display Width */
{ 0x3208 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0B , 0x00 , 0x00 , 0x00 }}, /* Display Height */
2015-03-30 11:11:17 +01:00
{ 0x320B , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0E , 0x00 , 0x00 , 0x00 }}, /* Presentation Y offset */
2008-08-29 17:04:18 +00:00
{ 0x320E , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Aspect Ratio */
{ 0x3201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x06 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Picture Essence Coding */
2012-05-27 14:21:41 +02:00
{ 0x3212 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x03 , 0x01 , 0x06 , 0x00 , 0x00 , 0x00 }}, /* Field Dominance (Opt) */
2015-05-24 02:43:26 +02:00
{ 0x3215 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x05 , 0x01 , 0x13 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Signal Standard */
2009-02-10 06:14:39 +00:00
// CDCI Picture Essence Descriptor
{ 0x3301 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x05 , 0x03 , 0x0A , 0x00 , 0x00 , 0x00 }}, /* Component Depth */
{ 0x3302 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Horizontal Subsampling */
2015-05-19 01:11:09 +02:00
{ 0x3303 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x06 , 0x00 , 0x00 , 0x00 }}, /* Color Siting */
2008-08-29 17:04:18 +00:00
// Generic Sound Essence Descriptor
2009-02-10 05:22:38 +00:00
{ 0x3D02 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x02 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 }}, /* Locked/Unlocked */
2008-08-29 17:04:18 +00:00
{ 0x3D03 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x02 , 0x03 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 }}, /* Audio sampling rate */
{ 0x3D07 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x02 , 0x01 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 }}, /* ChannelCount */
{ 0x3D01 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x02 , 0x03 , 0x03 , 0x04 , 0x00 , 0x00 , 0x00 }}, /* Quantization bits */
2008-10-26 23:59:28 +00:00
{ 0x3D06 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x02 , 0x04 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Sound Essence Compression */
2009-02-02 10:03:38 +00:00
// Index Table Segment
{ 0x3F0B , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x05 , 0x30 , 0x04 , 0x06 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Index Edit Rate */
{ 0x3F0C , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x07 , 0x02 , 0x01 , 0x03 , 0x01 , 0x0A , 0x00 , 0x00 }}, /* Index Start Position */
{ 0x3F0D , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x07 , 0x02 , 0x02 , 0x01 , 0x01 , 0x02 , 0x00 , 0x00 }}, /* Index Duration */
2009-02-10 05:22:38 +00:00
{ 0x3F05 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x06 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* Edit Unit Byte Count */
2009-02-02 10:03:38 +00:00
{ 0x3F06 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x03 , 0x04 , 0x05 , 0x00 , 0x00 , 0x00 , 0x00 }}, /* IndexSID */
{ 0x3F08 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x04 , 0x04 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Slice Count */
{ 0x3F09 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x04 , 0x04 , 0x01 , 0x06 , 0x00 , 0x00 , 0x00 }}, /* Delta Entry Array */
{ 0x3F0A , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x04 , 0x04 , 0x02 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Index Entry Array */
2009-02-02 03:45:03 +00:00
// MPEG video Descriptor
{ 0x8000 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x0B , 0x00 , 0x00 }}, /* BitRate */
2009-07-04 07:49:12 +00:00
{ 0x8007 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x0A , 0x00 , 0x00 }}, /* ProfileAndLevel */
2009-02-02 04:36:54 +00:00
// Wave Audio Essence Descriptor
{ 0x3D09 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x02 , 0x03 , 0x03 , 0x05 , 0x00 , 0x00 , 0x00 }}, /* Average Bytes Per Second */
{ 0x3D0A , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x02 , 0x03 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 }}, /* Block Align */
2008-08-22 04:12:52 +00:00
};
2011-02-20 11:04:12 +01:00
static void mxf_write_uuid ( AVIOContext * pb , enum MXFMetadataSetType type , int value )
2008-08-18 18:11:00 +00:00
{
2011-02-21 19:28:17 +01:00
avio_write ( pb , uuid_base , 12 );
avio_wb16 ( pb , type );
avio_wb16 ( pb , value );
2008-08-18 18:11:00 +00:00
}
2009-03-11 06:15:00 +00:00
static void mxf_write_umid ( AVFormatContext * s , int type )
2008-08-19 12:36:17 +00:00
{
2009-03-11 06:15:00 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-21 19:28:17 +01:00
avio_write ( s -> pb , umid_ul , 13 );
avio_wb24 ( s -> pb , mxf -> instance_number );
avio_write ( s -> pb , mxf -> umid , 15 );
avio_w8 ( s -> pb , type );
2008-08-19 12:36:17 +00:00
}
2008-08-19 22:01:57 +00:00
2011-02-20 11:04:12 +01:00
static void mxf_write_refs_count ( AVIOContext * pb , int ref_count )
2008-08-19 22:01:57 +00:00
{
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , ref_count );
avio_wb32 ( pb , 16 );
2008-08-19 22:01:57 +00:00
}
2009-02-07 02:13:23 +00:00
static int klv_ber_length ( uint64_t len )
{
if ( len < 128 )
return 1 ;
else
return ( av_log2 ( len ) >> 3 ) + 2 ;
}
2011-02-20 11:04:12 +01:00
static int klv_encode_ber_length ( AVIOContext * pb , uint64_t len )
2008-08-18 18:11:00 +00:00
{
// Determine the best BER size
int size ;
if ( len < 128 ) {
//short form
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , len );
2008-08-18 18:11:00 +00:00
return 1 ;
}
size = ( av_log2 ( len ) >> 3 ) + 1 ;
// long form
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0x80 + size );
2008-08-18 18:11:00 +00:00
while ( size ) {
2009-02-02 20:29:31 +00:00
size -- ;
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , len >> 8 * size & 0xff );
2008-08-18 18:11:00 +00:00
}
return 0 ;
}
2011-02-20 11:04:12 +01:00
static void klv_encode_ber4_length ( AVIOContext * pb , int len )
2009-02-13 05:33:11 +00:00
{
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0x80 + 3 );
avio_wb24 ( pb , len );
2009-02-13 05:33:11 +00:00
}
2015-01-28 19:44:21 -08:00
static void klv_encode_ber9_length ( AVIOContext * pb , uint64_t len )
{
avio_w8 ( pb , 0x80 + 8 );
avio_wb64 ( pb , len );
}
2008-08-31 00:23:38 +00:00
/*
2008-08-31 04:13:44 +00:00
* Get essence container ul index
2008-08-31 00:23:38 +00:00
*/
2012-08-05 11:11:04 +02:00
static int mxf_get_essence_container_ul_index ( enum AVCodecID id )
2008-08-14 21:48:02 +00:00
{
2008-08-31 04:13:44 +00:00
int i ;
2009-02-02 10:54:10 +00:00
for ( i = 0 ; mxf_essence_mappings [ i ]. id ; i ++ )
if ( mxf_essence_mappings [ i ]. id == id )
return mxf_essence_mappings [ i ]. index ;
2008-08-31 04:13:44 +00:00
return - 1 ;
2008-08-14 21:48:02 +00:00
}
2008-08-22 04:12:52 +00:00
static void mxf_write_primer_pack ( AVFormatContext * s )
2008-08-18 18:11:00 +00:00
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-18 18:11:00 +00:00
int local_tag_number , i = 0 ;
2008-10-21 21:40:24 +00:00
local_tag_number = FF_ARRAY_ELEMS ( mxf_local_tag_batch );
2008-08-18 18:11:00 +00:00
2011-02-21 19:28:17 +01:00
avio_write ( pb , primer_pack_key , 16 );
2008-08-18 18:11:00 +00:00
klv_encode_ber_length ( pb , local_tag_number * 18 + 8 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , local_tag_number ); // local_tag num
avio_wb32 ( pb , 18 ); // item size, always 18 according to the specs
2008-08-18 18:11:00 +00:00
for ( i = 0 ; i < local_tag_number ; i ++ ) {
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , mxf_local_tag_batch [ i ]. local_tag );
avio_write ( pb , mxf_local_tag_batch [ i ]. uid , 16 );
2008-08-18 18:11:00 +00:00
}
}
2011-02-20 11:04:12 +01:00
static void mxf_write_local_tag ( AVIOContext * pb , int size , int tag )
2008-08-18 18:11:00 +00:00
{
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , tag );
avio_wb16 ( pb , size );
2008-08-18 18:11:00 +00:00
}
2011-02-20 11:04:12 +01:00
static void mxf_write_metadata_key ( AVIOContext * pb , unsigned int value )
2008-08-19 12:36:17 +00:00
{
2011-02-21 19:28:17 +01:00
avio_write ( pb , header_metadata_key , 13 );
avio_wb24 ( pb , value );
2008-08-19 12:36:17 +00:00
}
2008-08-14 21:48:02 +00:00
static void mxf_free ( AVFormatContext * s )
{
int i ;
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
2008-08-31 00:36:30 +00:00
AVStream * st = s -> streams [ i ];
2008-08-14 21:48:02 +00:00
av_freep ( & st -> priv_data );
}
}
2009-02-08 05:12:30 +00:00
static const MXFCodecUL * mxf_get_data_definition_ul ( int type )
2008-08-14 21:48:02 +00:00
{
2009-02-08 05:12:30 +00:00
const MXFCodecUL * uls = ff_mxf_data_definition_uls ;
while ( uls -> uid [ 0 ]) {
if ( type == uls -> id )
2008-08-14 21:48:02 +00:00
break ;
2008-08-30 22:58:49 +00:00
uls ++ ;
2008-08-14 21:48:02 +00:00
}
return uls ;
}
2012-10-25 10:23:59 +02:00
//one EC -> one descriptor. N ECs -> MultipleDescriptor + N descriptors
#define DESCRIPTOR_COUNT(essence_container_count) \
(essence_container_count > 1 ? essence_container_count + 1 : essence_container_count)
2008-08-31 00:28:36 +00:00
static void mxf_write_essence_container_refs ( AVFormatContext * s )
2008-08-26 15:58:25 +00:00
{
2008-08-31 00:23:38 +00:00
MXFContext * c = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-31 00:23:38 +00:00
int i ;
2008-08-26 15:58:25 +00:00
2012-10-25 10:23:59 +02:00
mxf_write_refs_count ( pb , DESCRIPTOR_COUNT ( c -> essence_container_count ));
2008-08-31 00:28:51 +00:00
av_log ( s , AV_LOG_DEBUG , "essence container count:%d \n " , c -> essence_container_count );
for ( i = 0 ; i < c -> essence_container_count ; i ++ ) {
2009-02-13 07:46:03 +00:00
MXFStreamContext * sc = s -> streams [ i ] -> priv_data ;
2011-02-21 19:28:17 +01:00
avio_write ( pb , mxf_essence_container_uls [ sc -> index ]. container_ul , 16 );
2008-08-31 00:28:51 +00:00
}
2012-10-25 10:23:59 +02:00
if ( c -> essence_container_count > 1 )
avio_write ( pb , multiple_desc_ul , 16 );
2008-08-26 15:58:25 +00:00
}
2008-08-22 04:12:52 +00:00
static void mxf_write_preface ( AVFormatContext * s )
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-22 04:12:52 +00:00
mxf_write_metadata_key ( pb , 0x012f00 );
PRINT_KEY ( s , "preface key" , pb -> buf_ptr - 16 );
2012-10-25 10:23:59 +02:00
klv_encode_ber_length ( pb , 130 + 16LL * DESCRIPTOR_COUNT ( mxf -> essence_container_count ));
2008-08-22 04:12:52 +00:00
// write preface set uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , Preface , 0 );
PRINT_KEY ( s , "preface uid" , pb -> buf_ptr - 16 );
2009-02-05 20:15:18 +00:00
// last modified date
2008-08-22 04:12:52 +00:00
mxf_write_local_tag ( pb , 8 , 0x3B02 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> timestamp );
2008-08-22 04:12:52 +00:00
// write version
mxf_write_local_tag ( pb , 2 , 0x3B05 );
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , 258 ); // v1.2
2008-08-22 04:12:52 +00:00
// write identification_refs
mxf_write_local_tag ( pb , 16 + 8 , 0x3B06 );
mxf_write_refs_count ( pb , 1 );
mxf_write_uuid ( pb , Identification , 0 );
// write content_storage_refs
mxf_write_local_tag ( pb , 16 , 0x3B03 );
mxf_write_uuid ( pb , ContentStorage , 0 );
2009-02-10 04:53:41 +00:00
// operational pattern
2008-08-22 04:12:52 +00:00
mxf_write_local_tag ( pb , 16 , 0x3B09 );
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer )
avio_write ( pb , opatom_ul , 16 );
else
avio_write ( pb , op1a_ul , 16 );
2008-08-22 04:12:52 +00:00
// write essence_container_refs
2012-10-25 10:23:59 +02:00
mxf_write_local_tag ( pb , 8 + 16LL * DESCRIPTOR_COUNT ( mxf -> essence_container_count ), 0x3B0A );
2008-08-31 00:28:36 +00:00
mxf_write_essence_container_refs ( s );
2008-08-22 04:12:52 +00:00
// write dm_scheme_refs
mxf_write_local_tag ( pb , 8 , 0x3B0B );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-22 04:12:52 +00:00
}
2008-08-30 22:23:11 +00:00
/*
2015-03-05 10:59:11 -08:00
* Returns the length of the UTF-16 string, in 16-bit characters, that would result
* from decoding the utf-8 string.
*/
static uint64_t mxf_utf16len ( const char * utf8_str )
{
const uint8_t * q = utf8_str ;
uint64_t size = 0 ;
while ( * q ) {
uint32_t ch ;
GET_UTF8 ( ch , * q ++ , goto invalid ;)
if ( ch < 0x10000 )
size ++ ;
else
size += 2 ;
continue ;
invalid :
av_log ( NULL , AV_LOG_ERROR , "Invaid UTF8 sequence in mxf_utf16len \n\n " );
}
size += 1 ;
return size ;
}
/*
* Returns the calculated length a local tag containing an utf-8 string as utf-16
*/
static int mxf_utf16_local_tag_length ( const char * utf8_str )
{
uint64_t size ;
if ( ! utf8_str )
return 0 ;
size = mxf_utf16len ( utf8_str );
if ( size >= UINT16_MAX / 2 ) {
av_log ( NULL , AV_LOG_ERROR , "utf16 local tag size %" PRIx64 " invalid (too large), ignoring \n " , size );
return 0 ;
}
return 4 + size * 2 ;
}
/*
* Write a local tag containing an utf-8 string as utf-16
2008-08-30 22:23:11 +00:00
*/
2011-02-20 11:04:12 +01:00
static void mxf_write_local_tag_utf16 ( AVIOContext * pb , int tag , const char * value )
2008-08-30 22:23:11 +00:00
{
2015-03-05 10:59:11 -08:00
uint64_t size = mxf_utf16len ( value );
if ( size >= UINT16_MAX / 2 ) {
av_log ( NULL , AV_LOG_ERROR , "utf16 local tag size %" PRIx64 " invalid (too large), ignoring \n " , size );
return ;
}
2008-08-30 22:32:23 +00:00
mxf_write_local_tag ( pb , size * 2 , tag );
2015-03-05 10:59:11 -08:00
avio_put_str16be ( pb , value );
2008-08-30 22:23:11 +00:00
}
2008-08-22 04:12:52 +00:00
static void mxf_write_identification ( AVFormatContext * s )
{
2009-02-05 20:15:18 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2011-04-17 23:57:50 +02:00
const char * company = "FFmpeg" ;
2015-03-01 13:02:20 +01:00
const char * product = s -> oformat != & ff_mxf_opatom_muxer ? "OP1a Muxer" : "OPAtom Muxer" ;
2008-08-30 22:37:19 +00:00
const char * version ;
2008-08-30 22:45:32 +00:00
int length ;
2008-08-22 04:12:52 +00:00
mxf_write_metadata_key ( pb , 0x013000 );
PRINT_KEY ( s , "identification key" , pb -> buf_ptr - 16 );
2014-05-01 10:43:10 +02:00
version = s -> flags & AVFMT_FLAG_BITEXACT ?
2008-08-30 22:41:01 +00:00
"0.0.0" : AV_STRINGIFY ( LIBAVFORMAT_VERSION );
2015-03-05 10:59:11 -08:00
length = 72 + mxf_utf16_local_tag_length ( company ) +
mxf_utf16_local_tag_length ( product ) +
mxf_utf16_local_tag_length ( version );
2008-08-22 04:12:52 +00:00
klv_encode_ber_length ( pb , length );
// write uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , Identification , 0 );
PRINT_KEY ( s , "identification uid" , pb -> buf_ptr - 16 );
2008-08-30 22:45:49 +00:00
2008-08-22 04:12:52 +00:00
// write generation uid
mxf_write_local_tag ( pb , 16 , 0x3C09 );
mxf_write_uuid ( pb , Identification , 1 );
2008-08-30 22:45:32 +00:00
mxf_write_local_tag_utf16 ( pb , 0x3C01 , company ); // Company Name
mxf_write_local_tag_utf16 ( pb , 0x3C02 , product ); // Product Name
2008-08-30 22:37:19 +00:00
mxf_write_local_tag_utf16 ( pb , 0x3C04 , version ); // Version String
2008-08-22 04:12:52 +00:00
// write product uid
mxf_write_local_tag ( pb , 16 , 0x3C05 );
mxf_write_uuid ( pb , Identification , 2 );
2009-02-05 19:30:01 +00:00
// modification date
2008-08-22 04:12:52 +00:00
mxf_write_local_tag ( pb , 8 , 0x3C06 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> timestamp );
2008-08-22 04:12:52 +00:00
}
static void mxf_write_content_storage ( AVFormatContext * s )
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-22 04:12:52 +00:00
mxf_write_metadata_key ( pb , 0x011800 );
PRINT_KEY ( s , "content storage key" , pb -> buf_ptr - 16 );
2009-01-23 20:57:12 +00:00
klv_encode_ber_length ( pb , 92 );
2008-08-22 04:12:52 +00:00
// write uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , ContentStorage , 0 );
PRINT_KEY ( s , "content storage uid" , pb -> buf_ptr - 16 );
2008-08-30 22:58:49 +00:00
2008-08-22 04:12:52 +00:00
// write package reference
mxf_write_local_tag ( pb , 16 * 2 + 8 , 0x1901 );
mxf_write_refs_count ( pb , 2 );
mxf_write_uuid ( pb , MaterialPackage , 0 );
mxf_write_uuid ( pb , SourcePackage , 0 );
2009-01-23 20:57:12 +00:00
// write essence container data
mxf_write_local_tag ( pb , 8 + 16 , 0x1902 );
mxf_write_refs_count ( pb , 1 );
mxf_write_uuid ( pb , EssenceContainerData , 0 );
2008-08-22 04:12:52 +00:00
}
2008-08-31 01:48:02 +00:00
static void mxf_write_track ( AVFormatContext * s , AVStream * st , enum MXFMetadataSetType type )
2008-08-24 05:55:46 +00:00
{
2009-02-04 04:50:47 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-31 00:36:30 +00:00
MXFStreamContext * sc = st -> priv_data ;
2008-08-24 05:55:46 +00:00
mxf_write_metadata_key ( pb , 0x013b00 );
PRINT_KEY ( s , "track key" , pb -> buf_ptr - 16 );
klv_encode_ber_length ( pb , 80 );
// write track uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
2008-08-31 01:48:02 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? Track : Track + TypeBottom , st -> index );
2008-08-24 05:55:46 +00:00
PRINT_KEY ( s , "track uid" , pb -> buf_ptr - 16 );
2008-08-30 22:58:49 +00:00
2008-08-24 05:55:46 +00:00
// write track id
mxf_write_local_tag ( pb , 4 , 0x4801 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> index + 2 );
2008-08-24 05:55:46 +00:00
2008-08-31 01:33:28 +00:00
// write track number
2008-08-24 05:55:46 +00:00
mxf_write_local_tag ( pb , 4 , 0x4804 );
2008-08-31 01:33:28 +00:00
if ( type == MaterialPackage )
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 0 ); // track number of material package is 0
2008-08-31 01:33:28 +00:00
else
2011-02-21 19:28:17 +01:00
avio_write ( pb , sc -> track_essence_element_key + 12 , 4 );
2008-08-24 05:55:46 +00:00
mxf_write_local_tag ( pb , 8 , 0x4B01 );
2015-04-11 17:18:13 -07:00
if ( st == mxf -> timecode_track && s -> oformat == & ff_mxf_opatom_muxer ){
avio_wb32 ( pb , mxf -> tc . rate . num );
avio_wb32 ( pb , mxf -> tc . rate . den );
} else {
avio_wb32 ( pb , mxf -> time_base . den );
avio_wb32 ( pb , mxf -> time_base . num );
}
2008-08-24 05:55:46 +00:00
// write origin
mxf_write_local_tag ( pb , 8 , 0x4B02 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-24 05:55:46 +00:00
// write sequence refs
mxf_write_local_tag ( pb , 16 , 0x4803 );
2008-08-31 01:48:02 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? Sequence : Sequence + TypeBottom , st -> index );
2008-08-24 05:55:46 +00:00
}
2009-02-11 07:18:00 +00:00
static const uint8_t smpte_12m_timecode_track_data_ul [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x03 , 0x02 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 };
static void mxf_write_common_fields ( AVFormatContext * s , AVStream * st )
2008-08-19 22:01:57 +00:00
{
2009-02-11 07:18:00 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-31 02:46:50 +00:00
2008-08-19 22:01:57 +00:00
// find data define uls
mxf_write_local_tag ( pb , 16 , 0x0201 );
2009-02-11 07:18:00 +00:00
if ( st == mxf -> timecode_track )
2011-02-21 19:28:17 +01:00
avio_write ( pb , smpte_12m_timecode_track_data_ul , 16 );
2009-02-11 07:18:00 +00:00
else {
const MXFCodecUL * data_def_ul = mxf_get_data_definition_ul ( st -> codec -> codec_type );
2011-02-21 19:28:17 +01:00
avio_write ( pb , data_def_ul -> uid , 16 );
2009-02-11 07:18:00 +00:00
}
2008-08-19 22:01:57 +00:00
// write duration
mxf_write_local_tag ( pb , 8 , 0x0202 );
2015-04-11 17:18:13 -07:00
if ( st != mxf -> timecode_track && s -> oformat == & ff_mxf_opatom_muxer && st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO ){
avio_wb64 ( pb , mxf -> body_offset / mxf -> edit_unit_byte_count );
} else {
avio_wb64 ( pb , mxf -> duration );
}
2008-08-19 22:01:57 +00:00
}
2008-08-31 01:48:02 +00:00
static void mxf_write_sequence ( AVFormatContext * s , AVStream * st , enum MXFMetadataSetType type )
2008-08-24 05:55:46 +00:00
{
2009-02-11 07:18:00 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-11 07:18:00 +00:00
enum MXFMetadataSetType component ;
2008-08-24 05:55:46 +00:00
mxf_write_metadata_key ( pb , 0x010f00 );
PRINT_KEY ( s , "sequence key" , pb -> buf_ptr - 16 );
klv_encode_ber_length ( pb , 80 );
mxf_write_local_tag ( pb , 16 , 0x3C0A );
2008-08-31 01:48:02 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? Sequence : Sequence + TypeBottom , st -> index );
2008-08-24 05:55:46 +00:00
PRINT_KEY ( s , "sequence uid" , pb -> buf_ptr - 16 );
2009-02-11 07:18:00 +00:00
mxf_write_common_fields ( s , st );
2008-08-24 05:55:46 +00:00
// write structural component
mxf_write_local_tag ( pb , 16 + 8 , 0x1001 );
mxf_write_refs_count ( pb , 1 );
2009-02-11 07:18:00 +00:00
if ( st == mxf -> timecode_track )
component = TimecodeComponent ;
else
2009-02-18 01:35:36 +00:00
component = SourceClip ;
if ( type == SourcePackage )
component += TypeBottom ;
2009-02-11 07:18:00 +00:00
mxf_write_uuid ( pb , component , st -> index );
}
2009-02-18 01:35:36 +00:00
static void mxf_write_timecode_component ( AVFormatContext * s , AVStream * st , enum MXFMetadataSetType type )
2009-02-11 07:18:00 +00:00
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-11 07:18:00 +00:00
mxf_write_metadata_key ( pb , 0x011400 );
klv_encode_ber_length ( pb , 75 );
// UID
mxf_write_local_tag ( pb , 16 , 0x3C0A );
2009-02-18 01:35:36 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? TimecodeComponent :
TimecodeComponent + TypeBottom , st -> index );
2009-02-11 07:18:00 +00:00
mxf_write_common_fields ( s , st );
// Start Time Code
mxf_write_local_tag ( pb , 8 , 0x1501 );
2011-07-06 16:35:12 +02:00
avio_wb64 ( pb , mxf -> tc . start );
2009-02-11 07:18:00 +00:00
// Rounded Time Code Base
mxf_write_local_tag ( pb , 2 , 0x1502 );
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , mxf -> timecode_base );
2009-02-11 07:18:00 +00:00
// Drop Frame
mxf_write_local_tag ( pb , 1 , 0x1503 );
2012-01-16 14:19:37 +01:00
avio_w8 ( pb , !! ( mxf -> tc . flags & AV_TIMECODE_FLAG_DROPFRAME ));
2008-08-24 05:55:46 +00:00
}
2008-08-31 01:48:02 +00:00
static void mxf_write_structural_component ( AVFormatContext * s , AVStream * st , enum MXFMetadataSetType type )
2008-08-24 05:55:46 +00:00
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-24 05:55:46 +00:00
int i ;
mxf_write_metadata_key ( pb , 0x011100 );
PRINT_KEY ( s , "sturctural component key" , pb -> buf_ptr - 16 );
klv_encode_ber_length ( pb , 108 );
// write uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
2008-08-31 01:48:02 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? SourceClip : SourceClip + TypeBottom , st -> index );
2008-08-24 05:55:46 +00:00
PRINT_KEY ( s , "structural component uid" , pb -> buf_ptr - 16 );
2009-02-11 07:18:00 +00:00
mxf_write_common_fields ( s , st );
2008-08-24 05:55:46 +00:00
// write start_position
mxf_write_local_tag ( pb , 8 , 0x1201 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-24 05:55:46 +00:00
2008-08-30 22:58:49 +00:00
// write source package uid, end of the reference
2008-08-24 05:55:46 +00:00
mxf_write_local_tag ( pb , 32 , 0x1101 );
if ( type == SourcePackage ) {
2008-08-30 22:58:49 +00:00
for ( i = 0 ; i < 4 ; i ++ )
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-24 05:55:46 +00:00
} else
2009-03-11 06:15:00 +00:00
mxf_write_umid ( s , 1 );
2008-08-24 05:55:46 +00:00
2008-08-30 22:58:49 +00:00
// write source track id
2008-08-24 05:55:46 +00:00
mxf_write_local_tag ( pb , 4 , 0x1102 );
if ( type == SourcePackage )
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 0 );
2008-08-24 05:55:46 +00:00
else
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> index + 2 );
2008-08-24 05:55:46 +00:00
}
2008-08-22 04:12:52 +00:00
static void mxf_write_multi_descriptor ( AVFormatContext * s )
{
2009-02-04 09:35:59 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-13 07:28:20 +00:00
const uint8_t * ul ;
2008-08-22 04:12:52 +00:00
int i ;
mxf_write_metadata_key ( pb , 0x014400 );
PRINT_KEY ( s , "multiple descriptor key" , pb -> buf_ptr - 16 );
2012-10-24 17:06:49 +02:00
klv_encode_ber_length ( pb , 64 + 16LL * s -> nb_streams );
2008-08-22 04:12:52 +00:00
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , MultipleDescriptor , 0 );
PRINT_KEY ( s , "multi_desc uid" , pb -> buf_ptr - 16 );
// write sample rate
mxf_write_local_tag ( pb , 8 , 0x3001 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> time_base . den );
avio_wb32 ( pb , mxf -> time_base . num );
2008-08-22 04:12:52 +00:00
// write essence container ul
mxf_write_local_tag ( pb , 16 , 0x3004 );
2009-02-13 07:28:20 +00:00
if ( mxf -> essence_container_count > 1 )
ul = multiple_desc_ul ;
2009-02-13 07:46:03 +00:00
else {
MXFStreamContext * sc = s -> streams [ 0 ] -> priv_data ;
ul = mxf_essence_container_uls [ sc -> index ]. container_ul ;
}
2011-02-21 19:28:17 +01:00
avio_write ( pb , ul , 16 );
2008-08-22 04:12:52 +00:00
// write sub descriptor refs
mxf_write_local_tag ( pb , s -> nb_streams * 16 + 8 , 0x3F01 );
mxf_write_refs_count ( pb , s -> nb_streams );
2008-08-30 22:58:49 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ )
2008-08-22 04:12:52 +00:00
mxf_write_uuid ( pb , SubDescriptor , i );
}
2009-02-04 09:35:59 +00:00
static void mxf_write_generic_desc ( AVFormatContext * s , AVStream * st , const UID key , unsigned size )
2008-08-19 22:01:57 +00:00
{
2009-02-04 09:35:59 +00:00
MXFContext * mxf = s -> priv_data ;
2008-08-30 23:54:24 +00:00
MXFStreamContext * sc = st -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-19 22:01:57 +00:00
2011-02-21 19:28:17 +01:00
avio_write ( pb , key , 16 );
2009-07-04 07:52:28 +00:00
klv_encode_ber4_length ( pb , size + 20 + 8 + 12 + 20 );
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , SubDescriptor , st -> index );
mxf_write_local_tag ( pb , 4 , 0x3006 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> index + 2 );
2008-08-19 22:01:57 +00:00
2008-08-22 04:12:52 +00:00
mxf_write_local_tag ( pb , 8 , 0x3001 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> time_base . den );
avio_wb32 ( pb , mxf -> time_base . num );
2008-08-22 04:12:52 +00:00
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 16 , 0x3004 );
2011-02-21 19:28:17 +01:00
avio_write ( pb , mxf_essence_container_uls [ sc -> index ]. container_ul , 16 );
2008-08-19 22:01:57 +00:00
}
2008-08-31 04:07:41 +00:00
static const UID mxf_mpegvideo_descriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x51 , 0x00 };
static const UID mxf_wav_descriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x48 , 0x00 };
2009-01-31 07:02:20 +00:00
static const UID mxf_aes3_descriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x47 , 0x00 };
2009-02-13 07:28:20 +00:00
static const UID mxf_cdci_descriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0D , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x28 , 0x00 };
static const UID mxf_generic_sound_descriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0D , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x42 , 0x00 };
2008-08-31 04:07:41 +00:00
2009-02-13 07:11:21 +00:00
static void mxf_write_cdci_common ( AVFormatContext * s , AVStream * st , const UID key , unsigned size )
2008-08-19 22:01:57 +00:00
{
2009-01-31 06:46:42 +00:00
MXFStreamContext * sc = st -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-01-23 20:15:46 +00:00
int stored_height = ( st -> codec -> height + 15 ) / 16 * 16 ;
2009-02-13 07:13:36 +00:00
int display_height ;
2009-01-31 09:23:50 +00:00
int f1 , f2 ;
2015-05-19 01:11:09 +02:00
unsigned desc_size = size + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 5 + 16 + sc -> interlaced * 4 + 12 + 20 + 5 ;
2012-05-27 14:21:41 +02:00
if ( sc -> interlaced && sc -> field_dominance )
desc_size += 5 ;
2015-05-24 02:43:26 +02:00
if ( sc -> signal_standard )
desc_size += 5 ;
2008-08-19 22:01:57 +00:00
2012-05-27 14:21:41 +02:00
mxf_write_generic_desc ( s , st , key , desc_size );
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 4 , 0x3203 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> codec -> width );
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 4 , 0x3202 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , stored_height >> sc -> interlaced );
2008-08-19 22:01:57 +00:00
2009-02-02 03:35:09 +00:00
mxf_write_local_tag ( pb , 4 , 0x3209 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> codec -> width );
2009-02-02 03:35:09 +00:00
2009-02-13 07:13:36 +00:00
if ( st -> codec -> height == 608 ) // PAL + VBI
display_height = 576 ;
else if ( st -> codec -> height == 512 ) // NTSC + VBI
display_height = 486 ;
else
display_height = st -> codec -> height ;
2009-02-02 03:35:09 +00:00
mxf_write_local_tag ( pb , 4 , 0x3208 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , display_height >> sc -> interlaced );
2009-02-02 03:35:09 +00:00
2015-03-30 11:11:17 +01:00
// presentation Y offset
mxf_write_local_tag ( pb , 4 , 0x320B );
avio_wb32 ( pb , ( st -> codec -> height - display_height ) >> sc -> interlaced );
2009-02-10 06:14:39 +00:00
// component depth
mxf_write_local_tag ( pb , 4 , 0x3301 );
2012-05-29 00:45:41 +02:00
avio_wb32 ( pb , sc -> component_depth );
2009-02-10 06:14:39 +00:00
// horizontal subsampling
mxf_write_local_tag ( pb , 4 , 0x3302 );
2015-05-16 20:02:01 +02:00
avio_wb32 ( pb , sc -> h_chroma_sub_sample );
2009-02-10 06:14:39 +00:00
2015-05-19 01:11:09 +02:00
// color siting
mxf_write_local_tag ( pb , 1 , 0x3303 );
avio_w8 ( pb , sc -> color_siting );
2015-05-24 02:43:26 +02:00
if ( sc -> signal_standard ) {
mxf_write_local_tag ( pb , 1 , 0x3215 );
avio_w8 ( pb , sc -> signal_standard );
}
2009-01-31 09:08:01 +00:00
// frame layout
mxf_write_local_tag ( pb , 1 , 0x320C );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , sc -> interlaced );
2009-01-31 09:08:01 +00:00
2009-01-31 09:23:50 +00:00
// video line map
switch ( st -> codec -> height ) {
2012-08-07 22:45:46 +02:00
case 576 : f1 = 23 ; f2 = st -> codec -> codec_id == AV_CODEC_ID_DVVIDEO ? 335 : 336 ; break ;
2009-01-31 09:23:50 +00:00
case 608 : f1 = 7 ; f2 = 320 ; break ;
2012-08-07 22:45:46 +02:00
case 480 : f1 = 20 ; f2 = st -> codec -> codec_id == AV_CODEC_ID_DVVIDEO ? 285 : 283 ; break ;
2009-01-31 09:23:50 +00:00
case 512 : f1 = 7 ; f2 = 270 ; break ;
case 720 : f1 = 26 ; f2 = 0 ; break ; // progressive
case 1080 : f1 = 21 ; f2 = 584 ; break ;
default : f1 = 0 ; f2 = 0 ; break ;
}
if ( ! sc -> interlaced ) {
f2 = 0 ;
f1 *= 2 ;
}
2009-02-02 10:10:41 +00:00
mxf_write_local_tag ( pb , 12 + sc -> interlaced * 4 , 0x320D );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , sc -> interlaced ? 2 : 1 );
avio_wb32 ( pb , 4 );
avio_wb32 ( pb , f1 );
2009-02-02 03:49:23 +00:00
if ( sc -> interlaced )
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , f2 );
2009-01-31 09:23:50 +00:00
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 8 , 0x320E );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , sc -> aspect_ratio . num );
avio_wb32 ( pb , sc -> aspect_ratio . den );
2009-01-31 06:49:42 +00:00
mxf_write_local_tag ( pb , 16 , 0x3201 );
2011-02-21 19:28:17 +01:00
avio_write ( pb , * sc -> codec_ul , 16 );
2012-05-27 14:21:41 +02:00
if ( sc -> interlaced && sc -> field_dominance ) {
mxf_write_local_tag ( pb , 1 , 0x3212 );
avio_w8 ( pb , sc -> field_dominance );
}
2008-08-19 22:01:57 +00:00
}
2009-02-13 07:28:20 +00:00
static void mxf_write_cdci_desc ( AVFormatContext * s , AVStream * st )
{
2009-02-18 00:12:05 +00:00
mxf_write_cdci_common ( s , st , mxf_cdci_descriptor_key , 0 );
2009-02-13 07:28:20 +00:00
}
2009-02-13 07:11:21 +00:00
static void mxf_write_mpegvideo_desc ( AVFormatContext * s , AVStream * st )
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2013-09-09 10:02:12 +02:00
MXFStreamContext * sc = st -> priv_data ;
2009-07-04 07:49:12 +00:00
int profile_and_level = ( st -> codec -> profile << 4 ) | st -> codec -> level ;
2009-02-13 07:11:21 +00:00
2014-10-28 22:38:22 +00:00
if ( st -> codec -> codec_id != AV_CODEC_ID_H264 ) {
2014-10-29 20:26:25 +00:00
mxf_write_cdci_common ( s , st , mxf_mpegvideo_descriptor_key , 8 + 5 );
2009-02-13 07:11:21 +00:00
2014-10-29 20:26:25 +00:00
// bit rate
mxf_write_local_tag ( pb , 4 , 0x8000 );
avio_wb32 ( pb , sc -> video_bit_rate );
2009-07-04 07:49:12 +00:00
2014-10-29 20:26:25 +00:00
// profile and level
mxf_write_local_tag ( pb , 1 , 0x8007 );
if ( ! st -> codec -> profile )
profile_and_level |= 0x80 ; // escape bit
avio_w8 ( pb , profile_and_level );
2014-10-28 22:38:22 +00:00
} else {
mxf_write_cdci_common ( s , st , mxf_mpegvideo_descriptor_key , 0 );
}
2009-02-13 07:11:21 +00:00
}
static void mxf_write_generic_sound_common ( AVFormatContext * s , AVStream * st , const UID key , unsigned size )
2008-08-19 22:01:57 +00:00
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2014-06-25 10:29:30 +00:00
MXFContext * mxf = s -> priv_data ;
int show_warnings = ! mxf -> footer_partition_offset ;
2015-04-11 17:18:13 -07:00
int duration_size = 0 ;
2008-08-19 22:01:57 +00:00
2015-04-11 17:18:13 -07:00
if ( s -> oformat == & ff_mxf_opatom_muxer )
duration_size = 12 ;
mxf_write_generic_desc ( s , st , key , size + duration_size + 5 + 12 + 8 + 8 );
if ( duration_size > 0 ){
mxf_write_local_tag ( pb , 8 , 0x3002 );
avio_wb64 ( pb , mxf -> body_offset / mxf -> edit_unit_byte_count );
}
2009-01-31 06:54:30 +00:00
2009-01-31 06:59:55 +00:00
// audio locked
2009-01-31 06:54:30 +00:00
mxf_write_local_tag ( pb , 1 , 0x3D02 );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 1 );
2008-08-19 22:01:57 +00:00
// write audio sampling rate
mxf_write_local_tag ( pb , 8 , 0x3D03 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> codec -> sample_rate );
avio_wb32 ( pb , 1 );
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 4 , 0x3D07 );
2014-06-25 10:29:30 +00:00
if ( mxf -> channel_count == - 1 ) {
if ( show_warnings && ( s -> oformat == & ff_mxf_d10_muxer ) && ( st -> codec -> channels != 4 ) && ( st -> codec -> channels != 8 ))
2014-06-26 16:10:45 +00:00
av_log ( s , AV_LOG_WARNING , "the number of audio channels shall be 4 or 8 : the output will not comply to MXF D-10 specs, use -d10_channelcount to fix this \n " );
2014-06-25 10:29:30 +00:00
avio_wb32 ( pb , st -> codec -> channels );
} else if ( s -> oformat == & ff_mxf_d10_muxer ) {
if ( show_warnings && ( mxf -> channel_count < st -> codec -> channels ))
2014-06-26 16:10:45 +00:00
av_log ( s , AV_LOG_WARNING , "d10_channelcount < actual number of audio channels : some channels will be discarded \n " );
2014-06-25 10:29:30 +00:00
if ( show_warnings && ( mxf -> channel_count != 4 ) && ( mxf -> channel_count != 8 ))
2014-06-26 16:10:45 +00:00
av_log ( s , AV_LOG_WARNING , "d10_channelcount shall be set to 4 or 8 : the output will not comply to MXF D-10 specs \n " );
2014-06-25 10:29:30 +00:00
avio_wb32 ( pb , mxf -> channel_count );
} else {
2015-04-11 17:18:13 -07:00
if ( show_warnings && mxf -> channel_count != - 1 && s -> oformat != & ff_mxf_opatom_muxer )
2014-06-26 16:10:45 +00:00
av_log ( s , AV_LOG_ERROR , "-d10_channelcount requires MXF D-10 and will be ignored \n " );
2014-06-25 10:29:30 +00:00
avio_wb32 ( pb , st -> codec -> channels );
}
2008-08-19 22:01:57 +00:00
mxf_write_local_tag ( pb , 4 , 0x3D01 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , av_get_bits_per_sample ( st -> codec -> codec_id ));
2008-08-19 22:01:57 +00:00
}
2009-02-13 07:11:21 +00:00
static void mxf_write_wav_common ( AVFormatContext * s , AVStream * st , const UID key , unsigned size )
2009-01-31 06:59:55 +00:00
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-02 04:36:54 +00:00
2009-02-18 00:12:05 +00:00
mxf_write_generic_sound_common ( s , st , key , size + 6 + 8 );
2009-02-02 04:36:54 +00:00
mxf_write_local_tag ( pb , 2 , 0x3D0A );
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , st -> codec -> block_align );
2009-02-02 04:36:54 +00:00
// avg bytes per sec
mxf_write_local_tag ( pb , 4 , 0x3D09 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , st -> codec -> block_align * st -> codec -> sample_rate );
2009-01-31 06:59:55 +00:00
}
2009-02-02 04:40:57 +00:00
static void mxf_write_wav_desc ( AVFormatContext * s , AVStream * st )
{
2009-02-18 00:12:05 +00:00
mxf_write_wav_common ( s , st , mxf_wav_descriptor_key , 0 );
2009-02-02 04:40:57 +00:00
}
2009-01-31 07:02:20 +00:00
static void mxf_write_aes3_desc ( AVFormatContext * s , AVStream * st )
{
2009-02-18 00:12:05 +00:00
mxf_write_wav_common ( s , st , mxf_aes3_descriptor_key , 0 );
2009-01-31 07:02:20 +00:00
}
2009-02-13 07:28:20 +00:00
static void mxf_write_generic_sound_desc ( AVFormatContext * s , AVStream * st )
{
2009-02-18 00:12:05 +00:00
mxf_write_generic_sound_common ( s , st , mxf_generic_sound_descriptor_key , 0 );
2009-02-13 07:28:20 +00:00
}
2015-03-14 17:59:50 -07:00
static const uint8_t mxf_indirect_value_utf16le [] = { 0x4c , 0x00 , 0x02 , 0x10 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x06 , 0x0e , 0x2b , 0x34 , 0x01 , 0x04 , 0x01 , 0x01 };
static int mxf_write_tagged_value ( AVFormatContext * s , const char * name , const char * value )
{
MXFContext * mxf = s -> priv_data ;
AVIOContext * pb = s -> pb ;
int name_size = mxf_utf16_local_tag_length ( name );
int indirect_value_size = 13 + mxf_utf16_local_tag_length ( value );
if ( ! name_size || indirect_value_size == 13 )
return 1 ;
mxf_write_metadata_key ( pb , 0x013f00 );
klv_encode_ber_length ( pb , 24 + name_size + indirect_value_size );
// write instance UID
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , TaggedValue , mxf -> tagged_value_count );
// write name
mxf_write_local_tag_utf16 ( pb , 0x5001 , name ); // Name
// write indirect value
mxf_write_local_tag ( pb , indirect_value_size , 0x5003 );
avio_write ( pb , mxf_indirect_value_utf16le , 17 );
avio_put_str16le ( pb , value );
mxf -> tagged_value_count ++ ;
return 0 ;
}
static int mxf_write_user_comments ( AVFormatContext * s , const AVDictionary * m )
{
MXFContext * mxf = s -> priv_data ;
AVDictionaryEntry * t = NULL ;
int count = 0 ;
while (( t = av_dict_get ( m , "comment_" , t , AV_DICT_IGNORE_SUFFIX ))) {
if ( mxf -> tagged_value_count >= UINT16_MAX ) {
av_log ( s , AV_LOG_ERROR , "too many tagged values, ignoring remaining \n " );
return count ;
}
if ( mxf_write_tagged_value ( s , t -> key + 8 , t -> value ) == 0 )
count ++ ;
}
return count ;
}
2015-03-05 10:59:11 -08:00
static void mxf_write_package ( AVFormatContext * s , enum MXFMetadataSetType type , const char * package_name )
2008-08-31 04:24:00 +00:00
{
2009-02-05 20:15:18 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-18 01:35:36 +00:00
int i , track_count = s -> nb_streams + 1 ;
2015-03-05 10:59:11 -08:00
int name_size = mxf_utf16_local_tag_length ( package_name );
2015-03-14 17:59:50 -07:00
int user_comment_count = 0 ;
2008-08-31 04:24:00 +00:00
if ( type == MaterialPackage ) {
2015-03-14 17:59:50 -07:00
user_comment_count = mxf_write_user_comments ( s , s -> metadata );
2008-08-31 04:24:00 +00:00
mxf_write_metadata_key ( pb , 0x013600 );
PRINT_KEY ( s , "Material Package key" , pb -> buf_ptr - 16 );
2015-03-14 17:59:50 -07:00
klv_encode_ber_length ( pb , 104 + name_size + ( 16 * track_count ) + ( 16 * user_comment_count ));
2008-08-31 04:24:00 +00:00
} else {
mxf_write_metadata_key ( pb , 0x013700 );
PRINT_KEY ( s , "Source Package key" , pb -> buf_ptr - 16 );
2015-03-14 17:59:50 -07:00
klv_encode_ber_length ( pb , 124 + name_size + ( 16 * track_count )); // 20 bytes length for descriptor reference
2008-08-31 04:24:00 +00:00
}
// write uid
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , type , 0 );
av_log ( s , AV_LOG_DEBUG , "package type:%d \n " , type );
PRINT_KEY ( s , "package uid" , pb -> buf_ptr - 16 );
// write package umid
mxf_write_local_tag ( pb , 32 , 0x4401 );
2009-03-11 06:15:00 +00:00
mxf_write_umid ( s , type == SourcePackage );
2008-08-31 04:24:00 +00:00
PRINT_KEY ( s , "package umid second part" , pb -> buf_ptr - 16 );
2015-03-05 10:59:11 -08:00
// package name
if ( name_size )
mxf_write_local_tag_utf16 ( pb , 0x4402 , package_name );
2009-02-05 20:15:18 +00:00
// package creation date
2008-08-31 04:24:00 +00:00
mxf_write_local_tag ( pb , 8 , 0x4405 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> timestamp );
2008-08-31 04:24:00 +00:00
2009-02-05 20:15:18 +00:00
// package modified date
2008-08-31 04:24:00 +00:00
mxf_write_local_tag ( pb , 8 , 0x4404 );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> timestamp );
2008-08-31 04:24:00 +00:00
// write track refs
2009-02-11 07:18:00 +00:00
mxf_write_local_tag ( pb , track_count * 16 + 8 , 0x4403 );
mxf_write_refs_count ( pb , track_count );
2009-02-18 01:35:36 +00:00
mxf_write_uuid ( pb , type == MaterialPackage ? Track :
Track + TypeBottom , - 1 ); // timecode track
2008-08-31 04:24:00 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ )
mxf_write_uuid ( pb , type == MaterialPackage ? Track : Track + TypeBottom , i );
2015-03-14 17:59:50 -07:00
// write user comment refs
mxf_write_local_tag ( pb , user_comment_count * 16 + 8 , 0x4406 );
mxf_write_refs_count ( pb , user_comment_count );
for ( i = 0 ; i < user_comment_count ; i ++ )
mxf_write_uuid ( pb , TaggedValue , mxf -> tagged_value_count - user_comment_count + i );
2008-08-31 04:24:00 +00:00
// write multiple descriptor reference
if ( type == SourcePackage ) {
mxf_write_local_tag ( pb , 16 , 0x4701 );
2008-08-31 04:35:09 +00:00
if ( s -> nb_streams > 1 ) {
mxf_write_uuid ( pb , MultipleDescriptor , 0 );
mxf_write_multi_descriptor ( s );
} else
mxf_write_uuid ( pb , SubDescriptor , 0 );
2008-08-31 04:26:12 +00:00
}
2008-08-19 22:01:57 +00:00
2009-02-18 01:35:36 +00:00
// write timecode track
mxf_write_track ( s , mxf -> timecode_track , type );
mxf_write_sequence ( s , mxf -> timecode_track , type );
mxf_write_timecode_component ( s , mxf -> timecode_track , type );
2008-08-31 01:44:45 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
2008-08-31 01:48:02 +00:00
AVStream * st = s -> streams [ i ];
mxf_write_track ( s , st , type );
mxf_write_sequence ( s , st , type );
mxf_write_structural_component ( s , st , type );
2008-08-19 22:01:57 +00:00
if ( type == SourcePackage ) {
2008-08-31 04:07:41 +00:00
MXFStreamContext * sc = st -> priv_data ;
2008-08-31 04:13:44 +00:00
mxf_essence_container_uls [ sc -> index ]. write_desc ( s , st );
2008-08-19 22:01:57 +00:00
}
}
}
2009-01-23 20:57:12 +00:00
static int mxf_write_essence_container_data ( AVFormatContext * s )
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-01-23 20:57:12 +00:00
mxf_write_metadata_key ( pb , 0x012300 );
2009-02-02 10:03:38 +00:00
klv_encode_ber_length ( pb , 72 );
2009-01-23 20:57:12 +00:00
mxf_write_local_tag ( pb , 16 , 0x3C0A ); // Instance UID
mxf_write_uuid ( pb , EssenceContainerData , 0 );
mxf_write_local_tag ( pb , 32 , 0x2701 ); // Linked Package UID
2009-03-11 06:15:00 +00:00
mxf_write_umid ( s , 1 );
2009-01-23 20:57:12 +00:00
mxf_write_local_tag ( pb , 4 , 0x3F07 ); // BodySID
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 1 );
2009-01-23 20:57:12 +00:00
2009-02-02 10:03:38 +00:00
mxf_write_local_tag ( pb , 4 , 0x3F06 ); // IndexSID
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 2 );
2009-02-02 10:03:38 +00:00
2009-01-23 20:57:12 +00:00
return 0 ;
}
2008-08-19 12:36:17 +00:00
static int mxf_write_header_metadata_sets ( AVFormatContext * s )
{
2015-03-05 10:59:11 -08:00
const char * material_package_name = NULL ;
const char * file_package_name = NULL ;
AVDictionaryEntry * entry = NULL ;
AVStream * st = NULL ;
int i ;
if ( entry = av_dict_get ( s -> metadata , "material_package_name" , NULL , 0 ))
material_package_name = entry -> value ;
if ( entry = av_dict_get ( s -> metadata , "file_package_name" , NULL , 0 )) {
file_package_name = entry -> value ;
} else {
/* check if any of the streams contain a file_package_name */
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
st = s -> streams [ i ];
if ( entry = av_dict_get ( st -> metadata , "file_package_name" , NULL , 0 )) {
file_package_name = entry -> value ;
break ;
}
}
}
2008-08-22 04:12:52 +00:00
mxf_write_preface ( s );
mxf_write_identification ( s );
mxf_write_content_storage ( s );
2015-03-05 10:59:11 -08:00
mxf_write_package ( s , MaterialPackage , material_package_name );
mxf_write_package ( s , SourcePackage , file_package_name );
2009-01-23 20:57:12 +00:00
mxf_write_essence_container_data ( s );
2008-08-19 12:36:17 +00:00
return 0 ;
}
2009-02-08 03:29:49 +00:00
static unsigned klv_fill_size ( uint64_t size )
2009-02-07 02:13:23 +00:00
{
2009-02-08 03:29:49 +00:00
unsigned pad = KAG_SIZE - ( size & ( KAG_SIZE - 1 ));
2009-02-13 05:33:11 +00:00
if ( pad < 20 ) // smallest fill item possible
2009-02-07 02:13:23 +00:00
return pad + KAG_SIZE ;
else
return pad & ( KAG_SIZE - 1 );
}
2009-02-08 09:42:37 +00:00
static void mxf_write_index_table_segment ( AVFormatContext * s )
2009-02-02 10:03:38 +00:00
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2010-07-02 08:35:47 +00:00
int i , j , temporal_reordering = 0 ;
2009-02-11 01:06:12 +00:00
int key_index = mxf -> last_key_index ;
2009-02-02 10:03:38 +00:00
av_log ( s , AV_LOG_DEBUG , "edit units count %d \n " , mxf -> edit_units_count );
2009-02-13 07:28:20 +00:00
if ( ! mxf -> edit_units_count && ! mxf -> edit_unit_byte_count )
2009-02-10 09:02:29 +00:00
return ;
2011-02-21 19:28:17 +01:00
avio_write ( pb , index_table_segment_key , 16 );
2009-02-13 07:28:20 +00:00
if ( mxf -> edit_unit_byte_count ) {
2009-02-18 02:13:59 +00:00
klv_encode_ber_length ( pb , 80 );
2009-02-13 07:28:20 +00:00
} else {
2012-10-24 17:06:49 +02:00
klv_encode_ber_length ( pb , 85 + 12 + ( s -> nb_streams + 1LL ) * 6 +
12 + mxf -> edit_units_count * ( 11 + mxf -> slice_count * 4LL ));
2009-02-13 07:28:20 +00:00
}
2009-02-02 10:03:38 +00:00
// instance id
mxf_write_local_tag ( pb , 16 , 0x3C0A );
mxf_write_uuid ( pb , IndexTableSegment , 0 );
// index edit rate
mxf_write_local_tag ( pb , 8 , 0x3F0B );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> time_base . den );
avio_wb32 ( pb , mxf -> time_base . num );
2009-02-02 10:03:38 +00:00
// index start position
mxf_write_local_tag ( pb , 8 , 0x3F0C );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> last_indexed_edit_unit );
2009-02-02 10:03:38 +00:00
// index duration
mxf_write_local_tag ( pb , 8 , 0x3F0D );
2009-07-04 07:56:58 +00:00
if ( mxf -> edit_unit_byte_count )
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 ); // index table covers whole container
2009-07-04 07:56:58 +00:00
else
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> edit_units_count );
2009-02-02 10:03:38 +00:00
// edit unit byte count
mxf_write_local_tag ( pb , 4 , 0x3F05 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> edit_unit_byte_count );
2009-02-02 10:03:38 +00:00
// index sid
mxf_write_local_tag ( pb , 4 , 0x3F06 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 2 );
2009-02-02 10:03:38 +00:00
// body sid
mxf_write_local_tag ( pb , 4 , 0x3F07 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 1 );
2009-02-02 10:03:38 +00:00
2009-02-13 07:28:20 +00:00
if ( ! mxf -> edit_unit_byte_count ) {
2009-02-18 02:13:59 +00:00
// real slice count - 1
mxf_write_local_tag ( pb , 1 , 0x3F08 );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , mxf -> slice_count );
2009-02-18 02:13:59 +00:00
2009-02-13 07:34:01 +00:00
// delta entry array
mxf_write_local_tag ( pb , 8 + ( s -> nb_streams + 1 ) * 6 , 0x3F09 );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , s -> nb_streams + 1 ); // num of entries
avio_wb32 ( pb , 6 ); // size of one entry
2009-02-13 07:34:01 +00:00
// write system item delta entry
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0 );
avio_w8 ( pb , 0 ); // slice entry
avio_wb32 ( pb , 0 ); // element delta
2009-02-13 07:34:01 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
AVStream * st = s -> streams [ i ];
MXFStreamContext * sc = st -> priv_data ;
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , sc -> temporal_reordering );
2009-02-13 07:34:01 +00:00
if ( sc -> temporal_reordering )
temporal_reordering = 1 ;
if ( i == 0 ) { // video track
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0 ); // slice number
avio_wb32 ( pb , KAG_SIZE ); // system item size including klv fill
2009-02-13 07:34:01 +00:00
} else { // audio track
unsigned audio_frame_size = sc -> aic . samples [ 0 ] * sc -> aic . sample_size ;
audio_frame_size += klv_fill_size ( audio_frame_size );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 1 );
avio_wb32 ( pb , ( i - 1 ) * audio_frame_size ); // element delta
2009-02-02 10:03:38 +00:00
}
2009-02-05 07:47:39 +00:00
}
2009-02-10 09:02:29 +00:00
2009-02-13 07:34:01 +00:00
mxf_write_local_tag ( pb , 8 + mxf -> edit_units_count * ( 11 + mxf -> slice_count * 4 ), 0x3F0A );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> edit_units_count ); // num of entries
avio_wb32 ( pb , 11 + mxf -> slice_count * 4 ); // size of one entry
2010-07-02 08:35:47 +00:00
2009-02-13 07:34:01 +00:00
for ( i = 0 ; i < mxf -> edit_units_count ; i ++ ) {
2009-06-30 07:41:40 +00:00
int temporal_offset = 0 ;
2010-07-02 08:35:47 +00:00
if ( ! ( mxf -> index_entries [ i ]. flags & 0x33 )) { // I frame
mxf -> last_key_index = key_index ;
key_index = i ;
}
2009-02-13 07:34:01 +00:00
if ( temporal_reordering ) {
2010-07-02 08:35:47 +00:00
int pic_num_in_gop = i - key_index ;
if ( pic_num_in_gop != mxf -> index_entries [ i ]. temporal_ref ) {
for ( j = key_index ; j < mxf -> edit_units_count ; j ++ ) {
if ( pic_num_in_gop == mxf -> index_entries [ j ]. temporal_ref )
break ;
2009-02-13 07:34:01 +00:00
}
2010-07-02 08:35:47 +00:00
if ( j == mxf -> edit_units_count )
av_log ( s , AV_LOG_WARNING , "missing frames \n " );
temporal_offset = j - key_index - pic_num_in_gop ;
2009-02-13 07:34:01 +00:00
}
2009-06-30 07:41:40 +00:00
}
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , temporal_offset );
2009-06-30 07:41:40 +00:00
if (( mxf -> index_entries [ i ]. flags & 0x30 ) == 0x30 ) { // back and forward prediction
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , mxf -> last_key_index - i );
2009-02-13 07:34:01 +00:00
} else {
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , key_index - i ); // key frame offset
2009-02-13 07:34:01 +00:00
if (( mxf -> index_entries [ i ]. flags & 0x20 ) == 0x20 ) // only forward
mxf -> last_key_index = key_index ;
}
2010-07-02 08:35:47 +00:00
if ( ! ( mxf -> index_entries [ i ]. flags & 0x33 ) && // I frame
mxf -> index_entries [ i ]. flags & 0x40 && ! temporal_offset )
mxf -> index_entries [ i ]. flags |= 0x80 ; // random access
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , mxf -> index_entries [ i ]. flags );
2009-02-13 07:34:01 +00:00
// stream offset
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> index_entries [ i ]. offset );
2009-02-13 07:34:01 +00:00
if ( s -> nb_streams > 1 )
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , mxf -> index_entries [ i ]. slice_offset );
2009-02-13 07:34:01 +00:00
}
mxf -> last_key_index = key_index - mxf -> edit_units_count ;
mxf -> last_indexed_edit_unit += mxf -> edit_units_count ;
mxf -> edit_units_count = 0 ;
2009-02-13 07:28:20 +00:00
}
2009-02-02 10:03:38 +00:00
}
2009-02-10 05:35:28 +00:00
static void mxf_write_klv_fill ( AVFormatContext * s )
{
2011-03-03 20:11:45 +01:00
unsigned pad = klv_fill_size ( avio_tell ( s -> pb ));
2009-02-10 05:35:28 +00:00
if ( pad ) {
2011-02-21 19:28:17 +01:00
avio_write ( s -> pb , klv_fill_key , 16 );
2009-02-13 05:33:11 +00:00
pad -= 16 + 4 ;
klv_encode_ber4_length ( s -> pb , pad );
2013-07-15 17:39:55 +00:00
ffio_fill ( s -> pb , 0 , pad );
2012-07-12 23:16:24 +02:00
av_assert1 ( ! ( avio_tell ( s -> pb ) & ( KAG_SIZE - 1 )));
2009-02-10 05:35:28 +00:00
}
}
2013-08-02 19:21:24 +02:00
static int mxf_write_partition ( AVFormatContext * s , int bodysid ,
2009-02-10 08:46:04 +00:00
int indexsid ,
2009-02-02 10:03:38 +00:00
const uint8_t * key , int write_metadata )
2008-08-24 05:55:46 +00:00
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-31 03:42:05 +00:00
int64_t header_byte_count_offset ;
2009-02-10 08:46:04 +00:00
unsigned index_byte_count = 0 ;
2011-03-03 20:11:45 +01:00
uint64_t partition_offset = avio_tell ( pb );
2013-08-02 19:21:24 +02:00
int err ;
2009-02-10 08:46:04 +00:00
2009-02-13 07:28:20 +00:00
if ( ! mxf -> edit_unit_byte_count && mxf -> edit_units_count )
index_byte_count = 85 + 12 + ( s -> nb_streams + 1 ) * 6 +
12 + mxf -> edit_units_count * ( 11 + mxf -> slice_count * 4 );
else if ( mxf -> edit_unit_byte_count && indexsid )
2009-02-18 07:14:23 +00:00
index_byte_count = 80 ;
2009-02-13 07:28:20 +00:00
if ( index_byte_count ) {
2009-02-10 08:46:04 +00:00
// add encoded ber length
index_byte_count += 16 + klv_ber_length ( index_byte_count );
index_byte_count += klv_fill_size ( index_byte_count );
2009-02-10 09:02:29 +00:00
}
2015-01-28 19:44:21 -08:00
if ( key && ! memcmp ( key , body_partition_key , 16 )) {
2013-08-02 19:21:24 +02:00
if (( err = av_reallocp_array ( & mxf -> body_partition_offset , mxf -> body_partitions_count + 1 ,
sizeof ( * mxf -> body_partition_offset ))) < 0 ) {
mxf -> body_partitions_count = 0 ;
return err ;
}
2009-02-10 23:25:23 +00:00
mxf -> body_partition_offset [ mxf -> body_partitions_count ++ ] = partition_offset ;
2009-02-10 08:46:04 +00:00
}
2008-08-30 22:58:49 +00:00
2008-08-24 05:55:46 +00:00
// write klv
2015-01-28 19:44:21 -08:00
if ( key )
avio_write ( pb , key , 16 );
else
avio_write ( pb , body_partition_key , 16 );
2012-10-25 10:23:59 +02:00
klv_encode_ber_length ( pb , 88 + 16LL * DESCRIPTOR_COUNT ( mxf -> essence_container_count ));
2008-08-24 05:55:46 +00:00
// write partition value
2011-02-21 19:28:17 +01:00
avio_wb16 ( pb , 1 ); // majorVersion
avio_wb16 ( pb , 2 ); // minorVersion
avio_wb32 ( pb , KAG_SIZE ); // KAGSize
2008-08-24 05:55:46 +00:00
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , partition_offset ); // ThisPartition
2009-02-10 09:02:29 +00:00
2015-01-28 19:44:21 -08:00
if ( key && ! memcmp ( key , body_partition_key , 16 ) && mxf -> body_partitions_count > 1 )
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> body_partition_offset [ mxf -> body_partitions_count - 2 ]); // PreviousPartition
2015-01-28 19:44:21 -08:00
else if ( key && ! memcmp ( key , footer_partition_key , 16 ) && mxf -> body_partitions_count )
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> body_partition_offset [ mxf -> body_partitions_count - 1 ]); // PreviousPartition
2009-02-10 09:02:29 +00:00
else
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-24 05:55:46 +00:00
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> footer_partition_offset ); // footerPartition
2008-08-24 05:55:46 +00:00
// set offset
2011-03-03 20:11:45 +01:00
header_byte_count_offset = avio_tell ( pb );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 ); // headerByteCount, update later
2008-08-24 05:55:46 +00:00
2009-02-02 10:03:38 +00:00
// indexTable
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , index_byte_count ); // indexByteCount
avio_wb32 ( pb , index_byte_count ? indexsid : 0 ); // indexSID
2009-02-10 09:02:29 +00:00
// BodyOffset
2015-01-28 19:44:21 -08:00
if ( bodysid && mxf -> edit_units_count && mxf -> body_partitions_count && s -> oformat != & ff_mxf_opatom_muxer )
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , mxf -> body_offset );
2015-01-28 19:44:21 -08:00
else
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , 0 );
2008-08-24 05:55:46 +00:00
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , bodysid ); // bodySID
2009-02-10 04:53:41 +00:00
// operational pattern
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer )
avio_write ( pb , opatom_ul , 16 );
else
avio_write ( pb , op1a_ul , 16 );
2008-08-24 05:55:46 +00:00
// essence container
2008-08-31 00:28:36 +00:00
mxf_write_essence_container_refs ( s );
2008-08-31 03:36:25 +00:00
if ( write_metadata ) {
// mark the start of the headermetadata and calculate metadata size
2009-02-10 06:09:50 +00:00
int64_t pos , start ;
2009-02-07 02:13:23 +00:00
unsigned header_byte_count ;
2009-02-10 05:35:28 +00:00
mxf_write_klv_fill ( s );
2011-03-03 20:11:45 +01:00
start = avio_tell ( s -> pb );
2008-08-31 03:36:25 +00:00
mxf_write_primer_pack ( s );
mxf_write_header_metadata_sets ( s );
2011-03-03 20:11:45 +01:00
pos = avio_tell ( s -> pb );
2009-02-08 03:29:49 +00:00
header_byte_count = pos - start + klv_fill_size ( pos );
2009-02-07 02:13:23 +00:00
2008-08-31 03:36:25 +00:00
// update header_byte_count
2011-02-28 14:57:54 +01:00
avio_seek ( pb , header_byte_count_offset , SEEK_SET );
2011-02-21 19:28:17 +01:00
avio_wb64 ( pb , header_byte_count );
2011-02-28 14:57:54 +01:00
avio_seek ( pb , pos , SEEK_SET );
2008-08-31 03:36:25 +00:00
}
2015-01-28 19:44:21 -08:00
if ( key )
avio_flush ( pb );
2013-08-02 19:21:24 +02:00
return 0 ;
2008-08-24 05:55:46 +00:00
}
2012-05-29 00:45:41 +02:00
static int mxf_parse_dnxhd_frame ( AVFormatContext * s , AVStream * st ,
AVPacket * pkt )
{
MXFContext * mxf = s -> priv_data ;
MXFStreamContext * sc = st -> priv_data ;
int i , cid ;
uint8_t * header_cid ;
2013-01-04 21:18:57 +01:00
int frame_size = 0 ;
2012-05-29 00:45:41 +02:00
if ( mxf -> header_written )
return 1 ;
if ( pkt -> size < 43 )
return - 1 ;
header_cid = pkt -> data + 0x28 ;
cid = header_cid [ 0 ] << 24 | header_cid [ 1 ] << 16 | header_cid [ 2 ] << 8 | header_cid [ 3 ];
2013-01-04 21:18:57 +01:00
if (( frame_size = avpriv_dnxhd_get_frame_size ( cid )) < 0 )
2012-05-29 00:45:41 +02:00
return - 1 ;
2015-05-04 17:44:14 +02:00
if (( sc -> interlaced = avpriv_dnxhd_get_interlaced ( cid )) < 0 )
return AVERROR_INVALIDDATA ;
2012-05-29 00:45:41 +02:00
switch ( cid ) {
case 1235 :
sc -> index = 24 ;
sc -> component_depth = 10 ;
break ;
case 1237 :
sc -> index = 25 ;
break ;
case 1238 :
sc -> index = 26 ;
break ;
case 1241 :
sc -> index = 27 ;
sc -> component_depth = 10 ;
break ;
case 1242 :
sc -> index = 28 ;
break ;
case 1243 :
sc -> index = 29 ;
break ;
case 1250 :
sc -> index = 30 ;
sc -> component_depth = 10 ;
break ;
case 1251 :
sc -> index = 31 ;
break ;
case 1252 :
sc -> index = 32 ;
break ;
case 1253 :
sc -> index = 33 ;
break ;
default :
return - 1 ;
}
2012-07-09 19:29:42 +02:00
sc -> codec_ul = & mxf_essence_container_uls [ sc -> index ]. codec_ul ;
sc -> aspect_ratio = ( AVRational ){ 16 , 9 };
2012-05-29 00:45:41 +02:00
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer ){
mxf -> edit_unit_byte_count = frame_size ;
return 1 ;
}
2012-05-29 00:45:41 +02:00
mxf -> edit_unit_byte_count = KAG_SIZE ;
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
AVStream * st = s -> streams [ i ];
MXFStreamContext * sc = st -> priv_data ;
if ( st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO ) {
mxf -> edit_unit_byte_count += 16 + 4 + sc -> aic . samples [ 0 ] * sc -> aic . sample_size ;
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
} else if ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO ) {
mxf -> edit_unit_byte_count += 16 + 4 + frame_size ;
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
}
}
return 1 ;
}
2012-05-26 18:09:47 +02:00
static int mxf_parse_dv_frame ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
MXFContext * mxf = s -> priv_data ;
MXFStreamContext * sc = st -> priv_data ;
uint8_t * vs_pack , * vsc_pack ;
int i , ul_index , frame_size , stype , pal ;
if ( mxf -> header_written )
return 1 ;
// Check for minimal frame size
if ( pkt -> size < 120000 )
return - 1 ;
vs_pack = pkt -> data + 80 * 5 + 48 ;
vsc_pack = pkt -> data + 80 * 5 + 53 ;
stype = vs_pack [ 3 ] & 0x1f ;
pal = ( vs_pack [ 3 ] >> 5 ) & 0x1 ;
if (( vs_pack [ 2 ] & 0x07 ) == 0x02 )
sc -> aspect_ratio = ( AVRational ){ 16 , 9 };
else
sc -> aspect_ratio = ( AVRational ){ 4 , 3 };
sc -> interlaced = ( vsc_pack [ 3 ] >> 4 ) & 0x01 ;
// TODO: fix dv encoder to set proper FF/FS value in VSC pack
// and set field dominance accordingly
// av_log(s, AV_LOG_DEBUG, "DV vsc pack ff/ss = %x\n", vsc_pack[2] >> 6);
switch ( stype ) {
case 0x18 : // DV100 720p
ul_index = 6 + pal ;
frame_size = pal ? 288000 : 240000 ;
if ( sc -> interlaced ) {
2012-09-01 12:35:14 +02:00
av_log ( s , AV_LOG_ERROR , "source marked as interlaced but codec profile is progressive \n " );
2012-05-26 18:09:47 +02:00
sc -> interlaced = 0 ;
}
break ;
case 0x14 : // DV100 1080i
ul_index = 4 + pal ;
frame_size = pal ? 576000 : 480000 ;
break ;
case 0x04 : // DV50
ul_index = 2 + pal ;
frame_size = pal ? 288000 : 240000 ;
break ;
default : // DV25
ul_index = 0 + pal ;
frame_size = pal ? 144000 : 120000 ;
}
sc -> index = ul_index + 16 ;
sc -> codec_ul = & mxf_essence_container_uls [ sc -> index ]. codec_ul ;
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer ) {
mxf -> edit_unit_byte_count = frame_size ;
return 1 ;
}
2012-05-26 18:09:47 +02:00
mxf -> edit_unit_byte_count = KAG_SIZE ;
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
AVStream * st = s -> streams [ i ];
MXFStreamContext * sc = st -> priv_data ;
if ( st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO ) {
mxf -> edit_unit_byte_count += 16 + 4 + sc -> aic . samples [ 0 ] * sc -> aic . sample_size ;
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
} else if ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO ) {
mxf -> edit_unit_byte_count += 16 + 4 + frame_size ;
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
}
}
return 1 ;
}
2014-10-28 22:38:22 +00:00
static const struct {
UID uid ;
int frame_size ;
int profile ;
uint8_t interlaced ;
} mxf_h264_codec_uls [] = {
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x20 , 0x01 }, 0 , 110 , 0 }, // AVC High 10 Intra
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x01 }, 232960 , 0 , 1 }, // AVC Intra 50 1080i60
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x02 }, 281088 , 0 , 1 }, // AVC Intra 50 1080i50
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x03 }, 232960 , 0 , 0 }, // AVC Intra 50 1080p30
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x04 }, 281088 , 0 , 0 }, // AVC Intra 50 1080p25
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x08 }, 116736 , 0 , 0 }, // AVC Intra 50 720p60
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x09 }, 140800 , 0 , 0 }, // AVC Intra 50 720p50
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x30 , 0x01 }, 0 , 122 , 0 }, // AVC High 422 Intra
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x01 }, 472576 , 0 , 1 }, // AVC Intra 100 1080i60
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x02 }, 568832 , 0 , 1 }, // AVC Intra 100 1080i50
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x03 }, 472576 , 0 , 0 }, // AVC Intra 100 1080p30
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x04 }, 568832 , 0 , 0 }, // AVC Intra 100 1080p25
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x08 }, 236544 , 0 , 0 }, // AVC Intra 100 720p60
{{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x09 }, 284672 , 0 , 0 }, // AVC Intra 100 720p50
};
static int mxf_parse_h264_frame ( AVFormatContext * s , AVStream * st ,
AVPacket * pkt , MXFIndexEntry * e )
{
MXFContext * mxf = s -> priv_data ;
MXFStreamContext * sc = st -> priv_data ;
static const int mxf_h264_num_codec_uls = sizeof ( mxf_h264_codec_uls ) / sizeof ( mxf_h264_codec_uls [ 0 ]);
const uint8_t * buf = pkt -> data ;
const uint8_t * buf_end = pkt -> data + pkt -> size ;
uint32_t state = - 1 ;
int extra_size = 512 ; // support AVC Intra files without SPS/PPS header
int i , frame_size ;
uint8_t uid_found ;
if ( pkt -> size > extra_size )
buf_end -= pkt -> size - extra_size ; // no need to parse beyond SPS/PPS header
for (;;) {
buf = avpriv_find_start_code ( buf , buf_end , & state );
if ( buf >= buf_end )
break ;
-- buf ;
switch ( state & 0x1f ) {
case NAL_SPS :
st -> codec -> profile = buf [ 1 ];
e -> flags |= 0x40 ;
break ;
case NAL_PPS :
if ( e -> flags & 0x40 ) { // sequence header present
e -> flags |= 0x80 ; // random access
extra_size = 0 ;
buf = buf_end ;
}
break ;
default :
break ;
}
}
if ( mxf -> header_written )
return 1 ;
sc -> aspect_ratio = ( AVRational ){ 16 , 9 }; // 16:9 is mandatory for broadcast HD
sc -> component_depth = 10 ; // AVC Intra is always 10 Bit
sc -> interlaced = st -> codec -> field_order != AV_FIELD_PROGRESSIVE ? 1 : 0 ;
if ( sc -> interlaced )
sc -> field_dominance = 1 ; // top field first is mandatory for AVC Intra
uid_found = 0 ;
frame_size = pkt -> size + extra_size ;
for ( i = 0 ; i < mxf_h264_num_codec_uls ; i ++ ) {
if ( frame_size == mxf_h264_codec_uls [ i ]. frame_size && sc -> interlaced == mxf_h264_codec_uls [ i ]. interlaced ) {
sc -> codec_ul = & mxf_h264_codec_uls [ i ]. uid ;
return 1 ;
} else if ( st -> codec -> profile == mxf_h264_codec_uls [ i ]. profile ) {
sc -> codec_ul = & mxf_h264_codec_uls [ i ]. uid ;
uid_found = 1 ;
}
}
if ( ! uid_found ) {
av_log ( s , AV_LOG_ERROR , "AVC Intra 50/100 supported only \n " );
return 0 ;
}
return 1 ;
}
2008-08-31 02:41:31 +00:00
static const UID mxf_mpeg2_codec_uls [] = {
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x01 , 0x10 , 0x00 }, // MP-ML I-Frame
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x01 , 0x11 , 0x00 }, // MP-ML Long GOP
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x02 , 0x00 }, // 422P-ML I-Frame
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x03 , 0x00 }, // 422P-ML Long GOP
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x03 , 0x02 , 0x00 }, // MP-HL I-Frame
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x03 , 0x03 , 0x00 }, // MP-HL Long GOP
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x04 , 0x02 , 0x00 }, // 422P-HL I-Frame
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x04 , 0x03 , 0x00 }, // 422P-HL Long GOP
2011-09-16 18:16:30 +02:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x05 , 0x02 , 0x00 }, // MP@H-14 I-Frame
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x05 , 0x03 , 0x00 }, // MP@H-14 Long GOP
2008-08-31 02:41:31 +00:00
};
static const UID * mxf_get_mpeg2_codec_ul ( AVCodecContext * avctx )
{
2009-07-04 08:02:01 +00:00
int long_gop = avctx -> gop_size > 1 || avctx -> has_b_frames ;
2008-08-31 02:41:31 +00:00
if ( avctx -> profile == 4 ) { // Main
if ( avctx -> level == 8 ) // Main
2009-07-04 08:02:01 +00:00
return & mxf_mpeg2_codec_uls [ 0 + long_gop ];
2008-08-31 02:41:31 +00:00
else if ( avctx -> level == 4 ) // High
2009-07-04 08:02:01 +00:00
return & mxf_mpeg2_codec_uls [ 4 + long_gop ];
2011-09-16 18:16:30 +02:00
else if ( avctx -> level == 6 ) // High 14
return & mxf_mpeg2_codec_uls [ 8 + long_gop ];
2008-08-31 02:41:31 +00:00
} else if ( avctx -> profile == 0 ) { // 422
if ( avctx -> level == 5 ) // Main
2009-07-04 08:02:01 +00:00
return & mxf_mpeg2_codec_uls [ 2 + long_gop ];
2008-08-31 02:41:31 +00:00
else if ( avctx -> level == 2 ) // High
2009-07-04 08:02:01 +00:00
return & mxf_mpeg2_codec_uls [ 6 + long_gop ];
2008-08-31 02:41:31 +00:00
}
return NULL ;
}
2010-07-02 08:35:47 +00:00
static int mxf_parse_mpeg2_frame ( AVFormatContext * s , AVStream * st ,
AVPacket * pkt , MXFIndexEntry * e )
2009-01-31 06:32:12 +00:00
{
MXFStreamContext * sc = st -> priv_data ;
uint32_t c = - 1 ;
int i ;
for ( i = 0 ; i < pkt -> size - 4 ; i ++ ) {
c = ( c << 8 ) + pkt -> data [ i ];
2009-06-30 07:43:32 +00:00
if ( c == 0x1b5 ) {
2009-05-15 04:43:44 +00:00
if (( pkt -> data [ i + 1 ] & 0xf0 ) == 0x10 ) { // seq ext
2009-01-31 06:32:12 +00:00
st -> codec -> profile = pkt -> data [ i + 1 ] & 0x07 ;
st -> codec -> level = pkt -> data [ i + 2 ] >> 4 ;
2009-01-31 06:42:47 +00:00
} else if ( i + 5 < pkt -> size && ( pkt -> data [ i + 1 ] & 0xf0 ) == 0x80 ) { // pict coding ext
sc -> interlaced = ! ( pkt -> data [ i + 5 ] & 0x80 ); // progressive frame
2012-05-27 14:21:41 +02:00
if ( sc -> interlaced )
sc -> field_dominance = 1 + ! ( pkt -> data [ i + 4 ] & 0x80 ); // top field first
2009-01-31 06:32:12 +00:00
break ;
}
2009-02-02 10:03:38 +00:00
} else if ( c == 0x1b8 ) { // gop
2009-06-30 07:41:40 +00:00
if ( pkt -> data [ i + 4 ] >> 6 & 0x01 ) { // closed
sc -> closed_gop = 1 ;
2010-07-02 08:35:47 +00:00
if ( e -> flags & 0x40 ) // sequence header present
e -> flags |= 0x80 ; // random access
2009-06-30 07:41:40 +00:00
}
2009-02-02 10:03:38 +00:00
} else if ( c == 0x1b3 ) { // seq
2010-07-02 08:35:47 +00:00
e -> flags |= 0x40 ;
2009-05-15 04:44:37 +00:00
switch (( pkt -> data [ i + 4 ] >> 4 ) & 0xf ) {
case 2 : sc -> aspect_ratio = ( AVRational ){ 4 , 3 }; break ;
case 3 : sc -> aspect_ratio = ( AVRational ){ 16 , 9 }; break ;
case 4 : sc -> aspect_ratio = ( AVRational ){ 221 , 100 }; break ;
default :
av_reduce ( & sc -> aspect_ratio . num , & sc -> aspect_ratio . den ,
st -> codec -> width , st -> codec -> height , 1024 * 1024 );
}
2009-02-02 10:03:38 +00:00
} else if ( c == 0x100 ) { // pic
int pict_type = ( pkt -> data [ i + 2 ] >> 3 ) & 0x07 ;
2010-07-02 08:35:47 +00:00
e -> temporal_ref = ( pkt -> data [ i + 1 ] << 2 ) | ( pkt -> data [ i + 2 ] >> 6 );
2009-02-02 10:03:38 +00:00
if ( pict_type == 2 ) { // P frame
2010-07-02 08:35:47 +00:00
e -> flags |= 0x22 ;
2009-06-30 07:41:40 +00:00
sc -> closed_gop = 0 ; // reset closed gop, don't matter anymore
2009-02-02 10:03:38 +00:00
} else if ( pict_type == 3 ) { // B frame
2009-06-30 07:41:40 +00:00
if ( sc -> closed_gop )
2010-07-02 08:35:47 +00:00
e -> flags |= 0x13 ; // only backward prediction
2009-06-30 07:41:40 +00:00
else
2010-07-02 08:35:47 +00:00
e -> flags |= 0x33 ;
2009-02-02 10:03:38 +00:00
sc -> temporal_reordering = - 1 ;
} else if ( ! pict_type ) {
av_log ( s , AV_LOG_ERROR , "error parsing mpeg2 frame \n " );
return 0 ;
}
2009-01-31 06:32:12 +00:00
}
}
2011-01-25 22:03:28 +00:00
if ( s -> oformat != & ff_mxf_d10_muxer )
2009-02-13 07:28:20 +00:00
sc -> codec_ul = mxf_get_mpeg2_codec_ul ( st -> codec );
2009-01-31 06:32:12 +00:00
return !! sc -> codec_ul ;
}
2009-02-05 20:15:18 +00:00
static uint64_t mxf_parse_timestamp ( time_t timestamp )
{
2014-10-24 10:46:36 +03:00
struct tm tmbuf ;
struct tm * time = gmtime_r ( & timestamp , & tmbuf );
2011-01-14 22:36:23 +00:00
if ( ! time )
return 0 ;
2009-02-05 20:15:18 +00:00
return ( uint64_t )( time -> tm_year + 1900 ) << 48 |
( uint64_t )( time -> tm_mon + 1 ) << 40 |
( uint64_t ) time -> tm_mday << 32 |
time -> tm_hour << 24 |
time -> tm_min << 16 |
time -> tm_sec << 8 ;
}
2009-03-11 06:15:00 +00:00
static void mxf_gen_umid ( AVFormatContext * s )
{
MXFContext * mxf = s -> priv_data ;
2010-05-23 08:53:40 +00:00
uint32_t seed = av_get_random_seed ();
2009-03-11 06:15:00 +00:00
uint64_t umid = seed + 0x5294713400000000LL ;
AV_WB64 ( mxf -> umid , umid );
AV_WB64 ( mxf -> umid + 8 , umid >> 8 );
2013-09-29 14:33:40 +02:00
mxf -> instance_number = seed & 0xFFFFFF ;
2009-03-11 06:15:00 +00:00
}
2015-04-11 17:18:13 -07:00
static int mxf_init_timecode ( AVFormatContext * s , AVStream * st , AVRational rate )
{
MXFContext * mxf = s -> priv_data ;
AVDictionaryEntry * tcr = av_dict_get ( s -> metadata , "timecode" , NULL , 0 );
if ( ! tcr )
tcr = av_dict_get ( st -> metadata , "timecode" , NULL , 0 );
if ( tcr )
return av_timecode_init_from_string ( & mxf -> tc , rate , tcr -> value , s );
else
return av_timecode_init ( & mxf -> tc , rate , 0 , 0 , s );
}
2008-08-31 02:50:25 +00:00
static int mxf_write_header ( AVFormatContext * s )
2008-08-22 04:12:52 +00:00
{
MXFContext * mxf = s -> priv_data ;
2012-01-16 14:19:37 +01:00
int i , ret ;
2008-10-21 21:40:24 +00:00
uint8_t present [ FF_ARRAY_ELEMS ( mxf_essence_container_uls )] = { 0 };
2012-09-13 00:48:39 +02:00
const MXFSamplesPerFrame * spf = NULL ;
2011-07-07 11:25:03 +02:00
AVDictionaryEntry * t ;
int64_t timestamp = 0 ;
2008-08-30 23:47:58 +00:00
2009-03-11 06:15:00 +00:00
if ( ! s -> nb_streams )
return - 1 ;
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer && s -> nb_streams != 1 ){
av_log ( s , AV_LOG_ERROR , "there must be exactly one stream for mxf opatom \n " );
return - 1 ;
}
2008-08-30 23:47:58 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
AVStream * st = s -> streams [ i ];
2008-08-31 00:39:34 +00:00
MXFStreamContext * sc = av_mallocz ( sizeof ( * sc ));
2008-08-30 23:47:58 +00:00
if ( ! sc )
return AVERROR ( ENOMEM );
st -> priv_data = sc ;
2009-01-31 06:18:25 +00:00
2015-04-11 17:18:13 -07:00
if ((( i == 0 ) ^ ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO )) && s -> oformat != & ff_mxf_opatom_muxer ) {
2012-03-29 11:48:45 +02:00
av_log ( s , AV_LOG_ERROR , "there must be exactly one video stream and it must be the first one \n " );
return - 1 ;
}
2010-03-30 23:30:55 +00:00
if ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2015-05-16 19:59:18 +02:00
const AVPixFmtDescriptor * pix_desc = av_pix_fmt_desc_get ( st -> codec -> pix_fmt );
2014-05-18 12:12:59 +02:00
// TODO: should be avg_frame_rate
2014-06-18 18:18:25 +02:00
AVRational rate , tbc = st -> time_base ;
2012-05-29 00:45:41 +02:00
// Default component depth to 8
sc -> component_depth = 8 ;
2015-05-16 20:02:01 +02:00
sc -> h_chroma_sub_sample = 2 ;
2015-05-19 01:11:09 +02:00
sc -> color_siting = 0xFF ;
2015-05-16 19:59:18 +02:00
if ( pix_desc ) {
2015-09-08 17:10:48 +02:00
sc -> component_depth = pix_desc -> comp [ 0 ]. depth ;
2015-05-16 20:02:01 +02:00
sc -> h_chroma_sub_sample = 1 << pix_desc -> log2_chroma_w ;
2015-05-16 19:59:18 +02:00
}
2015-05-19 01:11:09 +02:00
switch ( ff_choose_chroma_location ( s , st )) {
case AVCHROMA_LOC_TOPLEFT : sc -> color_siting = 0 ; break ;
case AVCHROMA_LOC_LEFT : sc -> color_siting = 6 ; break ;
case AVCHROMA_LOC_TOP : sc -> color_siting = 1 ; break ;
case AVCHROMA_LOC_CENTER : sc -> color_siting = 3 ; break ;
}
2015-05-16 19:59:18 +02:00
2012-08-03 10:21:24 +02:00
mxf -> timecode_base = ( tbc . den + tbc . num / 2 ) / tbc . num ;
2012-09-20 20:31:28 +02:00
spf = ff_mxf_get_samples_per_frame ( s , tbc );
2012-09-13 00:48:39 +02:00
if ( ! spf ) {
2012-08-03 10:20:44 +02:00
av_log ( s , AV_LOG_ERROR , "Unsupported video frame rate %d/%d \n " ,
tbc . den , tbc . num );
return AVERROR ( EINVAL );
2009-01-31 06:18:25 +00:00
}
2012-09-13 00:48:39 +02:00
mxf -> time_base = spf -> time_base ;
2012-08-05 23:25:27 +02:00
rate = av_inv_q ( mxf -> time_base );
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( st , 64 , mxf -> time_base . num , mxf -> time_base . den );
2015-04-11 17:18:13 -07:00
if (( ret = mxf_init_timecode ( s , st , rate )) < 0 )
2012-01-16 14:19:37 +01:00
return ret ;
2015-04-11 17:18:13 -07:00
2013-09-09 10:03:14 +02:00
sc -> video_bit_rate = st -> codec -> bit_rate ? st -> codec -> bit_rate : st -> codec -> rc_max_rate ;
2011-01-25 22:03:28 +00:00
if ( s -> oformat == & ff_mxf_d10_muxer ) {
2015-06-01 21:35:02 +02:00
if (( sc -> video_bit_rate == 50000000 ) && ( mxf -> time_base . den == 25 )) {
sc -> index = 3 ;
} else if (( sc -> video_bit_rate == 49999840 || sc -> video_bit_rate == 50000000 ) && ( mxf -> time_base . den != 25 )) {
sc -> index = 5 ;
2013-09-09 10:02:12 +02:00
} else if ( sc -> video_bit_rate == 40000000 ) {
2009-02-13 07:28:20 +00:00
if ( mxf -> time_base . den == 25 ) sc -> index = 7 ;
else sc -> index = 9 ;
2013-09-09 10:02:12 +02:00
} else if ( sc -> video_bit_rate == 30000000 ) {
2009-02-13 07:28:20 +00:00
if ( mxf -> time_base . den == 25 ) sc -> index = 11 ;
else sc -> index = 13 ;
2012-10-21 17:36:53 +02:00
} else {
2009-02-13 07:28:20 +00:00
av_log ( s , AV_LOG_ERROR , "error MXF D-10 only support 30/40/50 mbit/s \n " );
return - 1 ;
}
mxf -> edit_unit_byte_count = KAG_SIZE ; // system element
2013-09-09 10:02:12 +02:00
mxf -> edit_unit_byte_count += 16 + 4 + ( uint64_t ) sc -> video_bit_rate *
2009-02-13 07:28:20 +00:00
mxf -> time_base . num / ( 8 * mxf -> time_base . den );
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
2012-09-13 00:48:39 +02:00
mxf -> edit_unit_byte_count += 16 + 4 + 4 + spf -> samples_per_frame [ 0 ] * 8 * 4 ;
2009-02-13 07:28:20 +00:00
mxf -> edit_unit_byte_count += klv_fill_size ( mxf -> edit_unit_byte_count );
2015-05-24 02:43:26 +02:00
sc -> signal_standard = 1 ;
2009-02-13 07:28:20 +00:00
}
2015-06-06 03:06:12 +02:00
if ( mxf -> signal_standard >= 0 )
sc -> signal_standard = mxf -> signal_standard ;
2010-03-30 23:30:55 +00:00
} else if ( st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO ) {
2009-01-31 06:18:25 +00:00
if ( st -> codec -> sample_rate != 48000 ) {
av_log ( s , AV_LOG_ERROR , "only 48khz is implemented \n " );
return - 1 ;
}
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( st , 64 , 1 , st -> codec -> sample_rate );
2011-01-25 22:03:28 +00:00
if ( s -> oformat == & ff_mxf_d10_muxer ) {
2009-02-13 07:28:20 +00:00
if ( st -> index != 1 ) {
av_log ( s , AV_LOG_ERROR , "MXF D-10 only support one audio track \n " );
return - 1 ;
}
2012-08-05 11:11:04 +02:00
if ( st -> codec -> codec_id != AV_CODEC_ID_PCM_S16LE &&
st -> codec -> codec_id != AV_CODEC_ID_PCM_S24LE ) {
2009-02-13 07:28:20 +00:00
av_log ( s , AV_LOG_ERROR , "MXF D-10 only support 16 or 24 bits le audio \n " );
}
sc -> index = (( MXFStreamContext * ) s -> streams [ 0 ] -> priv_data ) -> index + 1 ;
2015-04-11 17:18:13 -07:00
} else if ( s -> oformat == & ff_mxf_opatom_muxer ) {
AVRational tbc = av_inv_q ( mxf -> audio_edit_rate );
if ( st -> codec -> codec_id != AV_CODEC_ID_PCM_S16LE &&
st -> codec -> codec_id != AV_CODEC_ID_PCM_S24LE ) {
av_log ( s , AV_LOG_ERROR , "Only pcm_s16le and pcm_s24le audio codecs are implemented \n " );
return AVERROR_PATCHWELCOME ;
}
if ( st -> codec -> channels != 1 ) {
av_log ( s , AV_LOG_ERROR , "MXF OPAtom only supports single channel audio \n " );
return AVERROR ( EINVAL );
}
spf = ff_mxf_get_samples_per_frame ( s , tbc );
if ( ! spf ){
av_log ( s , AV_LOG_ERROR , "Unsupported timecode frame rate %d/%d \n " , tbc . den , tbc . num );
return AVERROR ( EINVAL );
}
mxf -> time_base = st -> time_base ;
if (( ret = mxf_init_timecode ( s , st , av_inv_q ( spf -> time_base ))) < 0 )
return ret ;
mxf -> timecode_base = ( tbc . den + tbc . num / 2 ) / tbc . num ;
mxf -> edit_unit_byte_count = ( av_get_bits_per_sample ( st -> codec -> codec_id ) * st -> codec -> channels ) >> 3 ;
sc -> index = 2 ;
} else {
mxf -> slice_count = 1 ;
}
2009-01-31 06:18:25 +00:00
}
2008-08-31 02:46:50 +00:00
2009-02-13 07:28:20 +00:00
if ( ! sc -> index ) {
2009-02-13 07:34:01 +00:00
sc -> index = mxf_get_essence_container_ul_index ( st -> codec -> codec_id );
if ( sc -> index == - 1 ) {
av_log ( s , AV_LOG_ERROR , "track %d: could not find essence container ul, "
"codec not currently supported in container \n " , i );
return - 1 ;
}
2009-02-13 07:28:20 +00:00
}
2008-08-31 02:41:31 +00:00
2009-01-31 06:32:12 +00:00
sc -> codec_ul = & mxf_essence_container_uls [ sc -> index ]. codec_ul ;
2008-08-31 02:41:31 +00:00
2008-08-31 04:13:44 +00:00
memcpy ( sc -> track_essence_element_key , mxf_essence_container_uls [ sc -> index ]. element_ul , 15 );
sc -> track_essence_element_key [ 15 ] = present [ sc -> index ];
2008-08-31 01:33:28 +00:00
PRINT_KEY ( s , "track essence element key" , sc -> track_essence_element_key );
2009-02-18 02:57:41 +00:00
if ( ! present [ sc -> index ])
mxf -> essence_container_count ++ ;
present [ sc -> index ] ++ ;
2008-08-30 23:47:58 +00:00
}
2008-08-22 04:12:52 +00:00
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_d10_muxer || s -> oformat == & ff_mxf_opatom_muxer ) {
2009-02-13 07:28:20 +00:00
mxf -> essence_container_count = 1 ;
}
2014-05-01 10:43:10 +02:00
if ( ! ( s -> flags & AVFMT_FLAG_BITEXACT ))
2009-03-11 06:15:00 +00:00
mxf_gen_umid ( s );
2009-01-31 06:18:25 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
MXFStreamContext * sc = s -> streams [ i ] -> priv_data ;
// update element count
sc -> track_essence_element_key [ 13 ] = present [ sc -> index ];
2012-05-26 18:09:47 +02:00
if ( ! memcmp ( sc -> track_essence_element_key , mxf_essence_container_uls [ 15 ]. element_ul , 13 )) // DV
sc -> order = ( 0x15 << 24 ) | AV_RB32 ( sc -> track_essence_element_key + 13 );
else
sc -> order = AV_RB32 ( sc -> track_essence_element_key + 12 );
2009-01-31 06:18:25 +00:00
}
2011-07-13 11:45:17 +02:00
if ( t = av_dict_get ( s -> metadata , "creation_time" , NULL , 0 ))
timestamp = ff_iso8601_to_unix_time ( t -> value );
2011-07-07 11:25:03 +02:00
if ( timestamp )
mxf -> timestamp = mxf_parse_timestamp ( timestamp );
2009-02-11 07:18:00 +00:00
mxf -> duration = - 1 ;
mxf -> timecode_track = av_mallocz ( sizeof ( * mxf -> timecode_track ));
if ( ! mxf -> timecode_track )
return AVERROR ( ENOMEM );
mxf -> timecode_track -> priv_data = av_mallocz ( sizeof ( MXFStreamContext ));
if ( ! mxf -> timecode_track -> priv_data )
return AVERROR ( ENOMEM );
2009-02-18 01:35:36 +00:00
mxf -> timecode_track -> index = - 1 ;
2009-02-05 20:15:18 +00:00
2012-09-13 00:48:39 +02:00
if ( ! spf )
2012-09-20 20:31:28 +02:00
spf = ff_mxf_get_samples_per_frame ( s , ( AVRational ){ 1 , 25 });
2009-01-31 10:49:26 +00:00
2012-09-13 00:48:39 +02:00
if ( ff_audio_interleave_init ( s , spf -> samples_per_frame , mxf -> time_base ) < 0 )
2009-01-31 06:18:25 +00:00
return - 1 ;
2008-08-22 04:12:52 +00:00
return 0 ;
}
2009-02-08 02:34:56 +00:00
static const uint8_t system_metadata_pack_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x05 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x04 , 0x01 , 0x01 , 0x00 };
static const uint8_t system_metadata_package_set_key [] = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x43 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x04 , 0x01 , 0x02 , 0x01 };
static void mxf_write_system_item ( AVFormatContext * s )
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-11 07:18:00 +00:00
unsigned frame ;
2009-02-08 02:34:56 +00:00
uint32_t time_code ;
2012-01-16 14:19:37 +01:00
frame = mxf -> last_indexed_edit_unit + mxf -> edit_units_count ;
2009-02-08 02:34:56 +00:00
// write system metadata pack
2011-02-21 19:28:17 +01:00
avio_write ( pb , system_metadata_pack_key , 16 );
2009-02-13 07:06:35 +00:00
klv_encode_ber4_length ( pb , 57 );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0x5c ); // UL, user date/time stamp, picture and sound item present
avio_w8 ( pb , 0x04 ); // content package rate
avio_w8 ( pb , 0x00 ); // content package type
avio_wb16 ( pb , 0x00 ); // channel handle
2012-10-15 15:58:44 +02:00
avio_wb16 ( pb , ( mxf -> tc . start + frame ) & 0xFFFF ); // continuity count, supposed to overflow
2009-02-08 02:34:56 +00:00
if ( mxf -> essence_container_count > 1 )
2011-02-21 19:28:17 +01:00
avio_write ( pb , multiple_desc_ul , 16 );
2009-02-13 07:46:03 +00:00
else {
MXFStreamContext * sc = s -> streams [ 0 ] -> priv_data ;
2011-02-21 19:28:17 +01:00
avio_write ( pb , mxf_essence_container_uls [ sc -> index ]. container_ul , 16 );
2009-02-13 07:46:03 +00:00
}
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0 );
avio_wb64 ( pb , 0 );
avio_wb64 ( pb , 0 ); // creation date/time stamp
2009-02-08 02:34:56 +00:00
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0x81 ); // SMPTE 12M time code
2012-01-16 14:19:37 +01:00
time_code = av_timecode_get_smpte_from_framenum ( & mxf -> tc , frame );
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , time_code );
avio_wb32 ( pb , 0 ); // binary group data
avio_wb64 ( pb , 0 );
2009-02-08 02:34:56 +00:00
// write system metadata package set
2011-02-21 19:28:17 +01:00
avio_write ( pb , system_metadata_package_set_key , 16 );
2009-02-13 07:06:35 +00:00
klv_encode_ber4_length ( pb , 35 );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , 0x83 ); // UMID
avio_wb16 ( pb , 0x20 );
2009-03-11 06:15:00 +00:00
mxf_write_umid ( s , 1 );
2009-02-08 02:34:56 +00:00
}
2009-02-13 07:28:20 +00:00
static void mxf_write_d10_video_packet ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2013-09-09 10:02:12 +02:00
MXFStreamContext * sc = st -> priv_data ;
int packet_size = ( uint64_t ) sc -> video_bit_rate * mxf -> time_base . num /
2009-02-13 07:28:20 +00:00
( 8 * mxf -> time_base . den ); // frame size
int pad ;
packet_size += 16 + 4 ;
packet_size += klv_fill_size ( packet_size );
klv_encode_ber4_length ( pb , pkt -> size );
2011-02-21 19:28:17 +01:00
avio_write ( pb , pkt -> data , pkt -> size );
2009-02-13 07:28:20 +00:00
// ensure CBR muxing by padding to correct video frame size
pad = packet_size - pkt -> size - 16 - 4 ;
if ( pad > 20 ) {
2011-02-21 19:28:17 +01:00
avio_write ( s -> pb , klv_fill_key , 16 );
2009-02-13 07:28:20 +00:00
pad -= 16 + 4 ;
klv_encode_ber4_length ( s -> pb , pad );
2013-07-15 17:39:55 +00:00
ffio_fill ( s -> pb , 0 , pad );
2012-07-12 23:16:24 +02:00
av_assert1 ( ! ( avio_tell ( s -> pb ) & ( KAG_SIZE - 1 )));
2009-02-13 07:28:20 +00:00
} else {
av_log ( s , AV_LOG_WARNING , "cannot fill d-10 video packet \n " );
2013-07-15 17:39:55 +00:00
ffio_fill ( s -> pb , 0 , pad );
2009-02-13 07:28:20 +00:00
}
}
static void mxf_write_d10_audio_packet ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2009-02-25 08:08:10 +00:00
int frame_size = pkt -> size / st -> codec -> block_align ;
2009-02-13 07:28:20 +00:00
uint8_t * samples = pkt -> data ;
uint8_t * end = pkt -> data + pkt -> size ;
int i ;
klv_encode_ber4_length ( pb , 4 + frame_size * 4 * 8 );
2011-02-21 19:28:17 +01:00
avio_w8 ( pb , ( frame_size == 1920 ? 0 : ( mxf -> edit_units_count - 1 ) % 5 + 1 ));
avio_wl16 ( pb , frame_size );
avio_w8 ( pb , ( 1 << st -> codec -> channels ) - 1 );
2009-02-13 07:28:20 +00:00
while ( samples < end ) {
for ( i = 0 ; i < st -> codec -> channels ; i ++ ) {
uint32_t sample ;
2012-08-05 11:11:04 +02:00
if ( st -> codec -> codec_id == AV_CODEC_ID_PCM_S24LE ) {
2009-02-25 08:05:43 +00:00
sample = AV_RL24 ( samples ) << 4 ;
2009-02-13 07:28:20 +00:00
samples += 3 ;
} else {
2009-02-25 08:05:43 +00:00
sample = AV_RL16 ( samples ) << 12 ;
2009-02-13 07:28:20 +00:00
samples += 2 ;
}
2011-02-21 19:28:17 +01:00
avio_wl32 ( pb , sample | i );
2009-02-13 07:28:20 +00:00
}
for (; i < 8 ; i ++ )
2011-02-21 19:28:17 +01:00
avio_wl32 ( pb , i );
2009-02-13 07:28:20 +00:00
}
}
2015-01-28 19:44:21 -08:00
static int mxf_write_opatom_body_partition ( AVFormatContext * s )
{
MXFContext * mxf = s -> priv_data ;
AVIOContext * pb = s -> pb ;
AVStream * st = s -> streams [ 0 ];
MXFStreamContext * sc = st -> priv_data ;
const uint8_t * key = NULL ;
int err ;
if ( ! mxf -> header_written )
key = body_partition_key ;
if (( err = mxf_write_partition ( s , 1 , 0 , key , 0 )) < 0 )
return err ;
mxf_write_klv_fill ( s );
avio_write ( pb , sc -> track_essence_element_key , 16 );
klv_encode_ber9_length ( pb , mxf -> body_offset );
return 0 ;
}
static int mxf_write_opatom_packet ( AVFormatContext * s , AVPacket * pkt , MXFIndexEntry * ie )
{
MXFContext * mxf = s -> priv_data ;
AVIOContext * pb = s -> pb ;
int err ;
if ( ! mxf -> header_written ) {
if (( err = mxf_write_partition ( s , 0 , 0 , header_open_partition_key , 1 )) < 0 )
return err ;
mxf_write_klv_fill ( s );
if (( err = mxf_write_opatom_body_partition ( s )) < 0 )
return err ;
mxf -> header_written = 1 ;
}
if ( ! mxf -> edit_unit_byte_count ) {
mxf -> index_entries [ mxf -> edit_units_count ]. offset = mxf -> body_offset ;
mxf -> index_entries [ mxf -> edit_units_count ]. flags = ie -> flags ;
mxf -> index_entries [ mxf -> edit_units_count ]. temporal_ref = ie -> temporal_ref ;
}
mxf -> edit_units_count ++ ;
avio_write ( pb , pkt -> data , pkt -> size );
mxf -> body_offset += pkt -> size ;
avio_flush ( pb );
return 0 ;
}
2008-08-31 02:50:25 +00:00
static int mxf_write_packet ( AVFormatContext * s , AVPacket * pkt )
2008-08-25 20:28:12 +00:00
{
2009-01-31 06:32:12 +00:00
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2008-08-25 20:28:12 +00:00
AVStream * st = s -> streams [ pkt -> stream_index ];
MXFStreamContext * sc = st -> priv_data ;
2010-07-02 08:35:47 +00:00
MXFIndexEntry ie = { 0 };
2013-08-02 19:21:24 +02:00
int err ;
2008-08-25 20:28:12 +00:00
2009-02-16 10:44:38 +00:00
if ( ! mxf -> edit_unit_byte_count && ! ( mxf -> edit_units_count % EDIT_UNITS_PER_BODY )) {
2013-08-02 19:21:24 +02:00
if (( err = av_reallocp_array ( & mxf -> index_entries , mxf -> edit_units_count
+ EDIT_UNITS_PER_BODY , sizeof ( * mxf -> index_entries ))) < 0 ) {
mxf -> edit_units_count = 0 ;
2009-02-02 10:03:38 +00:00
av_log ( s , AV_LOG_ERROR , "could not allocate index entries \n " );
2013-08-02 19:21:24 +02:00
return err ;
2009-01-31 06:32:12 +00:00
}
2009-02-02 10:03:38 +00:00
}
2012-08-05 11:11:04 +02:00
if ( st -> codec -> codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
2010-07-02 08:35:47 +00:00
if ( ! mxf_parse_mpeg2_frame ( s , st , pkt , & ie )) {
2009-02-02 10:03:38 +00:00
av_log ( s , AV_LOG_ERROR , "could not get mpeg2 profile and level \n " );
return - 1 ;
}
2012-08-07 22:45:46 +02:00
} else if ( st -> codec -> codec_id == AV_CODEC_ID_DNXHD ) {
2012-05-29 00:45:41 +02:00
if ( ! mxf_parse_dnxhd_frame ( s , st , pkt )) {
av_log ( s , AV_LOG_ERROR , "could not get dnxhd profile \n " );
return - 1 ;
}
2012-08-07 22:45:46 +02:00
} else if ( st -> codec -> codec_id == AV_CODEC_ID_DVVIDEO ) {
2012-05-26 18:09:47 +02:00
if ( ! mxf_parse_dv_frame ( s , st , pkt )) {
av_log ( s , AV_LOG_ERROR , "could not get dv profile \n " );
return - 1 ;
}
2014-10-28 22:38:22 +00:00
} else if ( st -> codec -> codec_id == AV_CODEC_ID_H264 ) {
if ( ! mxf_parse_h264_frame ( s , st , pkt , & ie )) {
av_log ( s , AV_LOG_ERROR , "could not get h264 profile \n " );
return - 1 ;
}
2009-02-02 10:03:38 +00:00
}
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer )
return mxf_write_opatom_packet ( s , pkt , & ie );
2009-02-02 10:03:38 +00:00
if ( ! mxf -> header_written ) {
2009-02-16 10:44:38 +00:00
if ( mxf -> edit_unit_byte_count ) {
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 1 , 2 , header_open_partition_key , 1 )) < 0 )
return err ;
2009-02-16 10:44:38 +00:00
mxf_write_klv_fill ( s );
mxf_write_index_table_segment ( s );
} else {
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 0 , 0 , header_open_partition_key , 1 )) < 0 )
return err ;
2009-02-16 10:44:38 +00:00
}
2009-01-31 06:32:12 +00:00
mxf -> header_written = 1 ;
}
2009-02-08 02:38:07 +00:00
if ( st -> index == 0 ) {
2009-02-16 10:44:38 +00:00
if ( ! mxf -> edit_unit_byte_count &&
( ! mxf -> edit_units_count || mxf -> edit_units_count > EDIT_UNITS_PER_BODY ) &&
2010-07-02 08:35:47 +00:00
! ( ie . flags & 0x33 )) { // I frame, Gop start
2009-02-10 09:02:29 +00:00
mxf_write_klv_fill ( s );
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 1 , 2 , body_partition_key , 0 )) < 0 )
return err ;
2009-02-10 09:02:29 +00:00
mxf_write_klv_fill ( s );
mxf_write_index_table_segment ( s );
}
2009-02-08 02:34:56 +00:00
mxf_write_klv_fill ( s );
2009-02-10 07:23:51 +00:00
mxf_write_system_item ( s );
2009-02-08 02:34:56 +00:00
2009-02-16 10:44:38 +00:00
if ( ! mxf -> edit_unit_byte_count ) {
mxf -> index_entries [ mxf -> edit_units_count ]. offset = mxf -> body_offset ;
2010-07-02 08:35:47 +00:00
mxf -> index_entries [ mxf -> edit_units_count ]. flags = ie . flags ;
mxf -> index_entries [ mxf -> edit_units_count ]. temporal_ref = ie . temporal_ref ;
2009-02-16 10:44:38 +00:00
mxf -> body_offset += KAG_SIZE ; // size of system element
}
2009-02-02 10:03:38 +00:00
mxf -> edit_units_count ++ ;
2009-02-16 10:44:38 +00:00
} else if ( ! mxf -> edit_unit_byte_count && st -> index == 1 ) {
2009-02-13 22:38:05 +00:00
mxf -> index_entries [ mxf -> edit_units_count - 1 ]. slice_offset =
mxf -> body_offset - mxf -> index_entries [ mxf -> edit_units_count - 1 ]. offset ;
2009-02-02 10:03:38 +00:00
}
2009-02-10 07:23:51 +00:00
mxf_write_klv_fill ( s );
2011-02-21 19:28:17 +01:00
avio_write ( pb , sc -> track_essence_element_key , 16 ); // write key
2011-01-25 22:03:28 +00:00
if ( s -> oformat == & ff_mxf_d10_muxer ) {
2010-03-30 23:30:55 +00:00
if ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO )
2009-02-16 10:44:38 +00:00
mxf_write_d10_video_packet ( s , st , pkt );
else
mxf_write_d10_audio_packet ( s , st , pkt );
} else {
klv_encode_ber4_length ( pb , pkt -> size ); // write length
2011-02-21 19:28:17 +01:00
avio_write ( pb , pkt -> data , pkt -> size );
2009-02-16 10:44:38 +00:00
mxf -> body_offset += 16 + 4 + pkt -> size + klv_fill_size ( 16 + 4 + pkt -> size );
}
2008-08-25 20:28:12 +00:00
2011-03-14 20:39:06 +01:00
avio_flush ( pb );
2009-02-13 22:38:05 +00:00
2008-08-25 20:28:12 +00:00
return 0 ;
}
2009-02-02 10:03:38 +00:00
static void mxf_write_random_index_pack ( AVFormatContext * s )
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2011-03-03 20:11:45 +01:00
uint64_t pos = avio_tell ( pb );
2009-02-10 09:02:29 +00:00
int i ;
2009-02-02 10:03:38 +00:00
2011-02-21 19:28:17 +01:00
avio_write ( pb , random_index_pack_key , 16 );
2012-10-24 17:06:49 +02:00
klv_encode_ber_length ( pb , 28 + 12LL * mxf -> body_partitions_count );
2009-02-02 10:03:38 +00:00
2015-01-28 19:44:21 -08:00
if ( mxf -> edit_unit_byte_count && s -> oformat != & ff_mxf_opatom_muxer )
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 1 ); // BodySID of header partition
2009-02-18 01:05:06 +00:00
else
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 0 );
avio_wb64 ( pb , 0 ); // offset of header partition
2009-02-02 10:03:38 +00:00
2009-02-10 09:02:29 +00:00
for ( i = 0 ; i < mxf -> body_partitions_count ; i ++ ) {
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 1 ); // BodySID
avio_wb64 ( pb , mxf -> body_partition_offset [ i ]);
2009-02-10 09:02:29 +00:00
}
2011-02-21 19:28:17 +01:00
avio_wb32 ( pb , 0 ); // BodySID of footer partition
avio_wb64 ( pb , mxf -> footer_partition_offset );
2009-02-02 10:03:38 +00:00
2011-03-03 20:11:45 +01:00
avio_wb32 ( pb , avio_tell ( pb ) - pos + 4 );
2009-02-02 10:03:38 +00:00
}
2008-08-31 03:36:25 +00:00
static int mxf_write_footer ( AVFormatContext * s )
2008-08-19 12:36:17 +00:00
{
MXFContext * mxf = s -> priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s -> pb ;
2015-03-14 17:47:53 +01:00
int err = 0 ;
2009-02-07 02:13:23 +00:00
2015-03-18 21:57:58 +01:00
if ( ! mxf -> header_written ||
( s -> oformat == & ff_mxf_opatom_muxer && ! mxf -> body_partition_offset )) {
/* reason could be invalid options/not supported codec/out of memory */
err = AVERROR_UNKNOWN ;
goto end ;
}
2009-02-11 07:18:00 +00:00
mxf -> duration = mxf -> last_indexed_edit_unit + mxf -> edit_units_count ;
2009-02-07 02:13:23 +00:00
mxf_write_klv_fill ( s );
2011-03-03 20:11:45 +01:00
mxf -> footer_partition_offset = avio_tell ( pb );
2015-01-28 19:44:21 -08:00
if ( mxf -> edit_unit_byte_count && s -> oformat != & ff_mxf_opatom_muxer ) { // no need to repeat index
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 0 , 0 , footer_partition_key , 0 )) < 0 )
2015-03-14 17:47:53 +01:00
goto end ;
2009-02-13 07:28:20 +00:00
} else {
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 0 , 2 , footer_partition_key , 0 )) < 0 )
2015-03-14 17:47:53 +01:00
goto end ;
2009-02-13 07:34:01 +00:00
mxf_write_klv_fill ( s );
mxf_write_index_table_segment ( s );
2009-02-13 07:28:20 +00:00
}
2009-02-02 10:03:38 +00:00
2009-02-10 05:35:28 +00:00
mxf_write_klv_fill ( s );
2009-02-02 10:03:38 +00:00
mxf_write_random_index_pack ( s );
2011-03-05 21:06:46 +01:00
if ( s -> pb -> seekable ) {
2015-01-28 19:44:21 -08:00
if ( s -> oformat == & ff_mxf_opatom_muxer ){
/* rewrite body partition to update lengths */
avio_seek ( pb , mxf -> body_partition_offset [ 0 ], SEEK_SET );
if (( err = mxf_write_opatom_body_partition ( s )) < 0 )
2015-03-14 17:47:53 +01:00
goto end ;
2015-01-28 19:44:21 -08:00
}
2011-02-28 14:57:54 +01:00
avio_seek ( pb , 0 , SEEK_SET );
2015-01-28 19:44:21 -08:00
if ( mxf -> edit_unit_byte_count && s -> oformat != & ff_mxf_opatom_muxer ) {
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 1 , 2 , header_closed_partition_key , 1 )) < 0 )
2015-03-14 17:47:53 +01:00
goto end ;
2009-02-13 07:28:20 +00:00
mxf_write_klv_fill ( s );
mxf_write_index_table_segment ( s );
2009-02-16 10:44:38 +00:00
} else {
2013-08-02 19:21:24 +02:00
if (( err = mxf_write_partition ( s , 0 , 0 , header_closed_partition_key , 1 )) < 0 )
2015-03-14 17:47:53 +01:00
goto end ;
2009-02-13 07:28:20 +00:00
}
2008-08-31 03:36:25 +00:00
}
2009-01-31 11:17:04 +00:00
2015-03-14 17:47:53 +01:00
end :
2009-01-31 11:17:04 +00:00
ff_audio_interleave_close ( s );
2009-02-08 04:35:36 +00:00
av_freep ( & mxf -> index_entries );
2009-02-10 09:02:29 +00:00
av_freep ( & mxf -> body_partition_offset );
2009-02-11 07:18:00 +00:00
av_freep ( & mxf -> timecode_track -> priv_data );
av_freep ( & mxf -> timecode_track );
2009-02-08 04:35:36 +00:00
2008-08-22 04:12:52 +00:00
mxf_free ( s );
2009-02-13 07:34:01 +00:00
2015-03-14 17:47:53 +01:00
return err < 0 ? err : 0 ;
2008-08-19 12:36:17 +00:00
}
2008-08-22 04:12:52 +00:00
2009-01-31 10:51:35 +00:00
static int mxf_interleave_get_packet ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush )
2009-01-31 06:18:25 +00:00
{
2010-01-29 06:38:00 +00:00
int i , stream_count = 0 ;
2009-01-31 06:18:25 +00:00
2010-01-29 06:38:00 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ )
stream_count += !! s -> streams [ i ] -> last_in_packet_buffer ;
2009-01-31 06:18:25 +00:00
if ( stream_count && ( s -> nb_streams == stream_count || flush )) {
2015-02-06 14:53:40 +01:00
AVPacketList * pktl = s -> internal -> packet_buffer ;
2009-02-02 10:04:36 +00:00
if ( s -> nb_streams != stream_count ) {
2009-02-12 05:32:40 +00:00
AVPacketList * last = NULL ;
2009-02-16 01:51:52 +00:00
// find last packet in edit unit
2009-02-02 10:04:36 +00:00
while ( pktl ) {
2009-02-16 01:51:52 +00:00
if ( ! stream_count || pktl -> pkt . stream_index == 0 )
2009-02-02 10:04:36 +00:00
break ;
2009-02-12 05:32:40 +00:00
last = pktl ;
2009-02-02 10:04:36 +00:00
pktl = pktl -> next ;
2009-02-16 01:51:52 +00:00
stream_count -- ;
2009-02-02 10:04:36 +00:00
}
2009-01-31 06:18:25 +00:00
// purge packet queue
while ( pktl ) {
AVPacketList * next = pktl -> next ;
2009-09-16 20:04:04 +00:00
if ( s -> streams [ pktl -> pkt . stream_index ] -> last_in_packet_buffer == pktl )
s -> streams [ pktl -> pkt . stream_index ] -> last_in_packet_buffer = NULL ;
2015-10-23 11:11:31 +02:00
av_packet_unref ( & pktl -> pkt );
2009-01-31 06:18:25 +00:00
av_freep ( & pktl );
pktl = next ;
}
2009-02-16 01:51:52 +00:00
if ( last )
last -> next = NULL ;
else {
2015-02-06 14:53:40 +01:00
s -> internal -> packet_buffer = NULL ;
s -> internal -> packet_buffer_end = NULL ;
2009-02-02 10:04:36 +00:00
goto out ;
2009-02-16 01:51:52 +00:00
}
2015-02-06 14:53:40 +01:00
pktl = s -> internal -> packet_buffer ;
2009-01-31 06:18:25 +00:00
}
2009-02-02 10:04:36 +00:00
* out = pktl -> pkt ;
2015-03-16 08:57:35 +00:00
av_log ( s , AV_LOG_TRACE , "out st:%d dts:%" PRId64 " \n " , ( * out ). stream_index , ( * out ). dts );
2015-02-06 14:53:40 +01:00
s -> internal -> packet_buffer = pktl -> next ;
2009-09-16 20:04:04 +00:00
if ( s -> streams [ pktl -> pkt . stream_index ] -> last_in_packet_buffer == pktl )
s -> streams [ pktl -> pkt . stream_index ] -> last_in_packet_buffer = NULL ;
2015-02-06 14:53:40 +01:00
if ( ! s -> internal -> packet_buffer )
s -> internal -> packet_buffer_end = NULL ;
2009-02-02 10:04:36 +00:00
av_freep ( & pktl );
2009-01-31 06:18:25 +00:00
return 1 ;
} else {
2009-02-02 10:04:36 +00:00
out :
2009-01-31 06:18:25 +00:00
av_init_packet ( out );
return 0 ;
}
}
static int mxf_compare_timestamps ( AVFormatContext * s , AVPacket * next , AVPacket * pkt )
{
2009-02-04 04:50:47 +00:00
MXFStreamContext * sc = s -> streams [ pkt -> stream_index ] -> priv_data ;
MXFStreamContext * sc2 = s -> streams [ next -> stream_index ] -> priv_data ;
2009-01-31 06:18:25 +00:00
2009-02-04 04:50:47 +00:00
return next -> dts > pkt -> dts ||
( next -> dts == pkt -> dts && sc -> order < sc2 -> order );
2009-01-31 06:18:25 +00:00
}
static int mxf_interleave ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush )
{
2009-02-09 21:34:20 +00:00
return ff_audio_rechunk_interleave ( s , out , pkt , flush ,
2009-02-08 04:31:44 +00:00
mxf_interleave_get_packet , mxf_compare_timestamps );
2009-01-31 06:18:25 +00:00
}
2015-06-06 03:06:12 +02:00
#define MXF_COMMON_OPTIONS \
{ "signal_standard", "Force/set Sigal Standard",\
offsetof(MXFContext, signal_standard), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "bt601", "ITU-R BT.601 and BT.656, also SMPTE 125M (525 and 625 line interlaced)",\
0, AV_OPT_TYPE_CONST, {.i64 = 1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "bt1358", "ITU-R BT.1358 and ITU-R BT.799-3, also SMPTE 293M (525 and 625 line progressive)",\
0, AV_OPT_TYPE_CONST, {.i64 = 2}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "smpte347m", "SMPTE 347M (540 Mbps mappings)",\
0, AV_OPT_TYPE_CONST, {.i64 = 3}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "smpte274m", "SMPTE 274M (1125 line)",\
0, AV_OPT_TYPE_CONST, {.i64 = 4}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "smpte296m", "SMPTE 296M (750 line progressive)",\
0, AV_OPT_TYPE_CONST, {.i64 = 5}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "smpte349m", "SMPTE 349M (1485 Mbps mappings)",\
0, AV_OPT_TYPE_CONST, {.i64 = 6}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "smpte428", "SMPTE 428-1 DCDM",\
0, AV_OPT_TYPE_CONST, {.i64 = 7}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},
2015-05-22 14:02:51 +02:00
static const AVOption mxf_options [] = {
2015-06-06 03:06:12 +02:00
MXF_COMMON_OPTIONS
2015-05-22 14:02:51 +02:00
{ NULL },
};
static const AVClass mxf_muxer_class = {
. class_name = "MXF muxer" ,
. item_name = av_default_item_name ,
. option = mxf_options ,
. version = LIBAVUTIL_VERSION_INT ,
};
2014-06-25 10:29:30 +00:00
static const AVOption d10_options [] = {
2014-06-26 16:10:45 +00:00
{ "d10_channelcount" , "Force/set channelcount in generic sound essence descriptor" ,
2014-06-25 10:29:30 +00:00
offsetof ( MXFContext , channel_count ), AV_OPT_TYPE_INT , {. i64 = - 1 }, - 1 , 8 , AV_OPT_FLAG_ENCODING_PARAM },
2015-06-06 03:06:12 +02:00
MXF_COMMON_OPTIONS
2014-06-25 10:29:30 +00:00
{ NULL },
};
static const AVClass mxf_d10_muxer_class = {
. class_name = "MXF-D10 muxer" ,
. item_name = av_default_item_name ,
. option = d10_options ,
. version = LIBAVUTIL_VERSION_INT ,
};
2015-04-11 17:18:13 -07:00
static const AVOption opatom_options [] = {
{ "mxf_audio_edit_rate" , "Audio edit rate for timecode" ,
offsetof ( MXFContext , audio_edit_rate ), AV_OPT_TYPE_RATIONAL , {. dbl = 25 }, 0 , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM },
2015-06-06 03:06:12 +02:00
MXF_COMMON_OPTIONS
2015-04-11 17:18:13 -07:00
{ NULL },
};
static const AVClass mxf_opatom_muxer_class = {
. class_name = "MXF-OPAtom muxer" ,
. item_name = av_default_item_name ,
. option = opatom_options ,
. version = LIBAVUTIL_VERSION_INT ,
};
2011-01-25 22:03:28 +00:00
AVOutputFormat ff_mxf_muxer = {
2011-07-16 22:18:12 +02:00
. name = "mxf" ,
2012-07-24 03:23:48 +02:00
. long_name = NULL_IF_CONFIG_SMALL ( "MXF (Material eXchange Format)" ),
2011-07-16 22:18:12 +02:00
. mime_type = "application/mxf" ,
. extensions = "mxf" ,
. priv_data_size = sizeof ( MXFContext ),
2012-08-05 11:11:04 +02:00
. audio_codec = AV_CODEC_ID_PCM_S16LE ,
. video_codec = AV_CODEC_ID_MPEG2VIDEO ,
2011-07-16 22:18:12 +02:00
. write_header = mxf_write_header ,
. write_packet = mxf_write_packet ,
. write_trailer = mxf_write_footer ,
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
2015-05-22 14:02:51 +02:00
. priv_class = & mxf_muxer_class ,
2008-08-14 21:48:02 +00:00
};
2009-02-13 07:28:20 +00:00
2011-01-25 22:03:28 +00:00
AVOutputFormat ff_mxf_d10_muxer = {
2011-07-16 22:18:12 +02:00
. name = "mxf_d10" ,
2012-07-24 03:23:48 +02:00
. long_name = NULL_IF_CONFIG_SMALL ( "MXF (Material eXchange Format) D-10 Mapping" ),
2011-07-16 22:18:12 +02:00
. mime_type = "application/mxf" ,
. priv_data_size = sizeof ( MXFContext ),
2012-08-05 11:11:04 +02:00
. audio_codec = AV_CODEC_ID_PCM_S16LE ,
. video_codec = AV_CODEC_ID_MPEG2VIDEO ,
2011-07-16 22:18:12 +02:00
. write_header = mxf_write_header ,
. write_packet = mxf_write_packet ,
. write_trailer = mxf_write_footer ,
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
2014-06-25 10:29:30 +00:00
. priv_class = & mxf_d10_muxer_class ,
2009-02-13 07:28:20 +00:00
};
2015-01-28 19:44:21 -08:00
AVOutputFormat ff_mxf_opatom_muxer = {
. name = "mxf_opatom" ,
. long_name = NULL_IF_CONFIG_SMALL ( "MXF (Material eXchange Format) Operational Pattern Atom" ),
. mime_type = "application/mxf" ,
. extensions = "mxf" ,
. priv_data_size = sizeof ( MXFContext ),
. audio_codec = AV_CODEC_ID_PCM_S16LE ,
. video_codec = AV_CODEC_ID_DNXHD ,
. write_header = mxf_write_header ,
. write_packet = mxf_write_packet ,
. write_trailer = mxf_write_footer ,
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
2015-04-11 17:18:13 -07:00
. priv_class = & mxf_opatom_muxer_class ,
2015-01-28 19:44:21 -08:00
};