2008-08-15 00:48:02 +03:00
/*
* MXF muxer
* Copyright ( c ) 2008 GUCAS , Zhentan Feng < spyfeng at gmail dot com >
2009-01-31 11:54:59 +02:00
* Copyright ( c ) 2008 Baptiste Coudurier < baptiste dot coudurier at gmail dot com >
2008-08-15 00:48:02 +03: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
*/
/*
2017-09-10 22:10:45 +02:00
* signal_standard , color_siting , store_user_comments , sample rate and klv_fill_key version
2015-11-09 15:24:26 +02:00
* fixes sponsored by NOA GmbH
2008-08-15 00:48:02 +03:00
*/
/*
* References
* SMPTE 336 M KLV Data Encoding Protocol Using Key - Length - Value
* SMPTE 377 M MXF File Format Specifications
* SMPTE 379 M MXF Generic Container
* SMPTE 381 M Mapping MPEG Streams into the MXF Generic Container
2014-09-30 15:16:52 +03:00
* SMPTE 422 M Mapping JPEG 2000 Codestreams into the MXF Generic Container
2008-08-15 00:48:02 +03:00
* SMPTE RP210 : SMPTE Metadata Dictionary
* SMPTE RP224 : Registry of SMPTE Universal Labels
*/
2013-04-22 05:50:45 +03:00
# include <inttypes.h>
2009-02-03 01:37:03 +02:00
# include <math.h>
2009-02-05 22:15:18 +02:00
# include <time.h>
2009-02-03 01:37:03 +02:00
2011-07-06 17:35:12 +03:00
# include "libavutil/opt.h"
2009-03-11 08:15:00 +02:00
# include "libavutil/random_seed.h"
2012-01-16 16:19:37 +03:00
# include "libavutil/timecode.h"
2012-07-13 00:16:24 +03: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 06:42:38 +02:00
# include "libavcodec/bytestream.h"
2012-05-29 01:45:41 +03:00
# include "libavcodec/dnxhddata.h"
2017-09-12 22:17:12 +02:00
# include "libavcodec/dv_profile.h"
2018-10-18 22:37:05 +02:00
# include "libavcodec/h264_ps.h"
# include "libavcodec/golomb.h"
2014-10-29 00:38:22 +02:00
# include "libavcodec/internal.h"
2009-02-08 06:31:44 +02:00
# include "audiointerleave.h"
2009-02-08 06:42:38 +02:00
# include "avformat.h"
2013-07-15 20:39:55 +03:00
# include "avio_internal.h"
2011-07-13 14:21:00 +03:00
# include "internal.h"
2018-10-18 22:37:05 +02:00
# include "avc.h"
2008-08-18 21:11:00 +03:00
# include "mxf.h"
2012-05-26 19:09:47 +03:00
# include "config.h"
2008-08-18 21:11:00 +03:00
2011-01-26 00:03:28 +02:00
extern AVOutputFormat ff_mxf_d10_muxer ;
2015-01-29 05:44:21 +02:00
extern AVOutputFormat ff_mxf_opatom_muxer ;
2009-02-13 09:28:20 +02:00
2009-02-10 11:02:29 +02:00
# define EDIT_UNITS_PER_BODY 250
2009-02-07 04:13:23 +02:00
# define KAG_SIZE 512
2009-02-02 12:03:38 +02:00
2014-09-22 10:19:33 +03:00
typedef struct MXFLocalTagPair {
2008-08-18 21:11:00 +03:00
int local_tag ;
UID uid ;
} MXFLocalTagPair ;
2014-09-22 10:19:33 +03:00
typedef struct MXFIndexEntry {
2009-02-02 12:03:38 +02:00
uint64_t offset ;
2009-02-08 11:39:19 +02:00
unsigned slice_offset ; ///< offset of audio slice
2010-07-02 11:35:47 +03:00
uint16_t temporal_ref ;
2020-03-13 12:18:40 +02:00
uint8_t flags ;
2009-02-02 12:03:38 +02:00
} MXFIndexEntry ;
2014-09-22 10:19:33 +03:00
typedef struct MXFStreamContext {
2009-01-31 08:18:25 +02:00
AudioInterleaveContext aic ;
2008-08-19 15:36:17 +03:00
UID track_essence_element_key ;
2009-06-30 10:43:32 +03:00
int index ; ///< index in mxf_essence_container_uls table
2008-08-31 05:41:31 +03:00
const UID * codec_ul ;
2019-06-21 00:40:31 +02:00
const UID * container_ul ;
2009-06-30 10:43:32 +03:00
int order ; ///< interleaving order if dts are equal
2011-10-05 15:12:42 +03:00
int interlaced ; ///< whether picture is interlaced
2012-05-27 15:21:41 +03:00
int field_dominance ; ///< tff=1, bff=2
2012-05-29 01:45:41 +03: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 ;
2018-03-21 20:32:32 +02:00
int v_chroma_sub_sample ;
2009-02-02 12:03:38 +02:00
int temporal_reordering ;
2009-02-16 14:48:45 +02:00
AVRational aspect_ratio ; ///< display aspect ratio
2009-06-30 10:41:40 +03:00
int closed_gop ; ///< gop is closed, used in mpeg-2 frame parsing
2013-09-09 11:02:12 +03:00
int video_bit_rate ;
2018-03-21 21:53:56 +02:00
int slice_offset ;
int frame_size ; ///< frame size in bytes
2018-03-21 18:35:22 +02:00
int seq_closed_gop ; ///< all gops in sequence are closed, used in mpeg-2 descriptor
int max_gop ; ///< maximum gop size, used by mpeg-2 descriptor
int b_picture_count ; ///< maximum number of consecutive b pictures, used in mpeg-2 descriptor
int low_delay ; ///< low delay, used in mpeg-2 descriptor
2018-10-18 22:37:05 +02:00
int avc_intra ;
2008-08-19 15:36:17 +03:00
} MXFStreamContext ;
2014-09-22 10:19:33 +03:00
typedef struct MXFContainerEssenceEntry {
2008-08-31 04:33:28 +03:00
UID container_ul ;
UID element_ul ;
2008-08-31 05:41:31 +03:00
UID codec_ul ;
2010-07-24 15:58:28 +03:00
void ( * write_desc ) ( AVFormatContext * , AVStream * ) ;
2008-08-31 07:20:47 +03:00
} MXFContainerEssenceEntry ;
2008-08-31 04:33:28 +03:00
2017-11-27 07:42:16 +02:00
typedef struct MXFPackage {
char * name ;
enum MXFMetadataSetType type ;
int instance ;
2017-12-05 06:46:22 +02:00
struct MXFPackage * ref ;
2017-11-27 07:42:16 +02:00
} MXFPackage ;
2017-09-10 22:10:43 +02:00
enum ULIndex {
2017-08-29 02:13:21 +02:00
INDEX_MPEG2 = 0 ,
INDEX_AES3 ,
INDEX_WAV ,
2019-06-21 01:11:28 +02:00
INDEX_D10_VIDEO ,
INDEX_D10_AUDIO ,
2017-08-29 02:13:21 +02:00
INDEX_DV ,
2018-10-16 22:19:45 +02:00
INDEX_DNXHD ,
2017-08-29 02:13:21 +02:00
INDEX_JPEG2000 ,
INDEX_H264 ,
2018-10-16 22:19:45 +02:00
INDEX_S436M ,
2018-12-05 19:10:37 +02:00
INDEX_PRORES ,
2017-08-29 02:13:21 +02:00
} ;
2017-09-10 22:10:43 +02:00
static const struct {
enum AVCodecID id ;
enum ULIndex index ;
} mxf_essence_mappings [ ] = {
{ AV_CODEC_ID_MPEG2VIDEO , INDEX_MPEG2 } ,
{ AV_CODEC_ID_PCM_S24LE , INDEX_AES3 } ,
{ AV_CODEC_ID_PCM_S16LE , INDEX_AES3 } ,
{ AV_CODEC_ID_DVVIDEO , INDEX_DV } ,
2018-10-16 22:19:45 +02:00
{ AV_CODEC_ID_DNXHD , INDEX_DNXHD } ,
2017-09-10 22:10:43 +02:00
{ AV_CODEC_ID_JPEG2000 , INDEX_JPEG2000 } ,
{ AV_CODEC_ID_H264 , INDEX_H264 } ,
2018-12-05 19:10:37 +02:00
{ AV_CODEC_ID_PRORES , INDEX_PRORES } ,
2017-09-10 22:10:43 +02:00
{ AV_CODEC_ID_NONE }
} ;
static void mxf_write_wav_desc ( AVFormatContext * s , AVStream * st ) ;
static void mxf_write_aes3_desc ( AVFormatContext * s , AVStream * st ) ;
static void mxf_write_mpegvideo_desc ( AVFormatContext * s , AVStream * st ) ;
2018-10-18 22:37:05 +02:00
static void mxf_write_h264_desc ( AVFormatContext * s , AVStream * st ) ;
2017-09-10 22:10:43 +02:00
static void mxf_write_cdci_desc ( AVFormatContext * s , AVStream * st ) ;
static void mxf_write_generic_sound_desc ( AVFormatContext * s , AVStream * st ) ;
2016-11-19 21:09:24 +02:00
static void mxf_write_s436m_anc_desc ( AVFormatContext * s , AVStream * st ) ;
2017-09-10 22:10:43 +02:00
2008-08-31 07:20:47 +03:00
static const MXFContainerEssenceEntry mxf_essence_container_uls [ ] = {
2008-08-31 04:33:28 +03:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x02 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x04 , 0x60 , 0x01 } ,
2008-08-31 05:41:31 +03:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x05 , 0x00 } ,
2008-08-31 07:07:41 +03:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x03 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 } ,
2009-02-02 12:54:10 +02:00
mxf_write_mpegvideo_desc } ,
2009-01-31 09:02:20 +02: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 12:54:10 +02:00
mxf_write_aes3_desc } ,
2008-08-31 04:33:28 +03:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x06 , 0x01 , 0x00 } ,
2008-08-31 05:41:31 +03:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x16 , 0x01 , 0x01 , 0x00 } ,
2008-08-31 07:07:41 +03:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 } ,
2009-02-02 12:54:10 +02:00
mxf_write_wav_desc } ,
2019-06-21 01:11:28 +02:00
// D-10 Video
2009-02-13 09:28:20 +02:00
{ { 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 } ,
2019-06-21 01:11:28 +02:00
// D-10 Audio
2009-02-13 09:28:20 +02:00
{ { 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 } ,
2019-06-21 00:40:31 +02:00
// DV
2012-05-26 19:09:47 +03: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 } ,
2018-10-16 22:19:45 +02:00
// DNxHD
2012-05-29 01:45:41 +03:00
{ { 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 20:29:42 +03:00
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0A , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x01 , 0x00 , 0x00 } ,
2012-05-29 01:45:41 +03:00
mxf_write_cdci_desc } ,
2014-09-30 15:16:52 +03: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-29 00:38:22 +02: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 } ,
2018-10-18 22:37:05 +02:00
mxf_write_h264_desc } ,
2016-11-19 21:09:24 +02:00
// S436M ANC
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x0e , 0x00 , 0x00 } ,
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x17 , 0x01 , 0x02 , 0x00 } ,
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x01 , 0x5C , 0x00 } ,
mxf_write_s436m_anc_desc } ,
2018-12-05 19:10:37 +02:00
// ProRes
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x0d , 0x01 , 0x03 , 0x01 , 0x02 , 0x1c , 0x01 , 0x00 } ,
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x02 , 0x01 , 0x01 , 0x0d , 0x01 , 0x03 , 0x01 , 0x15 , 0x01 , 0x17 , 0x00 } ,
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x03 , 0x00 } ,
mxf_write_cdci_desc } ,
2008-08-31 04:33:28 +03:00
{ { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ,
2008-08-31 05:41:31 +03:00
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ,
2008-08-31 07:07:41 +03:00
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ,
2009-02-02 12:54:10 +02:00
NULL } ,
2008-08-31 04:33:28 +03:00
} ;
2019-06-21 01:11:28 +02:00
static const UID mxf_d10_codec_uls [ ] = {
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x01 } , // D-10 625/50 PAL 50mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x02 } , // D-10 525/50 NTSC 50mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x03 } , // D-10 625/50 PAL 40mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x04 } , // D-10 525/50 NTSC 40mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x05 } , // D-10 625/50 PAL 30mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x02 , 0x01 , 0x06 } , // D-10 525/50 NTSC 30mb/s
} ;
static const UID mxf_d10_container_uls [ ] = {
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 } , // D-10 625/50 PAL 50mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x02 , 0x01 } , // D-10 525/50 NTSC 50mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x03 , 0x01 } , // D-10 625/50 PAL 40mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x04 , 0x01 } , // D-10 525/50 NTSC 40mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x05 , 0x01 } , // D-10 625/50 PAL 30mb/s
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x01 , 0x06 , 0x01 } , // D-10 525/50 NTSC 30mb/s
} ;
2008-08-19 15:36:17 +03:00
typedef struct MXFContext {
2011-07-06 17:35:12 +03:00
AVClass * av_class ;
2008-08-31 06:36:25 +03:00
int64_t footer_partition_offset ;
2008-08-19 15:36:17 +03:00
int essence_container_count ;
2009-01-31 08:18:25 +02:00
AVRational time_base ;
2009-01-31 08:32:12 +02:00
int header_written ;
2009-02-02 12:03:38 +02:00
MXFIndexEntry * index_entries ;
unsigned edit_units_count ;
2009-02-05 22:15:18 +02:00
uint64_t timestamp ; ///< timestamp, as year(16),month(8),day(8),hour(8),minutes(8),msec/4(8)
2009-02-08 11:39:19 +02:00
uint8_t slice_count ; ///< index slice count minus 1 (1 if no audio, 0 otherwise)
2009-02-10 11:02:29 +02: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 09:18:00 +02:00
uint64_t duration ;
2012-01-16 16:19:37 +03:00
AVTimecode tc ; ///< timecode context
2009-02-11 09:18:00 +02:00
AVStream * timecode_track ;
int timecode_base ; ///< rounded time code base (25 or 30)
2009-02-13 09:28:20 +02:00
int edit_unit_byte_count ; ///< fixed edit unit byte count
2018-03-21 22:13:51 +02:00
int content_package_rate ; ///< content package rate in system element, see SMPTE 326M
2009-02-14 00:38:05 +02:00
uint64_t body_offset ;
2009-03-11 08:15:00 +02:00
uint32_t instance_number ;
uint8_t umid [ 16 ] ; ///< unique material identifier
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
int channel_count ;
2015-06-06 03:06:12 +02:00
int signal_standard ;
2015-03-15 02:59:50 +02:00
uint32_t tagged_value_count ;
2015-04-12 02:18:13 +02:00
AVRational audio_edit_rate ;
2015-11-09 15:24:26 +02:00
int store_user_comments ;
2017-12-05 06:46:21 +02:00
int track_instance_count ; // used to generate MXFTrack uuids
2018-03-21 21:53:56 +02:00
int cbr_index ; ///< use a constant bitrate index
2008-08-19 15:36:17 +03:00
} MXFContext ;
2008-08-20 01:01:57 +03:00
2008-08-18 21:11:00 +03:00
static const uint8_t uuid_base [ ] = { 0xAD , 0xAB , 0x44 , 0x24 , 0x2f , 0x25 , 0x4d , 0xc7 , 0x92 , 0xff , 0x29 , 0xbd } ;
2009-03-11 08:15:00 +02:00
static const uint8_t umid_ul [ ] = { 0x06 , 0x0A , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x01 , 0x01 , 0x0D , 0x00 , 0x13 } ;
2008-08-18 21:11:00 +03:00
/**
* complete key for operation pattern , partitions , and primer pack
*/
2009-02-18 09:13:57 +02: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-29 05:44:21 +02: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 22:29:31 +02: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 06:06:38 +03: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 11:02:29 +02: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 06:06:38 +03:00
2008-08-20 01:01:57 +03: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 22:29:31 +02: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-20 01:01:57 +03:00
2008-08-22 07:12:52 +03:00
/**
* SMPTE RP210 http : //www.smpte-ra.org/mdd/index.html
2016-08-09 14:15:38 +02:00
* https : //smpte-ra.org/sites/default/files/Labels.xml
2008-08-22 07:12:52 +03:00
*/
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 */
2018-03-17 22:16:26 +02:00
{ 0x3B07 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x01 , 0x02 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 } } , /* Object Model Version */
2008-08-22 07:12:52 +03:00
{ 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 */
2018-03-17 17:01:15 +02:00
{ 0x3C03 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 } } , /* Product Version */
2008-08-29 19:56:36 +03:00
{ 0x3C04 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x05 , 0x01 , 0x00 , 0x00 } } , /* Version String */
2008-08-22 07:12:52 +03: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 */
2018-03-17 17:01:15 +02:00
{ 0x3C07 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x0A , 0x00 , 0x00 , 0x00 } } , /* Toolkit Version */
{ 0x3C08 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x05 , 0x20 , 0x07 , 0x01 , 0x06 , 0x01 , 0x00 , 0x00 } } , /* Platform */
2008-08-22 07:12:52 +03:00
// 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 22:57:12 +02: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 07:12:52 +03: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-22 01:45:27 +02:00
{ 0x4402 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x02 , 0x01 , 0x00 , 0x00 , 0x00 } } , /* Package Name */
2008-08-22 07:12:52 +03:00
{ 0x4403 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x05 , 0x00 , 0x00 } } , /* Tracks Strong reference array */
{ 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 04:34:26 +03:00
{ 0x4804 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x01 , 0x04 , 0x01 , 0x03 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Track Number */
2008-08-22 07:12:52 +03: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 07:22:38 +02:00
{ 0x1201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x07 , 0x02 , 0x01 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 } } , /* Start position */
2008-08-22 07:12:52 +03: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 09:18:00 +02: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 */
2008-08-29 20:04:18 +03: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 07:12:52 +03: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-22 01:45:27 +02:00
{ 0x3002 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x06 , 0x01 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* ContainerDuration */
2008-08-29 20:04:18 +03: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 11:08:01 +02:00
{ 0x320C , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 } } , /* Frame Layout */
2009-02-10 07:22:38 +02:00
{ 0x320D , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x03 , 0x02 , 0x05 , 0x00 , 0x00 , 0x00 } } , /* Video Line Map */
2008-08-29 20:04:18 +03: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 */
2018-03-18 00:06:13 +02:00
{ 0x3216 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x03 , 0x02 , 0x08 , 0x00 , 0x00 , 0x00 } } , /* Stored F2 Offset */
{ 0x3205 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x08 , 0x00 , 0x00 , 0x00 } } , /* Sampled Width */
{ 0x3204 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x07 , 0x00 , 0x00 , 0x00 } } , /* Sampled Height */
{ 0x3206 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x09 , 0x00 , 0x00 , 0x00 } } , /* Sampled X Offset */
{ 0x3207 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0A , 0x00 , 0x00 , 0x00 } } , /* Sampled Y Offset */
2009-02-02 05:35:09 +02: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 */
2018-03-18 00:06:13 +02:00
{ 0x320A , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0D , 0x00 , 0x00 , 0x00 } } , /* Display X offset */
2015-03-30 12:11:17 +02:00
{ 0x320B , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x01 , 0x0E , 0x00 , 0x00 , 0x00 } } , /* Presentation Y offset */
2018-03-18 00:06:13 +02:00
{ 0x3217 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x03 , 0x02 , 0x07 , 0x00 , 0x00 , 0x00 } } , /* Display F2 offset */
2008-08-29 20:04:18 +03:00
{ 0x320E , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 } } , /* Aspect Ratio */
2018-03-21 22:34:20 +02:00
{ 0x3210 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x02 , 0x01 , 0x01 , 0x01 , 0x02 , 0x00 } } , /* Transfer characteristic */
2018-04-18 00:09:00 +02:00
{ 0x3213 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x18 , 0x01 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Image Start Offset */
{ 0x3214 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x18 , 0x01 , 0x03 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Image End Offset */
2008-08-29 20:04:18 +03:00
{ 0x3201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x06 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Picture Essence Coding */
2012-05-27 15:21:41 +03: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 08:14:39 +02: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 */
2018-03-21 20:32:32 +02:00
{ 0x3308 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x05 , 0x01 , 0x10 , 0x00 , 0x00 , 0x00 } } , /* Vertical 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 */
2018-04-05 23:30:37 +02:00
{ 0x3307 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x18 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Padding Bits */
2018-04-05 22:53:22 +02:00
{ 0x3304 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x03 , 0x03 , 0x00 , 0x00 , 0x00 } } , /* Black Ref level */
{ 0x3305 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x05 , 0x03 , 0x04 , 0x00 , 0x00 , 0x00 } } , /* White Ref level */
{ 0x3306 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x05 , 0x03 , 0x05 , 0x00 , 0x00 , 0x00 } } , /* Color Range */
2008-08-29 20:04:18 +03:00
// Generic Sound Essence Descriptor
2009-02-10 07:22:38 +02:00
{ 0x3D02 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x04 , 0x04 , 0x02 , 0x03 , 0x01 , 0x04 , 0x00 , 0x00 , 0x00 } } , /* Locked/Unlocked */
2008-08-29 20:04:18 +03:00
{ 0x3D03 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x02 , 0x03 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 } } , /* Audio sampling rate */
2018-04-06 21:44:23 +02:00
{ 0x3D04 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x01 , 0x04 , 0x02 , 0x01 , 0x01 , 0x03 , 0x00 , 0x00 , 0x00 } } , /* Audio Ref Level */
2008-08-29 20:04:18 +03:00
{ 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-27 01:59:28 +02:00
{ 0x3D06 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x04 , 0x02 , 0x04 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 } } , /* Sound Essence Compression */
2009-02-02 12:03:38 +02: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 07:22:38 +02: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 12:03:38 +02: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 05:45:03 +02:00
// MPEG video Descriptor
{ 0x8000 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x0B , 0x00 , 0x00 } } , /* BitRate */
2018-03-21 18:35:22 +02:00
{ 0x8003 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x05 , 0x00 , 0x00 } } , /* LowDelay */
{ 0x8004 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x06 , 0x00 , 0x00 } } , /* ClosedGOP */
{ 0x8006 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x08 , 0x00 , 0x00 } } , /* MaxGOP */
2009-07-04 10:49:12 +03:00
{ 0x8007 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x0A , 0x00 , 0x00 } } , /* ProfileAndLevel */
2018-03-21 18:35:22 +02:00
{ 0x8008 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x05 , 0x04 , 0x01 , 0x06 , 0x02 , 0x01 , 0x09 , 0x00 , 0x00 } } , /* BPictureCount */
2009-02-02 06:36:54 +02: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 07:12:52 +03:00
} ;
2018-10-18 22:37:05 +02:00
static const MXFLocalTagPair mxf_avc_subdescriptor_local_tags [ ] = {
{ 0x8100 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x09 , 0x06 , 0x01 , 0x01 , 0x04 , 0x06 , 0x10 , 0x00 , 0x00 } } , /* SubDescriptors */
{ 0x8200 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x0E , 0x04 , 0x01 , 0x06 , 0x06 , 0x01 , 0x0E , 0x00 , 0x00 } } , /* AVC Decoding Delay */
{ 0x8201 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x0E , 0x04 , 0x01 , 0x06 , 0x06 , 0x01 , 0x0A , 0x00 , 0x00 } } , /* AVC Profile */
{ 0x8202 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x0E , 0x04 , 0x01 , 0x06 , 0x06 , 0x01 , 0x0D , 0x00 , 0x00 } } , /* AVC Level */
} ;
2015-11-09 15:24:26 +02:00
static const MXFLocalTagPair mxf_user_comments_local_tag [ ] = {
{ 0x4406 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x01 , 0x01 , 0x01 , 0x02 , 0x03 , 0x02 , 0x01 , 0x02 , 0x0C , 0x00 , 0x00 , 0x00 } } , /* User Comments */
{ 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 */
} ;
2011-02-20 12:04:12 +02:00
static void mxf_write_uuid ( AVIOContext * pb , enum MXFMetadataSetType type , int value )
2008-08-18 21:11:00 +03:00
{
2011-02-21 20:28:17 +02:00
avio_write ( pb , uuid_base , 12 ) ;
avio_wb16 ( pb , type ) ;
avio_wb16 ( pb , value ) ;
2008-08-18 21:11:00 +03:00
}
2009-03-11 08:15:00 +02:00
static void mxf_write_umid ( AVFormatContext * s , int type )
2008-08-19 15:36:17 +03:00
{
2009-03-11 08:15:00 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-21 20:28:17 +02: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 15:36:17 +03:00
}
2008-08-20 01:01:57 +03:00
2011-02-20 12:04:12 +02:00
static void mxf_write_refs_count ( AVIOContext * pb , int ref_count )
2008-08-20 01:01:57 +03:00
{
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , ref_count ) ;
avio_wb32 ( pb , 16 ) ;
2008-08-20 01:01:57 +03:00
}
2009-02-07 04:13:23 +02:00
static int klv_ber_length ( uint64_t len )
{
if ( len < 128 )
return 1 ;
else
return ( av_log2 ( len ) > > 3 ) + 2 ;
}
2011-02-20 12:04:12 +02:00
static int klv_encode_ber_length ( AVIOContext * pb , uint64_t len )
2008-08-18 21:11:00 +03:00
{
// Determine the best BER size
2019-08-29 10:44:01 +02:00
int size = klv_ber_length ( len ) ;
if ( size = = 1 ) {
2008-08-18 21:11:00 +03:00
//short form
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , len ) ;
2008-08-18 21:11:00 +03:00
return 1 ;
}
2019-08-29 10:44:01 +02:00
size - - ;
2008-08-18 21:11:00 +03:00
// long form
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0x80 + size ) ;
2008-08-18 21:11:00 +03:00
while ( size ) {
2009-02-02 22:29:31 +02:00
size - - ;
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , len > > 8 * size & 0xff ) ;
2008-08-18 21:11:00 +03:00
}
return 0 ;
}
2011-02-20 12:04:12 +02:00
static void klv_encode_ber4_length ( AVIOContext * pb , int len )
2009-02-13 07:33:11 +02:00
{
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0x80 + 3 ) ;
avio_wb24 ( pb , len ) ;
2009-02-13 07:33:11 +02:00
}
2015-01-29 05:44:21 +02:00
static void klv_encode_ber9_length ( AVIOContext * pb , uint64_t len )
{
avio_w8 ( pb , 0x80 + 8 ) ;
avio_wb64 ( pb , len ) ;
}
2008-08-31 03:23:38 +03:00
/*
2008-08-31 07:13:44 +03:00
* Get essence container ul index
2008-08-31 03:23:38 +03:00
*/
2012-08-05 12:11:04 +03:00
static int mxf_get_essence_container_ul_index ( enum AVCodecID id )
2008-08-15 00:48:02 +03:00
{
2008-08-31 07:13:44 +03:00
int i ;
2009-02-02 12:54:10 +02: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 07:13:44 +03:00
return - 1 ;
2008-08-15 00:48:02 +03:00
}
2018-10-18 22:37:05 +02:00
static void mxf_write_local_tags ( AVIOContext * pb , const MXFLocalTagPair * local_tags , int count )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
avio_wb16 ( pb , local_tags [ i ] . local_tag ) ;
avio_write ( pb , local_tags [ i ] . uid , 16 ) ;
}
}
2008-08-22 07:12:52 +03:00
static void mxf_write_primer_pack ( AVFormatContext * s )
2008-08-18 21:11:00 +03:00
{
2015-11-09 15:24:26 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-18 21:11:00 +03:00
int local_tag_number , i = 0 ;
2018-10-18 22:37:05 +02:00
int avc_tags_count = 0 ;
2008-08-18 21:11:00 +03:00
2008-10-22 00:40:24 +03:00
local_tag_number = FF_ARRAY_ELEMS ( mxf_local_tag_batch ) ;
2015-11-09 15:24:26 +02:00
local_tag_number + = mxf - > store_user_comments * FF_ARRAY_ELEMS ( mxf_user_comments_local_tag ) ;
2008-08-18 21:11:00 +03:00
2018-10-18 22:37:05 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
MXFStreamContext * sc = s - > streams [ i ] - > priv_data ;
if ( s - > streams [ i ] - > codecpar - > codec_id = = AV_CODEC_ID_H264 & & ! sc - > avc_intra ) {
avc_tags_count = FF_ARRAY_ELEMS ( mxf_avc_subdescriptor_local_tags ) ;
local_tag_number + = avc_tags_count ;
}
}
2011-02-21 20:28:17 +02:00
avio_write ( pb , primer_pack_key , 16 ) ;
2008-08-18 21:11:00 +03:00
klv_encode_ber_length ( pb , local_tag_number * 18 + 8 ) ;
2011-02-21 20:28:17 +02: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 21:11:00 +03:00
2015-11-09 15:24:26 +02:00
for ( i = 0 ; i < FF_ARRAY_ELEMS ( mxf_local_tag_batch ) ; i + + ) {
2011-02-21 20:28:17 +02:00
avio_wb16 ( pb , mxf_local_tag_batch [ i ] . local_tag ) ;
avio_write ( pb , mxf_local_tag_batch [ i ] . uid , 16 ) ;
2008-08-18 21:11:00 +03:00
}
2015-11-09 15:24:26 +02:00
if ( mxf - > store_user_comments )
for ( i = 0 ; i < FF_ARRAY_ELEMS ( mxf_user_comments_local_tag ) ; i + + ) {
avio_wb16 ( pb , mxf_user_comments_local_tag [ i ] . local_tag ) ;
avio_write ( pb , mxf_user_comments_local_tag [ i ] . uid , 16 ) ;
}
2018-10-18 22:37:05 +02:00
if ( avc_tags_count > 0 )
mxf_write_local_tags ( pb , mxf_avc_subdescriptor_local_tags , avc_tags_count ) ;
2008-08-18 21:11:00 +03:00
}
2011-02-20 12:04:12 +02:00
static void mxf_write_local_tag ( AVIOContext * pb , int size , int tag )
2008-08-18 21:11:00 +03:00
{
2011-02-21 20:28:17 +02:00
avio_wb16 ( pb , tag ) ;
avio_wb16 ( pb , size ) ;
2008-08-18 21:11:00 +03:00
}
2011-02-20 12:04:12 +02:00
static void mxf_write_metadata_key ( AVIOContext * pb , unsigned int value )
2008-08-19 15:36:17 +03:00
{
2011-02-21 20:28:17 +02:00
avio_write ( pb , header_metadata_key , 13 ) ;
avio_wb24 ( pb , value ) ;
2008-08-19 15:36:17 +03:00
}
2009-02-08 07:12:30 +02:00
static const MXFCodecUL * mxf_get_data_definition_ul ( int type )
2008-08-15 00:48:02 +03:00
{
2009-02-08 07:12:30 +02:00
const MXFCodecUL * uls = ff_mxf_data_definition_uls ;
while ( uls - > uid [ 0 ] ) {
if ( type = = uls - > id )
2008-08-15 00:48:02 +03:00
break ;
2008-08-31 01:58:49 +03:00
uls + + ;
2008-08-15 00:48:02 +03:00
}
return uls ;
}
2012-10-25 11:23:59 +03: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 03:28:36 +03:00
static void mxf_write_essence_container_refs ( AVFormatContext * s )
2008-08-26 18:58:25 +03:00
{
2008-08-31 03:23:38 +03:00
MXFContext * c = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-31 03:23:38 +03:00
int i ;
2008-08-26 18:58:25 +03:00
2012-10-25 11:23:59 +03:00
mxf_write_refs_count ( pb , DESCRIPTOR_COUNT ( c - > essence_container_count ) ) ;
2008-08-31 03:28:51 +03:00
av_log ( s , AV_LOG_DEBUG , " essence container count:%d \n " , c - > essence_container_count ) ;
2016-11-19 21:09:24 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2009-02-13 09:46:03 +02:00
MXFStreamContext * sc = s - > streams [ i ] - > priv_data ;
2016-11-19 21:09:24 +02:00
// check first track of essence container type and only write it once
if ( sc - > track_essence_element_key [ 15 ] ! = 0 )
continue ;
2019-06-21 00:40:31 +02:00
avio_write ( pb , * sc - > container_ul , 16 ) ;
2016-11-19 21:09:24 +02:00
if ( c - > essence_container_count = = 1 )
break ;
2008-08-31 03:28:51 +03:00
}
2012-10-25 11:23:59 +03:00
if ( c - > essence_container_count > 1 )
avio_write ( pb , multiple_desc_ul , 16 ) ;
2008-08-26 18:58:25 +03:00
}
2008-08-22 07:12:52 +03:00
static void mxf_write_preface ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-22 07:12:52 +03:00
mxf_write_metadata_key ( pb , 0x012f00 ) ;
PRINT_KEY ( s , " preface key " , pb - > buf_ptr - 16 ) ;
2018-03-17 22:16:26 +02:00
klv_encode_ber_length ( pb , 138 + 16LL * DESCRIPTOR_COUNT ( mxf - > essence_container_count ) ) ;
2008-08-22 07:12:52 +03: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 22:15:18 +02:00
// last modified date
2008-08-22 07:12:52 +03:00
mxf_write_local_tag ( pb , 8 , 0x3B02 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > timestamp ) ;
2008-08-22 07:12:52 +03:00
// write version
mxf_write_local_tag ( pb , 2 , 0x3B05 ) ;
2018-05-08 21:24:15 +02:00
avio_wb16 ( pb , 259 ) ; // v1.3
2008-08-22 07:12:52 +03:00
2018-03-17 22:16:26 +02:00
// Object Model Version
mxf_write_local_tag ( pb , 4 , 0x3B07 ) ;
avio_wb32 ( pb , 1 ) ;
2008-08-22 07:12:52 +03: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 06:53:41 +02:00
// operational pattern
2008-08-22 07:12:52 +03:00
mxf_write_local_tag ( pb , 16 , 0x3B09 ) ;
2015-01-29 05:44:21 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer )
avio_write ( pb , opatom_ul , 16 ) ;
else
avio_write ( pb , op1a_ul , 16 ) ;
2008-08-22 07:12:52 +03:00
// write essence_container_refs
2012-10-25 11:23:59 +03:00
mxf_write_local_tag ( pb , 8 + 16LL * DESCRIPTOR_COUNT ( mxf - > essence_container_count ) , 0x3B0A ) ;
2008-08-31 03:28:36 +03:00
mxf_write_essence_container_refs ( s ) ;
2008-08-22 07:12:52 +03:00
// write dm_scheme_refs
mxf_write_local_tag ( pb , 8 , 0x3B0B ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-22 07:12:52 +03:00
}
2008-08-31 01:23:11 +03:00
/*
2015-03-05 20:59:11 +02: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 :
2016-07-17 18:10:27 +02:00
av_log ( NULL , AV_LOG_ERROR , " Invalid UTF8 sequence in mxf_utf16len \n \n " ) ;
2015-03-05 20:59:11 +02:00
}
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-31 01:23:11 +03:00
*/
2011-02-20 12:04:12 +02:00
static void mxf_write_local_tag_utf16 ( AVIOContext * pb , int tag , const char * value )
2008-08-31 01:23:11 +03:00
{
2015-03-05 20:59:11 +02: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-31 01:32:23 +03:00
mxf_write_local_tag ( pb , size * 2 , tag ) ;
2015-03-05 20:59:11 +02:00
avio_put_str16be ( pb , value ) ;
2008-08-31 01:23:11 +03:00
}
2018-03-17 17:01:15 +02:00
static void store_version ( AVFormatContext * s ) {
AVIOContext * pb = s - > pb ;
if ( s - > flags & AVFMT_FLAG_BITEXACT ) {
avio_wb16 ( pb , 0 ) ; // major
avio_wb16 ( pb , 0 ) ; // minor
avio_wb16 ( pb , 0 ) ; // tertiary
} else {
avio_wb16 ( pb , LIBAVFORMAT_VERSION_MAJOR ) ; // major
avio_wb16 ( pb , LIBAVFORMAT_VERSION_MINOR ) ; // minor
avio_wb16 ( pb , LIBAVFORMAT_VERSION_MICRO ) ; // tertiary
}
avio_wb16 ( pb , 0 ) ; // patch
avio_wb16 ( pb , 0 ) ; // release
}
2008-08-22 07:12:52 +03:00
static void mxf_write_identification ( AVFormatContext * s )
{
2009-02-05 22:15:18 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-04-18 00:57:50 +03:00
const char * company = " FFmpeg " ;
2015-03-01 14:02:20 +02:00
const char * product = s - > oformat ! = & ff_mxf_opatom_muxer ? " OP1a Muxer " : " OPAtom Muxer " ;
2008-08-31 01:37:19 +03:00
const char * version ;
2008-08-31 01:45:32 +03:00
int length ;
2008-08-22 07:12:52 +03:00
mxf_write_metadata_key ( pb , 0x013000 ) ;
PRINT_KEY ( s , " identification key " , pb - > buf_ptr - 16 ) ;
2014-05-01 11:43:10 +03:00
version = s - > flags & AVFMT_FLAG_BITEXACT ?
2008-08-31 01:41:01 +03:00
" 0.0.0 " : AV_STRINGIFY ( LIBAVFORMAT_VERSION ) ;
2018-03-17 17:01:15 +02:00
length = 100 + mxf_utf16_local_tag_length ( company ) +
2015-03-05 20:59:11 +02:00
mxf_utf16_local_tag_length ( product ) +
mxf_utf16_local_tag_length ( version ) ;
2008-08-22 07:12:52 +03: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-31 01:45:49 +03:00
2008-08-22 07:12:52 +03:00
// write generation uid
mxf_write_local_tag ( pb , 16 , 0x3C09 ) ;
mxf_write_uuid ( pb , Identification , 1 ) ;
2008-08-31 01:45:32 +03:00
mxf_write_local_tag_utf16 ( pb , 0x3C01 , company ) ; // Company Name
mxf_write_local_tag_utf16 ( pb , 0x3C02 , product ) ; // Product Name
2018-03-17 17:01:15 +02:00
mxf_write_local_tag ( pb , 10 , 0x3C03 ) ; // Product Version
store_version ( s ) ;
2008-08-31 01:37:19 +03:00
mxf_write_local_tag_utf16 ( pb , 0x3C04 , version ) ; // Version String
2008-08-22 07:12:52 +03:00
// write product uid
mxf_write_local_tag ( pb , 16 , 0x3C05 ) ;
mxf_write_uuid ( pb , Identification , 2 ) ;
2009-02-05 21:30:01 +02:00
// modification date
2008-08-22 07:12:52 +03:00
mxf_write_local_tag ( pb , 8 , 0x3C06 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > timestamp ) ;
2018-03-17 17:01:15 +02:00
mxf_write_local_tag ( pb , 10 , 0x3C07 ) ; // Toolkit Version
store_version ( s ) ;
2008-08-22 07:12:52 +03:00
}
2017-11-27 07:42:16 +02:00
static void mxf_write_content_storage ( AVFormatContext * s , MXFPackage * packages , int package_count )
2008-08-22 07:12:52 +03:00
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2017-11-27 07:42:16 +02:00
int i ;
2008-08-22 07:12:52 +03:00
mxf_write_metadata_key ( pb , 0x011800 ) ;
PRINT_KEY ( s , " content storage key " , pb - > buf_ptr - 16 ) ;
2017-11-27 07:42:16 +02:00
klv_encode_ber_length ( pb , 60 + ( 16 * package_count ) ) ;
2008-08-22 07:12:52 +03: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-31 01:58:49 +03:00
2008-08-22 07:12:52 +03:00
// write package reference
2017-11-27 07:42:16 +02:00
mxf_write_local_tag ( pb , 16 * package_count + 8 , 0x1901 ) ;
mxf_write_refs_count ( pb , package_count ) ;
for ( i = 0 ; i < package_count ; i + + ) {
mxf_write_uuid ( pb , packages [ i ] . type , packages [ i ] . instance ) ;
}
2009-01-23 22:57:12 +02: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 07:12:52 +03:00
}
2017-11-27 07:42:16 +02:00
static void mxf_write_track ( AVFormatContext * s , AVStream * st , MXFPackage * package )
2008-08-24 08:55:46 +03:00
{
2009-02-04 06:50:47 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-31 03:36:30 +03:00
MXFStreamContext * sc = st - > priv_data ;
2008-08-24 08:55:46 +03: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 ) ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , Track , mxf - > track_instance_count ) ;
2008-08-24 08:55:46 +03:00
PRINT_KEY ( s , " track uid " , pb - > buf_ptr - 16 ) ;
2008-08-31 01:58:49 +03:00
2008-08-24 08:55:46 +03:00
// write track id
mxf_write_local_tag ( pb , 4 , 0x4801 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , st - > index + 2 ) ;
2008-08-24 08:55:46 +03:00
2008-08-31 04:33:28 +03:00
// write track number
2008-08-24 08:55:46 +03:00
mxf_write_local_tag ( pb , 4 , 0x4804 ) ;
2017-11-27 07:42:16 +02:00
if ( package - > type = = MaterialPackage )
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 0 ) ; // track number of material package is 0
2008-08-31 04:33:28 +03:00
else
2011-02-21 20:28:17 +02:00
avio_write ( pb , sc - > track_essence_element_key + 12 , 4 ) ;
2008-08-24 08:55:46 +03:00
2017-09-10 22:10:44 +02:00
// write edit rate
2008-08-24 08:55:46 +03:00
mxf_write_local_tag ( pb , 8 , 0x4B01 ) ;
2015-04-12 02:18:13 +02:00
2017-09-14 16:05:31 +02:00
if ( st = = mxf - > timecode_track & & s - > oformat = = & ff_mxf_opatom_muxer ) {
2015-04-12 02:18:13 +02:00
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 08:55:46 +03:00
// write origin
mxf_write_local_tag ( pb , 8 , 0x4B02 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
// write sequence refs
mxf_write_local_tag ( pb , 16 , 0x4803 ) ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , Sequence , mxf - > track_instance_count ) ;
2008-08-24 08:55:46 +03:00
}
2009-02-11 09:18:00 +02: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-20 01:01:57 +03:00
{
2009-02-11 09:18:00 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-31 05:46:50 +03:00
2008-08-20 01:01:57 +03:00
// find data define uls
mxf_write_local_tag ( pb , 16 , 0x0201 ) ;
2009-02-11 09:18:00 +02:00
if ( st = = mxf - > timecode_track )
2011-02-21 20:28:17 +02:00
avio_write ( pb , smpte_12m_timecode_track_data_ul , 16 ) ;
2009-02-11 09:18:00 +02:00
else {
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
const MXFCodecUL * data_def_ul = mxf_get_data_definition_ul ( st - > codecpar - > codec_type ) ;
2011-02-21 20:28:17 +02:00
avio_write ( pb , data_def_ul - > uid , 16 ) ;
2009-02-11 09:18:00 +02:00
}
2008-08-20 01:01:57 +03:00
// write duration
mxf_write_local_tag ( pb , 8 , 0x0202 ) ;
2015-04-12 02:18:13 +02:00
2017-09-14 16:05:31 +02:00
if ( st ! = mxf - > timecode_track & & s - > oformat = = & ff_mxf_opatom_muxer & & st - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2015-04-12 02:18:13 +02:00
avio_wb64 ( pb , mxf - > body_offset / mxf - > edit_unit_byte_count ) ;
} else {
avio_wb64 ( pb , mxf - > duration ) ;
}
2008-08-20 01:01:57 +03:00
}
2017-11-27 07:42:16 +02:00
static void mxf_write_sequence ( AVFormatContext * s , AVStream * st , MXFPackage * package )
2008-08-24 08:55:46 +03:00
{
2009-02-11 09:18:00 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-02-11 09:18:00 +02:00
enum MXFMetadataSetType component ;
2008-08-24 08:55:46 +03: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 ) ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , Sequence , mxf - > track_instance_count ) ;
2008-08-24 08:55:46 +03:00
PRINT_KEY ( s , " sequence uid " , pb - > buf_ptr - 16 ) ;
2009-02-11 09:18:00 +02:00
mxf_write_common_fields ( s , st ) ;
2008-08-24 08:55:46 +03:00
// write structural component
mxf_write_local_tag ( pb , 16 + 8 , 0x1001 ) ;
mxf_write_refs_count ( pb , 1 ) ;
2009-02-11 09:18:00 +02:00
if ( st = = mxf - > timecode_track )
component = TimecodeComponent ;
else
2009-02-18 03:35:36 +02:00
component = SourceClip ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , component , mxf - > track_instance_count ) ;
2009-02-11 09:18:00 +02:00
}
2017-11-27 07:42:16 +02:00
static void mxf_write_timecode_component ( AVFormatContext * s , AVStream * st , MXFPackage * package )
2009-02-11 09:18:00 +02:00
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-02-11 09:18:00 +02:00
mxf_write_metadata_key ( pb , 0x011400 ) ;
klv_encode_ber_length ( pb , 75 ) ;
// UID
mxf_write_local_tag ( pb , 16 , 0x3C0A ) ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , TimecodeComponent , mxf - > track_instance_count ) ;
2009-02-11 09:18:00 +02:00
mxf_write_common_fields ( s , st ) ;
// Start Time Code
mxf_write_local_tag ( pb , 8 , 0x1501 ) ;
2011-07-06 17:35:12 +03:00
avio_wb64 ( pb , mxf - > tc . start ) ;
2009-02-11 09:18:00 +02:00
// Rounded Time Code Base
mxf_write_local_tag ( pb , 2 , 0x1502 ) ;
2011-02-21 20:28:17 +02:00
avio_wb16 ( pb , mxf - > timecode_base ) ;
2009-02-11 09:18:00 +02:00
// Drop Frame
mxf_write_local_tag ( pb , 1 , 0x1503 ) ;
2012-01-16 16:19:37 +03:00
avio_w8 ( pb , ! ! ( mxf - > tc . flags & AV_TIMECODE_FLAG_DROPFRAME ) ) ;
2008-08-24 08:55:46 +03:00
}
2017-11-27 07:42:16 +02:00
static void mxf_write_structural_component ( AVFormatContext * s , AVStream * st , MXFPackage * package )
2008-08-24 08:55:46 +03:00
{
2017-12-05 06:46:21 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-24 08:55:46 +03: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 ) ;
2017-12-05 06:46:21 +02:00
mxf_write_uuid ( pb , SourceClip , mxf - > track_instance_count ) ;
2008-08-24 08:55:46 +03:00
PRINT_KEY ( s , " structural component uid " , pb - > buf_ptr - 16 ) ;
2009-02-11 09:18:00 +02:00
mxf_write_common_fields ( s , st ) ;
2008-08-24 08:55:46 +03:00
// write start_position
mxf_write_local_tag ( pb , 8 , 0x1201 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
2008-08-31 01:58:49 +03:00
// write source package uid, end of the reference
2008-08-24 08:55:46 +03:00
mxf_write_local_tag ( pb , 32 , 0x1101 ) ;
2017-12-05 06:46:22 +02:00
if ( ! package - > ref ) {
2008-08-31 01:58:49 +03:00
for ( i = 0 ; i < 4 ; i + + )
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
} else
2017-12-05 06:46:22 +02:00
mxf_write_umid ( s , package - > ref - > instance ) ;
2008-08-24 08:55:46 +03:00
2008-08-31 01:58:49 +03:00
// write source track id
2008-08-24 08:55:46 +03:00
mxf_write_local_tag ( pb , 4 , 0x1102 ) ;
2017-12-05 06:46:22 +02:00
if ( package - > type = = SourcePackage & & ! package - > ref )
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
else
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , st - > index + 2 ) ;
2008-08-24 08:55:46 +03:00
}
2017-12-05 06:46:22 +02:00
static void mxf_write_tape_descriptor ( AVFormatContext * s )
{
AVIOContext * pb = s - > pb ;
mxf_write_metadata_key ( pb , 0x012e00 ) ;
PRINT_KEY ( s , " tape descriptor key " , pb - > buf_ptr - 16 ) ;
klv_encode_ber_length ( pb , 20 ) ;
mxf_write_local_tag ( pb , 16 , 0x3C0A ) ;
mxf_write_uuid ( pb , TapeDescriptor , 0 ) ;
PRINT_KEY ( s , " tape_desc uid " , pb - > buf_ptr - 16 ) ;
}
2008-08-22 07:12:52 +03:00
static void mxf_write_multi_descriptor ( AVFormatContext * s )
{
2009-02-04 11:35:59 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-02-13 09:28:20 +02:00
const uint8_t * ul ;
2008-08-22 07:12:52 +03:00
int i ;
mxf_write_metadata_key ( pb , 0x014400 ) ;
PRINT_KEY ( s , " multiple descriptor key " , pb - > buf_ptr - 16 ) ;
2012-10-24 18:06:49 +03:00
klv_encode_ber_length ( pb , 64 + 16LL * s - > nb_streams ) ;
2008-08-22 07:12:52 +03: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 20:28:17 +02:00
avio_wb32 ( pb , mxf - > time_base . den ) ;
avio_wb32 ( pb , mxf - > time_base . num ) ;
2008-08-22 07:12:52 +03:00
// write essence container ul
mxf_write_local_tag ( pb , 16 , 0x3004 ) ;
2009-02-13 09:28:20 +02:00
if ( mxf - > essence_container_count > 1 )
ul = multiple_desc_ul ;
2009-02-13 09:46:03 +02:00
else {
MXFStreamContext * sc = s - > streams [ 0 ] - > priv_data ;
2019-06-21 00:40:31 +02:00
ul = * sc - > container_ul ;
2009-02-13 09:46:03 +02:00
}
2011-02-21 20:28:17 +02:00
avio_write ( pb , ul , 16 ) ;
2008-08-22 07:12:52 +03: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-31 01:58:49 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + )
2008-08-22 07:12:52 +03:00
mxf_write_uuid ( pb , SubDescriptor , i ) ;
}
2018-03-21 17:37:59 +02:00
static int64_t mxf_write_generic_desc ( AVFormatContext * s , AVStream * st , const UID key )
2008-08-20 01:01:57 +03:00
{
2009-02-04 11:35:59 +02:00
MXFContext * mxf = s - > priv_data ;
2008-08-31 02:54:24 +03:00
MXFStreamContext * sc = st - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2018-03-21 17:37:59 +02:00
int64_t pos ;
2008-08-20 01:01:57 +03:00
2011-02-21 20:28:17 +02:00
avio_write ( pb , key , 16 ) ;
2018-03-21 17:37:59 +02:00
klv_encode_ber4_length ( pb , 0 ) ;
pos = avio_tell ( pb ) ;
2008-08-20 01:01:57 +03: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 20:28:17 +02:00
avio_wb32 ( pb , st - > index + 2 ) ;
2008-08-20 01:01:57 +03:00
2008-08-22 07:12:52 +03:00
mxf_write_local_tag ( pb , 8 , 0x3001 ) ;
2017-09-10 22:10:45 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer ) {
avio_wb32 ( pb , mxf - > time_base . den ) ;
avio_wb32 ( pb , mxf - > time_base . num ) ;
} else {
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_PCM_S16LE | |
st - > codecpar - > codec_id = = AV_CODEC_ID_PCM_S24LE ) {
avio_wb32 ( pb , st - > codecpar - > sample_rate ) ;
avio_wb32 ( pb , 1 ) ;
} else {
avio_wb32 ( pb , mxf - > time_base . den ) ;
avio_wb32 ( pb , mxf - > time_base . num ) ;
}
}
2008-08-22 07:12:52 +03:00
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 16 , 0x3004 ) ;
2019-06-21 00:40:31 +02:00
avio_write ( pb , * sc - > container_ul , 16 ) ;
2018-03-21 17:37:59 +02:00
return pos ;
2008-08-20 01:01:57 +03:00
}
2016-11-19 21:09:24 +02:00
static const UID mxf_s436m_anc_descriptor_key = { 0x06 , 0x0e , 0x2b , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x5c , 0x00 } ;
2008-08-31 07:07:41 +03: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 09:02:20 +02: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 09:28:20 +02: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 07:07:41 +03:00
2018-10-18 22:37:05 +02:00
static const UID mxf_avc_subdescriptor_key = { 0x06 , 0x0E , 0x2B , 0x34 , 0x02 , 0x53 , 0x01 , 0x01 , 0x0d , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x6E , 0x00 } ;
2018-03-21 22:34:20 +02:00
static int get_trc ( UID ul , enum AVColorTransferCharacteristic trc )
{
switch ( trc ) {
case AVCOL_TRC_GAMMA28 :
case AVCOL_TRC_GAMMA22 :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
case AVCOL_TRC_BT709 :
case AVCOL_TRC_SMPTE170M :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x02 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
case AVCOL_TRC_SMPTE240M :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x03 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
case AVCOL_TRC_BT1361_ECG :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x06 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x05 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
case AVCOL_TRC_LINEAR :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x06 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x06 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
case AVCOL_TRC_SMPTE428 :
2018-05-22 20:57:13 +02:00
memcpy ( ul , ( ( UID ) { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x08 , 0x04 , 0x01 , 0x01 , 0x01 , 0x01 , 0x07 , 0x00 , 0x00 } ) , 16 ) ;
2018-03-21 22:34:20 +02:00
return 0 ;
default :
return - 1 ;
}
}
2018-03-21 17:37:59 +02:00
static int64_t mxf_write_cdci_common ( AVFormatContext * s , AVStream * st , const UID key )
2008-08-20 01:01:57 +03:00
{
2009-01-31 08:46:42 +02:00
MXFStreamContext * sc = st - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2019-08-26 22:15:32 +02:00
int stored_width = 0 ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
int stored_height = ( st - > codecpar - > height + 15 ) / 16 * 16 ;
2009-02-13 09:13:36 +02:00
int display_height ;
2009-01-31 11:23:50 +02:00
int f1 , f2 ;
2018-03-21 22:34:20 +02:00
UID transfer_ul = { 0 } ;
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_generic_desc ( s , st , key ) ;
2018-03-21 22:34:20 +02:00
2018-03-21 17:37:59 +02:00
get_trc ( transfer_ul , st - > codecpar - > color_trc ) ;
2008-08-20 01:01:57 +03:00
2019-08-26 22:15:32 +02:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_DVVIDEO ) {
if ( st - > codecpar - > height = = 1080 )
stored_width = 1920 ;
else if ( st - > codecpar - > height = = 720 )
stored_width = 1280 ;
}
if ( ! stored_width )
stored_width = ( st - > codecpar - > width + 15 ) / 16 * 16 ;
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 4 , 0x3203 ) ;
2018-03-18 00:04:50 +02:00
avio_wb32 ( pb , stored_width ) ;
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 4 , 0x3202 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , stored_height > > sc - > interlaced ) ;
2008-08-20 01:01:57 +03:00
2018-04-18 00:09:00 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer ) {
//Stored F2 Offset
mxf_write_local_tag ( pb , 4 , 0x3216 ) ;
avio_wb32 ( pb , 0 ) ;
//Image Start Offset
mxf_write_local_tag ( pb , 4 , 0x3213 ) ;
avio_wb32 ( pb , 0 ) ;
//Image End Offset
mxf_write_local_tag ( pb , 4 , 0x3214 ) ;
avio_wb32 ( pb , 0 ) ;
}
2018-03-18 00:06:13 +02:00
//Sampled width
mxf_write_local_tag ( pb , 4 , 0x3205 ) ;
2019-08-26 22:15:32 +02:00
avio_wb32 ( pb , stored_width ) ;
2018-03-18 00:06:13 +02:00
//Samples height
mxf_write_local_tag ( pb , 4 , 0x3204 ) ;
avio_wb32 ( pb , st - > codecpar - > height > > sc - > interlaced ) ;
//Sampled X Offset
mxf_write_local_tag ( pb , 4 , 0x3206 ) ;
avio_wb32 ( pb , 0 ) ;
//Sampled Y Offset
mxf_write_local_tag ( pb , 4 , 0x3207 ) ;
avio_wb32 ( pb , 0 ) ;
2009-02-02 05:35:09 +02:00
mxf_write_local_tag ( pb , 4 , 0x3209 ) ;
2019-08-26 22:15:32 +02:00
avio_wb32 ( pb , stored_width ) ;
2009-02-02 05:35:09 +02:00
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( st - > codecpar - > height = = 608 ) // PAL + VBI
2009-02-13 09:13:36 +02:00
display_height = 576 ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
else if ( st - > codecpar - > height = = 512 ) // NTSC + VBI
2009-02-13 09:13:36 +02:00
display_height = 486 ;
else
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
display_height = st - > codecpar - > height ;
2009-02-13 09:13:36 +02:00
2009-02-02 05:35:09 +02:00
mxf_write_local_tag ( pb , 4 , 0x3208 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , display_height > > sc - > interlaced ) ;
2009-02-02 05:35:09 +02:00
2018-03-18 00:06:13 +02:00
// display X offset
mxf_write_local_tag ( pb , 4 , 0x320A ) ;
avio_wb32 ( pb , 0 ) ;
// display Y offset
2015-03-30 12:11:17 +02:00
mxf_write_local_tag ( pb , 4 , 0x320B ) ;
2016-04-10 21:58:15 +02:00
avio_wb32 ( pb , ( st - > codecpar - > height - display_height ) > > sc - > interlaced ) ;
2015-03-30 12:11:17 +02:00
2018-03-18 00:06:13 +02:00
if ( sc - > interlaced ) {
//Display F2 Offset
mxf_write_local_tag ( pb , 4 , 0x3217 ) ;
avio_wb32 ( pb , - ( ( st - > codecpar - > height - display_height ) & 1 ) ) ;
}
2009-02-10 08:14:39 +02:00
// component depth
mxf_write_local_tag ( pb , 4 , 0x3301 ) ;
2012-05-29 01:45:41 +03:00
avio_wb32 ( pb , sc - > component_depth ) ;
2009-02-10 08:14:39 +02: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 08:14:39 +02:00
2018-03-21 20:32:32 +02:00
// vertical subsampling
2018-03-21 18:35:22 +02:00
mxf_write_local_tag ( pb , 4 , 0x3308 ) ;
avio_wb32 ( pb , sc - > v_chroma_sub_sample ) ;
2018-03-21 20:32:32 +02:00
2015-05-19 01:11:09 +02:00
// color siting
mxf_write_local_tag ( pb , 1 , 0x3303 ) ;
avio_w8 ( pb , sc - > color_siting ) ;
2018-04-05 23:30:37 +02:00
// Padding Bits
mxf_write_local_tag ( pb , 2 , 0x3307 ) ;
avio_wb16 ( pb , 0 ) ;
2018-04-05 22:53:22 +02:00
if ( st - > codecpar - > color_range ! = AVCOL_RANGE_UNSPECIFIED ) {
int black = 0 ,
white = ( 1 < < sc - > component_depth ) - 1 ,
color = ( 1 < < sc - > component_depth ) - 1 ;
if ( st - > codecpar - > color_range = = AVCOL_RANGE_MPEG ) {
black = 1 < < ( sc - > component_depth - 4 ) ;
white = 235 < < ( sc - > component_depth - 8 ) ;
color = ( 14 < < ( sc - > component_depth - 4 ) ) + 1 ;
}
mxf_write_local_tag ( pb , 4 , 0x3304 ) ;
avio_wb32 ( pb , black ) ;
mxf_write_local_tag ( pb , 4 , 0x3305 ) ;
avio_wb32 ( pb , white ) ;
mxf_write_local_tag ( pb , 4 , 0x3306 ) ;
avio_wb32 ( pb , color ) ;
}
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 11:08:01 +02:00
// frame layout
mxf_write_local_tag ( pb , 1 , 0x320C ) ;
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , sc - > interlaced ) ;
2009-01-31 11:08:01 +02:00
2009-01-31 11:23:50 +02:00
// video line map
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
switch ( st - > codecpar - > height ) {
2016-04-10 21:58:15 +02:00
case 576 : f1 = 23 ; f2 = st - > codecpar - > codec_id = = AV_CODEC_ID_DVVIDEO ? 335 : 336 ; break ;
2009-01-31 11:23:50 +02:00
case 608 : f1 = 7 ; f2 = 320 ; break ;
2016-04-10 21:58:15 +02:00
case 480 : f1 = 20 ; f2 = st - > codecpar - > codec_id = = AV_CODEC_ID_DVVIDEO ? 285 : 283 ; break ;
2009-01-31 11:23:50 +02: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 ;
}
2018-10-16 22:19:45 +02:00
if ( ! sc - > interlaced & & f2 ) {
2009-01-31 11:23:50 +02:00
f2 = 0 ;
f1 * = 2 ;
}
2016-01-29 18:45:05 +02:00
mxf_write_local_tag ( pb , 16 , 0x320D ) ;
avio_wb32 ( pb , 2 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 4 ) ;
avio_wb32 ( pb , f1 ) ;
2016-01-29 18:45:05 +02:00
avio_wb32 ( pb , f2 ) ;
2009-01-31 11:23:50 +02:00
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 8 , 0x320E ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , sc - > aspect_ratio . num ) ;
avio_wb32 ( pb , sc - > aspect_ratio . den ) ;
2009-01-31 08:49:42 +02:00
2018-03-21 22:34:20 +02:00
//Transfer characteristic
if ( transfer_ul [ 0 ] ) {
mxf_write_local_tag ( pb , 16 , 0x3210 ) ;
avio_write ( pb , transfer_ul , 16 ) ;
} ;
2009-01-31 08:49:42 +02:00
mxf_write_local_tag ( pb , 16 , 0x3201 ) ;
2011-02-21 20:28:17 +02:00
avio_write ( pb , * sc - > codec_ul , 16 ) ;
2012-05-27 15:21:41 +03:00
if ( sc - > interlaced & & sc - > field_dominance ) {
mxf_write_local_tag ( pb , 1 , 0x3212 ) ;
avio_w8 ( pb , sc - > field_dominance ) ;
}
2018-10-18 22:37:05 +02:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_H264 & & ! sc - > avc_intra ) {
// write avc sub descriptor ref
mxf_write_local_tag ( pb , 8 + 16 , 0x8100 ) ;
mxf_write_refs_count ( pb , 1 ) ;
mxf_write_uuid ( pb , AVCSubDescriptor , 0 ) ;
}
2018-03-21 17:37:59 +02:00
return pos ;
}
static void mxf_update_klv_size ( AVIOContext * pb , int64_t pos )
{
int64_t cur_pos = avio_tell ( pb ) ;
int size = cur_pos - pos ;
avio_seek ( pb , pos - 4 , SEEK_SET ) ;
klv_encode_ber4_length ( pb , size ) ;
avio_seek ( pb , cur_pos , SEEK_SET ) ;
2008-08-20 01:01:57 +03:00
}
2018-10-18 22:37:05 +02:00
static void mxf_write_avc_subdesc ( AVFormatContext * s , AVStream * st )
{
AVIOContext * pb = s - > pb ;
int64_t pos ;
avio_write ( pb , mxf_avc_subdescriptor_key , 16 ) ;
klv_encode_ber4_length ( pb , 0 ) ;
pos = avio_tell ( pb ) ;
mxf_write_local_tag ( pb , 16 , 0x3C0A ) ;
mxf_write_uuid ( pb , AVCSubDescriptor , 0 ) ;
mxf_write_local_tag ( pb , 1 , 0x8200 ) ;
avio_w8 ( pb , 0xFF ) ; // AVC Decoding Delay, unknown
mxf_write_local_tag ( pb , 1 , 0x8201 ) ;
avio_w8 ( pb , st - > codecpar - > profile ) ; // AVC Profile
mxf_write_local_tag ( pb , 1 , 0x8202 ) ;
avio_w8 ( pb , st - > codecpar - > level ) ; // AVC Level
mxf_update_klv_size ( s - > pb , pos ) ;
}
2009-02-13 09:28:20 +02:00
static void mxf_write_cdci_desc ( AVFormatContext * s , AVStream * st )
{
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_cdci_common ( s , st , mxf_cdci_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
2018-10-18 22:37:05 +02:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_H264 ) {
mxf_write_avc_subdesc ( s , st ) ;
}
}
static void mxf_write_h264_desc ( AVFormatContext * s , AVStream * st )
{
MXFStreamContext * sc = st - > priv_data ;
if ( sc - > avc_intra ) {
mxf_write_mpegvideo_desc ( s , st ) ;
} else {
int64_t pos = mxf_write_cdci_common ( s , st , mxf_cdci_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
mxf_write_avc_subdesc ( s , st ) ;
}
2009-02-13 09:28:20 +02:00
}
2016-11-19 21:09:24 +02:00
static void mxf_write_s436m_anc_desc ( AVFormatContext * s , AVStream * st )
{
int64_t pos = mxf_write_generic_desc ( s , st , mxf_s436m_anc_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
}
2009-02-13 09:11:21 +02:00
static void mxf_write_mpegvideo_desc ( AVFormatContext * s , AVStream * st )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2013-09-09 11:02:12 +03:00
MXFStreamContext * sc = st - > priv_data ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
int profile_and_level = ( st - > codecpar - > profile < < 4 ) | st - > codecpar - > level ;
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_cdci_common ( s , st , mxf_mpegvideo_descriptor_key ) ;
2009-02-13 09:11:21 +02:00
2016-04-10 21:58:15 +02:00
if ( st - > codecpar - > codec_id ! = AV_CODEC_ID_H264 ) {
2014-10-29 22:26:25 +02:00
// bit rate
mxf_write_local_tag ( pb , 4 , 0x8000 ) ;
avio_wb32 ( pb , sc - > video_bit_rate ) ;
2009-07-04 10:49:12 +03:00
2014-10-29 22:26:25 +02:00
// profile and level
mxf_write_local_tag ( pb , 1 , 0x8007 ) ;
2016-04-10 21:58:15 +02:00
if ( ! st - > codecpar - > profile )
2014-10-29 22:26:25 +02:00
profile_and_level | = 0x80 ; // escape bit
avio_w8 ( pb , profile_and_level ) ;
2018-03-21 18:35:22 +02:00
// low delay
mxf_write_local_tag ( pb , 1 , 0x8003 ) ;
avio_w8 ( pb , sc - > low_delay ) ;
// closed gop
mxf_write_local_tag ( pb , 1 , 0x8004 ) ;
avio_w8 ( pb , sc - > seq_closed_gop ) ;
// max gop
mxf_write_local_tag ( pb , 2 , 0x8006 ) ;
avio_wb16 ( pb , sc - > max_gop ) ;
// b picture count
mxf_write_local_tag ( pb , 2 , 0x8008 ) ;
avio_wb16 ( pb , sc - > b_picture_count ) ;
2014-10-29 00:38:22 +02:00
}
2018-03-21 17:37:59 +02:00
mxf_update_klv_size ( pb , pos ) ;
2009-02-13 09:11:21 +02:00
}
2018-03-21 17:37:59 +02:00
static int64_t mxf_write_generic_sound_common ( AVFormatContext * s , AVStream * st , const UID key )
2008-08-20 01:01:57 +03:00
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
MXFContext * mxf = s - > priv_data ;
int show_warnings = ! mxf - > footer_partition_offset ;
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_generic_desc ( s , st , key ) ;
2015-04-12 02:18:13 +02:00
2018-03-21 17:37:59 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer ) {
2015-04-12 02:18:13 +02:00
mxf_write_local_tag ( pb , 8 , 0x3002 ) ;
avio_wb64 ( pb , mxf - > body_offset / mxf - > edit_unit_byte_count ) ;
}
2009-01-31 08:54:30 +02:00
2009-01-31 08:59:55 +02:00
// audio locked
2009-01-31 08:54:30 +02:00
mxf_write_local_tag ( pb , 1 , 0x3D02 ) ;
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 1 ) ;
2008-08-20 01:01:57 +03:00
// write audio sampling rate
mxf_write_local_tag ( pb , 8 , 0x3D03 ) ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avio_wb32 ( pb , st - > codecpar - > sample_rate ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 1 ) ;
2008-08-20 01:01:57 +03:00
2018-04-06 21:44:23 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer ) {
mxf_write_local_tag ( pb , 1 , 0x3D04 ) ;
avio_w8 ( pb , 0 ) ;
}
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 4 , 0x3D07 ) ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
if ( mxf - > channel_count = = - 1 ) {
2016-04-10 21:58:15 +02:00
if ( show_warnings & & ( s - > oformat = = & ff_mxf_d10_muxer ) & & ( st - > codecpar - > channels ! = 4 ) & & ( st - > codecpar - > channels ! = 8 ) )
2014-06-26 19:10:45 +03: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 " ) ;
2016-04-10 21:58:15 +02:00
avio_wb32 ( pb , st - > codecpar - > channels ) ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
} else if ( s - > oformat = = & ff_mxf_d10_muxer ) {
2016-04-10 21:58:15 +02:00
if ( show_warnings & & ( mxf - > channel_count < st - > codecpar - > channels ) )
2014-06-26 19:10:45 +03:00
av_log ( s , AV_LOG_WARNING , " d10_channelcount < actual number of audio channels : some channels will be discarded \n " ) ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
if ( show_warnings & & ( mxf - > channel_count ! = 4 ) & & ( mxf - > channel_count ! = 8 ) )
2014-06-26 19:10:45 +03: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 " ) ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
avio_wb32 ( pb , mxf - > channel_count ) ;
} else {
2016-04-10 21:58:15 +02:00
avio_wb32 ( pb , st - > codecpar - > channels ) ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
}
2008-08-20 01:01:57 +03:00
mxf_write_local_tag ( pb , 4 , 0x3D01 ) ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avio_wb32 ( pb , av_get_bits_per_sample ( st - > codecpar - > codec_id ) ) ;
2018-03-21 17:37:59 +02:00
return pos ;
2008-08-20 01:01:57 +03:00
}
2018-03-21 17:37:59 +02:00
static int64_t mxf_write_wav_common ( AVFormatContext * s , AVStream * st , const UID key )
2009-01-31 08:59:55 +02:00
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_generic_sound_common ( s , st , key ) ;
2009-02-02 06:36:54 +02:00
mxf_write_local_tag ( pb , 2 , 0x3D0A ) ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avio_wb16 ( pb , st - > codecpar - > block_align ) ;
2009-02-02 06:36:54 +02:00
// avg bytes per sec
mxf_write_local_tag ( pb , 4 , 0x3D09 ) ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avio_wb32 ( pb , st - > codecpar - > block_align * st - > codecpar - > sample_rate ) ;
2018-03-21 17:37:59 +02:00
return pos ;
2009-01-31 08:59:55 +02:00
}
2009-02-02 06:40:57 +02:00
static void mxf_write_wav_desc ( AVFormatContext * s , AVStream * st )
2009-01-31 09:02:20 +02:00
{
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_wav_common ( s , st , mxf_wav_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
2009-02-02 06:40:57 +02:00
}
2009-02-02 06:36:54 +02:00
2009-02-02 06:40:57 +02:00
static void mxf_write_aes3_desc ( AVFormatContext * s , AVStream * st )
{
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_wav_common ( s , st , mxf_aes3_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
2009-01-31 09:02:20 +02:00
}
2009-02-13 09:28:20 +02:00
static void mxf_write_generic_sound_desc ( AVFormatContext * s , AVStream * st )
{
2018-03-21 17:37:59 +02:00
int64_t pos = mxf_write_generic_sound_common ( s , st , mxf_generic_sound_descriptor_key ) ;
mxf_update_klv_size ( s - > pb , pos ) ;
2009-02-13 09:28:20 +02:00
}
2015-03-15 02:59:50 +02: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 ;
}
2017-11-27 07:42:16 +02:00
static void mxf_write_package ( AVFormatContext * s , MXFPackage * package )
2008-08-31 07:24:00 +03:00
{
2009-02-05 22:15:18 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-02-18 03:35:36 +02:00
int i , track_count = s - > nb_streams + 1 ;
2017-11-27 07:42:16 +02:00
int name_size = mxf_utf16_local_tag_length ( package - > name ) ;
2015-03-15 02:59:50 +02:00
int user_comment_count = 0 ;
2008-08-31 07:24:00 +03:00
2017-11-27 07:42:16 +02:00
if ( package - > type = = MaterialPackage ) {
2015-11-09 15:24:26 +02:00
if ( mxf - > store_user_comments )
user_comment_count = mxf_write_user_comments ( s , s - > metadata ) ;
2008-08-31 07:24:00 +03:00
mxf_write_metadata_key ( pb , 0x013600 ) ;
PRINT_KEY ( s , " Material Package key " , pb - > buf_ptr - 16 ) ;
2015-12-09 19:13:25 +02:00
klv_encode_ber_length ( pb , 92 + name_size + ( 16 * track_count ) + ( 16 * user_comment_count ) + 12LL * mxf - > store_user_comments ) ;
2008-08-31 07:24:00 +03:00
} else {
mxf_write_metadata_key ( pb , 0x013700 ) ;
PRINT_KEY ( s , " Source Package key " , pb - > buf_ptr - 16 ) ;
2015-12-09 19:13:25 +02:00
klv_encode_ber_length ( pb , 112 + name_size + ( 16 * track_count ) + 12LL * mxf - > store_user_comments ) ; // 20 bytes length for descriptor reference
2008-08-31 07:24:00 +03:00
}
// write uid
mxf_write_local_tag ( pb , 16 , 0x3C0A ) ;
2017-11-27 07:42:16 +02:00
mxf_write_uuid ( pb , package - > type , package - > instance ) ;
av_log ( s , AV_LOG_DEBUG , " package type:%d \n " , package - > type ) ;
2008-08-31 07:24:00 +03:00
PRINT_KEY ( s , " package uid " , pb - > buf_ptr - 16 ) ;
// write package umid
mxf_write_local_tag ( pb , 32 , 0x4401 ) ;
2017-12-05 06:46:21 +02:00
mxf_write_umid ( s , package - > instance ) ;
2008-08-31 07:24:00 +03:00
PRINT_KEY ( s , " package umid second part " , pb - > buf_ptr - 16 ) ;
2015-03-05 20:59:11 +02:00
// package name
if ( name_size )
2017-11-27 07:42:16 +02:00
mxf_write_local_tag_utf16 ( pb , 0x4402 , package - > name ) ;
2015-03-05 20:59:11 +02:00
2009-02-05 22:15:18 +02:00
// package creation date
2008-08-31 07:24:00 +03:00
mxf_write_local_tag ( pb , 8 , 0x4405 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > timestamp ) ;
2008-08-31 07:24:00 +03:00
2009-02-05 22:15:18 +02:00
// package modified date
2008-08-31 07:24:00 +03:00
mxf_write_local_tag ( pb , 8 , 0x4404 ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > timestamp ) ;
2008-08-31 07:24:00 +03:00
// write track refs
2009-02-11 09:18:00 +02:00
mxf_write_local_tag ( pb , track_count * 16 + 8 , 0x4403 ) ;
mxf_write_refs_count ( pb , track_count ) ;
2017-12-05 06:46:21 +02:00
// these are the uuids of the tracks the will be written in mxf_write_track
for ( i = 0 ; i < track_count ; i + + )
mxf_write_uuid ( pb , Track , mxf - > track_instance_count + i ) ;
2008-08-31 07:24:00 +03:00
2015-03-15 02:59:50 +02:00
// write user comment refs
2015-11-09 15:24:26 +02:00
if ( mxf - > store_user_comments ) {
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 ) ;
}
2015-03-15 02:59:50 +02:00
2008-08-31 07:24:00 +03:00
// write multiple descriptor reference
2017-12-05 06:46:22 +02:00
if ( package - > type = = SourcePackage & & package - > instance = = 1 ) {
2008-08-31 07:24:00 +03:00
mxf_write_local_tag ( pb , 16 , 0x4701 ) ;
2008-08-31 07:35:09 +03:00
if ( s - > nb_streams > 1 ) {
mxf_write_uuid ( pb , MultipleDescriptor , 0 ) ;
mxf_write_multi_descriptor ( s ) ;
} else
mxf_write_uuid ( pb , SubDescriptor , 0 ) ;
2017-12-05 06:46:22 +02:00
} else if ( package - > type = = SourcePackage & & package - > instance = = 2 ) {
mxf_write_local_tag ( pb , 16 , 0x4701 ) ;
mxf_write_uuid ( pb , TapeDescriptor , 0 ) ;
mxf_write_tape_descriptor ( s ) ;
2008-08-31 07:26:12 +03:00
}
2008-08-20 01:01:57 +03:00
2017-12-05 06:46:21 +02:00
/*
* for every 1 track in a package there is 1 sequence and 1 component .
* all 3 of these elements share the same instance number for generating
* there instance uuids . mxf - > track_instance_count stores this value .
* mxf - > track_instance_count is incremented after a group of all 3 of
* these elements are written .
*/
2009-02-18 03:35:36 +02:00
// write timecode track
2017-11-27 07:42:16 +02:00
mxf_write_track ( s , mxf - > timecode_track , package ) ;
mxf_write_sequence ( s , mxf - > timecode_track , package ) ;
mxf_write_timecode_component ( s , mxf - > timecode_track , package ) ;
2017-12-05 06:46:21 +02:00
mxf - > track_instance_count + + ;
2009-02-18 03:35:36 +02:00
2008-08-31 04:44:45 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2008-08-31 04:48:02 +03:00
AVStream * st = s - > streams [ i ] ;
2017-11-27 07:42:16 +02:00
mxf_write_track ( s , st , package ) ;
mxf_write_sequence ( s , st , package ) ;
mxf_write_structural_component ( s , st , package ) ;
2017-12-05 06:46:21 +02:00
mxf - > track_instance_count + + ;
2008-08-20 01:01:57 +03:00
2017-12-05 06:46:22 +02:00
if ( package - > type = = SourcePackage & & package - > instance = = 1 ) {
2008-08-31 07:07:41 +03:00
MXFStreamContext * sc = st - > priv_data ;
2008-08-31 07:13:44 +03:00
mxf_essence_container_uls [ sc - > index ] . write_desc ( s , st ) ;
2008-08-20 01:01:57 +03:00
}
}
}
2009-01-23 22:57:12 +02:00
static int mxf_write_essence_container_data ( AVFormatContext * s )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-01-23 22:57:12 +02:00
mxf_write_metadata_key ( pb , 0x012300 ) ;
2009-02-02 12:03:38 +02:00
klv_encode_ber_length ( pb , 72 ) ;
2009-01-23 22:57:12 +02: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 08:15:00 +02:00
mxf_write_umid ( s , 1 ) ;
2009-01-23 22:57:12 +02:00
mxf_write_local_tag ( pb , 4 , 0x3F07 ) ; // BodySID
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 1 ) ;
2009-01-23 22:57:12 +02:00
2009-02-02 12:03:38 +02:00
mxf_write_local_tag ( pb , 4 , 0x3F06 ) ; // IndexSID
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 2 ) ;
2009-02-02 12:03:38 +02:00
2009-01-23 22:57:12 +02:00
return 0 ;
}
2008-08-19 15:36:17 +03:00
static int mxf_write_header_metadata_sets ( AVFormatContext * s )
{
2017-12-05 06:46:21 +02:00
MXFContext * mxf = s - > priv_data ;
2015-03-05 20:59:11 +02:00
AVDictionaryEntry * entry = NULL ;
AVStream * st = NULL ;
int i ;
2017-12-05 06:46:22 +02:00
MXFPackage packages [ 3 ] = { { 0 } } ;
2017-11-27 07:42:16 +02:00
int package_count = 2 ;
packages [ 0 ] . type = MaterialPackage ;
packages [ 1 ] . type = SourcePackage ;
2017-12-05 06:46:21 +02:00
packages [ 1 ] . instance = 1 ;
2017-12-05 06:46:22 +02:00
packages [ 0 ] . ref = & packages [ 1 ] ;
2017-11-27 07:42:16 +02:00
2015-03-05 20:59:11 +02:00
if ( entry = av_dict_get ( s - > metadata , " material_package_name " , NULL , 0 ) )
2017-11-27 07:42:16 +02:00
packages [ 0 ] . name = entry - > value ;
2015-03-05 20:59:11 +02:00
if ( entry = av_dict_get ( s - > metadata , " file_package_name " , NULL , 0 ) ) {
2017-11-27 07:42:16 +02:00
packages [ 1 ] . name = entry - > value ;
2015-03-05 20:59:11 +02:00
} 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 ) ) {
2017-11-27 07:42:16 +02:00
packages [ 1 ] . name = entry - > value ;
2015-03-05 20:59:11 +02:00
break ;
}
}
}
2017-12-05 06:46:22 +02:00
entry = av_dict_get ( s - > metadata , " reel_name " , NULL , 0 ) ;
if ( entry ) {
packages [ 2 ] . name = entry - > value ;
packages [ 2 ] . type = SourcePackage ;
packages [ 2 ] . instance = 2 ;
packages [ 1 ] . ref = & packages [ 2 ] ;
package_count = 3 ;
}
2008-08-31 01:58:49 +03:00
mxf_write_preface ( s ) ;
2008-08-22 07:12:52 +03:00
mxf_write_identification ( s ) ;
2017-11-27 07:42:16 +02:00
mxf_write_content_storage ( s , packages , package_count ) ;
2017-12-05 06:46:21 +02:00
mxf - > track_instance_count = 0 ;
2017-11-27 07:42:16 +02:00
for ( i = 0 ; i < package_count ; i + + )
mxf_write_package ( s , & packages [ i ] ) ;
2009-01-23 22:57:12 +02:00
mxf_write_essence_container_data ( s ) ;
2008-08-19 15:36:17 +03:00
return 0 ;
}
2009-02-08 05:29:49 +02:00
static unsigned klv_fill_size ( uint64_t size )
2009-02-07 04:13:23 +02:00
{
2009-02-08 05:29:49 +02:00
unsigned pad = KAG_SIZE - ( size & ( KAG_SIZE - 1 ) ) ;
2009-02-13 07:33:11 +02:00
if ( pad < 20 ) // smallest fill item possible
2009-02-07 04:13:23 +02:00
return pad + KAG_SIZE ;
else
return pad & ( KAG_SIZE - 1 ) ;
}
2009-02-08 11:42:37 +02:00
static void mxf_write_index_table_segment ( AVFormatContext * s )
2009-02-02 12:03:38 +02:00
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2010-07-02 11:35:47 +03:00
int i , j , temporal_reordering = 0 ;
2009-02-11 03:06:12 +02:00
int key_index = mxf - > last_key_index ;
2018-03-21 18:35:22 +02:00
int prev_non_b_picture = 0 ;
2016-11-19 21:09:24 +02:00
int audio_frame_size = 0 ;
2018-03-21 21:53:56 +02:00
int64_t pos ;
2009-02-02 12:03:38 +02:00
av_log ( s , AV_LOG_DEBUG , " edit units count %d \n " , mxf - > edit_units_count ) ;
2009-02-13 09:28:20 +02:00
if ( ! mxf - > edit_units_count & & ! mxf - > edit_unit_byte_count )
2009-02-10 11:02:29 +02:00
return ;
2011-02-21 20:28:17 +02:00
avio_write ( pb , index_table_segment_key , 16 ) ;
2009-02-13 09:28:20 +02:00
2018-03-21 21:53:56 +02:00
klv_encode_ber4_length ( pb , 0 ) ;
pos = avio_tell ( pb ) ;
2009-02-02 12:03:38 +02: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 20:28:17 +02:00
avio_wb32 ( pb , mxf - > time_base . den ) ;
avio_wb32 ( pb , mxf - > time_base . num ) ;
2009-02-02 12:03:38 +02:00
// index start position
mxf_write_local_tag ( pb , 8 , 0x3F0C ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > last_indexed_edit_unit ) ;
2009-02-02 12:03:38 +02:00
// index duration
mxf_write_local_tag ( pb , 8 , 0x3F0D ) ;
2009-07-04 10:56:58 +03:00
if ( mxf - > edit_unit_byte_count )
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ; // index table covers whole container
2009-07-04 10:56:58 +03:00
else
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > edit_units_count ) ;
2009-02-02 12:03:38 +02:00
// edit unit byte count
mxf_write_local_tag ( pb , 4 , 0x3F05 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , mxf - > edit_unit_byte_count ) ;
2009-02-02 12:03:38 +02:00
// index sid
mxf_write_local_tag ( pb , 4 , 0x3F06 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 2 ) ;
2009-02-02 12:03:38 +02:00
// body sid
mxf_write_local_tag ( pb , 4 , 0x3F07 ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 1 ) ;
2009-02-02 12:03:38 +02:00
2018-03-21 21:53:56 +02:00
// real slice count - 1
mxf_write_local_tag ( pb , 1 , 0x3F08 ) ;
avio_w8 ( pb , ! mxf - > edit_unit_byte_count ) ; // only one slice for CBR
// delta entry array
mxf_write_local_tag ( pb , 8 + ( s - > nb_streams + 1 ) * 6 , 0x3F09 ) ;
avio_wb32 ( pb , s - > nb_streams + 1 ) ; // num of entries
avio_wb32 ( pb , 6 ) ; // size of one entry
// write system item delta entry
avio_w8 ( pb , 0 ) ;
avio_w8 ( pb , 0 ) ; // slice entry
avio_wb32 ( pb , 0 ) ; // element delta
// write each stream delta entry
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
MXFStreamContext * sc = st - > priv_data ;
avio_w8 ( pb , sc - > temporal_reordering ) ;
if ( sc - > temporal_reordering )
temporal_reordering = 1 ;
if ( mxf - > edit_unit_byte_count ) {
avio_w8 ( pb , 0 ) ; // slice number
avio_wb32 ( pb , sc - > slice_offset ) ;
} else if ( i = = 0 ) { // video track
avio_w8 ( pb , 0 ) ; // slice number
avio_wb32 ( pb , KAG_SIZE ) ; // system item size including klv fill
2016-11-19 21:09:24 +02:00
} else { // audio or data track
if ( ! audio_frame_size ) {
2020-02-28 01:26:20 +02:00
audio_frame_size = sc - > frame_size ;
2016-11-19 21:09:24 +02:00
audio_frame_size + = klv_fill_size ( audio_frame_size ) ;
}
2018-03-21 21:53:56 +02:00
avio_w8 ( pb , 1 ) ;
avio_wb32 ( pb , ( i - 1 ) * audio_frame_size ) ; // element delta
2009-02-08 05:29:49 +02:00
}
2018-03-21 21:53:56 +02:00
}
2009-02-02 12:03:38 +02:00
2018-03-21 21:53:56 +02:00
if ( ! mxf - > edit_unit_byte_count ) {
2018-03-21 18:35:22 +02:00
MXFStreamContext * sc = s - > streams [ 0 ] - > priv_data ;
2018-03-21 21:53:56 +02:00
mxf_write_local_tag ( pb , 8 + mxf - > edit_units_count * 15 , 0x3F0A ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , mxf - > edit_units_count ) ; // num of entries
2018-03-21 21:53:56 +02:00
avio_wb32 ( pb , 15 ) ; // size of one entry
2010-07-02 11:35:47 +03:00
2009-02-13 09:34:01 +02:00
for ( i = 0 ; i < mxf - > edit_units_count ; i + + ) {
2009-06-30 10:41:40 +03:00
int temporal_offset = 0 ;
2010-07-02 11:35:47 +03:00
2016-04-27 19:45:23 +02:00
if ( ! ( mxf - > index_entries [ i ] . flags & 0x33 ) ) { // I-frame
2018-03-21 18:35:22 +02:00
sc - > max_gop = FFMAX ( sc - > max_gop , i - mxf - > last_key_index ) ;
2010-07-02 11:35:47 +03:00
mxf - > last_key_index = key_index ;
key_index = i ;
}
2009-02-13 09:34:01 +02:00
if ( temporal_reordering ) {
2010-07-02 11:35:47 +03: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-02 12:41:43 +02:00
}
2010-07-02 11:35:47 +03: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-02 12:03:38 +02:00
}
2009-06-30 10:41:40 +03:00
}
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , temporal_offset ) ;
2009-06-30 10:41:40 +03:00
if ( ( mxf - > index_entries [ i ] . flags & 0x30 ) = = 0x30 ) { // back and forward prediction
2018-03-21 18:35:22 +02:00
sc - > b_picture_count = FFMAX ( sc - > b_picture_count , i - prev_non_b_picture ) ;
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , mxf - > last_key_index - i ) ;
2009-02-13 09:34:01 +02:00
} else {
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , key_index - i ) ; // key frame offset
2009-02-13 09:34:01 +02:00
if ( ( mxf - > index_entries [ i ] . flags & 0x20 ) = = 0x20 ) // only forward
mxf - > last_key_index = key_index ;
2018-03-21 18:35:22 +02:00
prev_non_b_picture = i ;
2009-02-13 09:34:01 +02:00
}
2010-07-02 11:35:47 +03:00
2016-04-27 19:45:23 +02:00
if ( ! ( mxf - > index_entries [ i ] . flags & 0x33 ) & & // I-frame
2010-07-02 11:35:47 +03:00
mxf - > index_entries [ i ] . flags & 0x40 & & ! temporal_offset )
mxf - > index_entries [ i ] . flags | = 0x80 ; // random access
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , mxf - > index_entries [ i ] . flags ) ;
2009-02-13 09:34:01 +02:00
// stream offset
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > index_entries [ i ] . offset ) ;
2009-02-13 09:34:01 +02:00
if ( s - > nb_streams > 1 )
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , mxf - > index_entries [ i ] . slice_offset ) ;
2018-03-21 21:53:56 +02:00
else
avio_wb32 ( pb , 0 ) ;
2009-02-05 09:47:39 +02:00
}
2009-02-10 11:02:29 +02:00
2009-02-13 09:34:01 +02: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 09:28:20 +02:00
}
2018-03-21 21:53:56 +02:00
mxf_update_klv_size ( pb , pos ) ;
2009-02-02 12:03:38 +02:00
}
2009-02-10 07:35:28 +02:00
static void mxf_write_klv_fill ( AVFormatContext * s )
{
2011-03-03 21:11:45 +02:00
unsigned pad = klv_fill_size ( avio_tell ( s - > pb ) ) ;
2009-02-10 07:35:28 +02:00
if ( pad ) {
2011-02-21 20:28:17 +02:00
avio_write ( s - > pb , klv_fill_key , 16 ) ;
2009-02-13 07:33:11 +02:00
pad - = 16 + 4 ;
klv_encode_ber4_length ( s - > pb , pad ) ;
2013-07-15 20:39:55 +03:00
ffio_fill ( s - > pb , 0 , pad ) ;
2012-07-13 00:16:24 +03:00
av_assert1 ( ! ( avio_tell ( s - > pb ) & ( KAG_SIZE - 1 ) ) ) ;
2009-02-10 07:35:28 +02:00
}
}
2013-08-02 20:21:24 +03:00
static int mxf_write_partition ( AVFormatContext * s , int bodysid ,
2009-02-10 10:46:04 +02:00
int indexsid ,
2009-02-02 12:03:38 +02:00
const uint8_t * key , int write_metadata )
2008-08-24 08:55:46 +03:00
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-31 06:42:05 +03:00
int64_t header_byte_count_offset ;
2009-02-10 10:46:04 +02:00
unsigned index_byte_count = 0 ;
2011-03-03 21:11:45 +02:00
uint64_t partition_offset = avio_tell ( pb ) ;
2013-08-02 20:21:24 +03:00
int err ;
2009-02-10 10:46:04 +02:00
2009-02-13 09:28:20 +02:00
if ( ! mxf - > edit_unit_byte_count & & mxf - > edit_units_count )
index_byte_count = 85 + 12 + ( s - > nb_streams + 1 ) * 6 +
2018-03-21 21:53:56 +02:00
12 + mxf - > edit_units_count * 15 ;
2009-02-13 09:28:20 +02:00
else if ( mxf - > edit_unit_byte_count & & indexsid )
2009-02-18 09:14:23 +02:00
index_byte_count = 80 ;
2009-02-13 09:28:20 +02:00
if ( index_byte_count ) {
2019-07-18 19:35:00 +02:00
index_byte_count + = 16 + 4 ; // add encoded ber4 length
2009-02-10 10:46:04 +02:00
index_byte_count + = klv_fill_size ( index_byte_count ) ;
2009-02-10 11:02:29 +02:00
}
2015-01-29 05:44:21 +02:00
if ( key & & ! memcmp ( key , body_partition_key , 16 ) ) {
2013-08-02 20:21:24 +03: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-11 01:25:23 +02:00
mxf - > body_partition_offset [ mxf - > body_partitions_count + + ] = partition_offset ;
2009-02-10 10:46:04 +02:00
}
2008-08-31 01:58:49 +03:00
2008-08-24 08:55:46 +03:00
// write klv
2015-01-29 05:44:21 +02:00
if ( key )
avio_write ( pb , key , 16 ) ;
else
avio_write ( pb , body_partition_key , 16 ) ;
2018-03-21 21:59:11 +02:00
klv_encode_ber4_length ( pb , 88 + 16LL * DESCRIPTOR_COUNT ( mxf - > essence_container_count ) ) ;
2008-08-24 08:55:46 +03:00
// write partition value
2011-02-21 20:28:17 +02:00
avio_wb16 ( pb , 1 ) ; // majorVersion
2018-05-08 21:24:15 +02:00
avio_wb16 ( pb , 3 ) ; // minorVersion
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , KAG_SIZE ) ; // KAGSize
2008-08-24 08:55:46 +03:00
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , partition_offset ) ; // ThisPartition
2009-02-10 11:02:29 +02:00
2015-01-29 05:44:21 +02:00
if ( key & & ! memcmp ( key , body_partition_key , 16 ) & & mxf - > body_partitions_count > 1 )
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > body_partition_offset [ mxf - > body_partitions_count - 2 ] ) ; // PreviousPartition
2015-01-29 05:44:21 +02:00
else if ( key & & ! memcmp ( key , footer_partition_key , 16 ) & & mxf - > body_partitions_count )
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > body_partition_offset [ mxf - > body_partitions_count - 1 ] ) ; // PreviousPartition
2009-02-10 11:02:29 +02:00
else
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > footer_partition_offset ) ; // footerPartition
2008-08-24 08:55:46 +03:00
// set offset
2011-03-03 21:11:45 +02:00
header_byte_count_offset = avio_tell ( pb ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ; // headerByteCount, update later
2008-08-24 08:55:46 +03:00
2009-02-02 12:03:38 +02:00
// indexTable
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , index_byte_count ) ; // indexByteCount
avio_wb32 ( pb , index_byte_count ? indexsid : 0 ) ; // indexSID
2009-02-10 11:02:29 +02:00
// BodyOffset
2015-01-29 05:44:21 +02:00
if ( bodysid & & mxf - > edit_units_count & & mxf - > body_partitions_count & & s - > oformat ! = & ff_mxf_opatom_muxer )
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , mxf - > body_offset ) ;
2015-01-29 05:44:21 +02:00
else
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , 0 ) ;
2008-08-24 08:55:46 +03:00
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , bodysid ) ; // bodySID
2009-02-10 06:53:41 +02:00
// operational pattern
2015-01-29 05:44:21 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer )
avio_write ( pb , opatom_ul , 16 ) ;
else
avio_write ( pb , op1a_ul , 16 ) ;
2008-08-24 08:55:46 +03:00
// essence container
2008-08-31 03:28:36 +03:00
mxf_write_essence_container_refs ( s ) ;
2008-08-31 06:36:25 +03:00
if ( write_metadata ) {
// mark the start of the headermetadata and calculate metadata size
2009-02-10 08:09:50 +02:00
int64_t pos , start ;
2009-02-07 04:13:23 +02:00
unsigned header_byte_count ;
2009-02-10 07:35:28 +02:00
mxf_write_klv_fill ( s ) ;
2011-03-03 21:11:45 +02:00
start = avio_tell ( s - > pb ) ;
2008-08-31 06:36:25 +03:00
mxf_write_primer_pack ( s ) ;
2018-04-30 02:26:37 +02:00
mxf_write_klv_fill ( s ) ;
2008-08-31 06:36:25 +03:00
mxf_write_header_metadata_sets ( s ) ;
2011-03-03 21:11:45 +02:00
pos = avio_tell ( s - > pb ) ;
2009-02-08 05:29:49 +02:00
header_byte_count = pos - start + klv_fill_size ( pos ) ;
2009-02-07 04:13:23 +02:00
2008-08-31 06:36:25 +03:00
// update header_byte_count
2011-02-28 15:57:54 +02:00
avio_seek ( pb , header_byte_count_offset , SEEK_SET ) ;
2011-02-21 20:28:17 +02:00
avio_wb64 ( pb , header_byte_count ) ;
2011-02-28 15:57:54 +02:00
avio_seek ( pb , pos , SEEK_SET ) ;
2008-08-31 06:36:25 +03:00
}
2015-01-29 05:44:21 +02:00
if ( key )
2019-12-27 14:53:00 +02:00
avio_write_marker ( pb , AV_NOPTS_VALUE , AVIO_DATA_MARKER_FLUSH_POINT ) ;
2013-08-02 20:21:24 +03:00
return 0 ;
2008-08-24 08:55:46 +03:00
}
2018-12-05 19:10:37 +02:00
static const struct {
int profile ;
UID codec_ul ;
} mxf_prores_codec_uls [ ] = {
{ FF_PROFILE_PRORES_PROXY , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x01 , 0x00 } } ,
{ FF_PROFILE_PRORES_LT , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x02 , 0x00 } } ,
{ FF_PROFILE_PRORES_STANDARD , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x03 , 0x00 } } ,
{ FF_PROFILE_PRORES_HQ , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x04 , 0x00 } } ,
{ FF_PROFILE_PRORES_4444 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x05 , 0x00 } } ,
{ FF_PROFILE_PRORES_XQ , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x03 , 0x06 , 0x06 , 0x00 } } ,
} ;
static int mxf_parse_prores_frame ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
MXFContext * mxf = s - > priv_data ;
MXFStreamContext * sc = st - > priv_data ;
int i , profile ;
if ( mxf - > header_written )
return 1 ;
sc - > codec_ul = NULL ;
profile = st - > codecpar - > profile ;
for ( i = 0 ; i < FF_ARRAY_ELEMS ( mxf_prores_codec_uls ) ; i + + ) {
if ( profile = = mxf_prores_codec_uls [ i ] . profile ) {
sc - > codec_ul = & mxf_prores_codec_uls [ i ] . codec_ul ;
break ;
}
}
if ( ! sc - > codec_ul )
return 0 ;
sc - > frame_size = pkt - > size ;
return 1 ;
}
2018-10-16 22:19:45 +02:00
static const struct {
int cid ;
UID codec_ul ;
} mxf_dnxhd_codec_uls [ ] = {
{ 1235 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x01 , 0x00 , 0x00 } } , // 1080p 10bit HIGH
{ 1237 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x03 , 0x00 , 0x00 } } , // 1080p 8bit MED
{ 1238 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x04 , 0x00 , 0x00 } } , // 1080p 8bit HIGH
{ 1241 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x07 , 0x00 , 0x00 } } , // 1080i 10bit HIGH
{ 1242 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x08 , 0x00 , 0x00 } } , // 1080i 8bit MED
{ 1243 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x09 , 0x00 , 0x00 } } , // 1080i 8bit HIGH
{ 1244 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x0a , 0x00 , 0x00 } } , // 1080i 8bit TR
{ 1250 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x10 , 0x00 , 0x00 } } , // 720p 10bit
{ 1251 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x11 , 0x00 , 0x00 } } , // 720p 8bit HIGH
{ 1252 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x12 , 0x00 , 0x00 } } , // 720p 8bit MED
{ 1253 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x13 , 0x00 , 0x00 } } , // 720p 8bit LOW
{ 1256 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x16 , 0x00 , 0x00 } } , // 1080p 10bit 444
{ 1258 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x18 , 0x00 , 0x00 } } , // 720p 8bit TR
{ 1259 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x19 , 0x00 , 0x00 } } , // 1080p 8bit TR
{ 1260 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x1a , 0x00 , 0x00 } } , // 1080i 8bit TR MBAFF
{ 1270 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x24 , 0x00 , 0x00 } } , // DNXHR 444
{ 1271 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x25 , 0x00 , 0x00 } } , // DNXHR HQX
{ 1272 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x26 , 0x00 , 0x00 } } , // DNXHR HQ
{ 1273 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x27 , 0x00 , 0x00 } } , // DNXHR SQ
{ 1274 , { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x71 , 0x28 , 0x00 , 0x00 } } , // DNXHR LB
} ;
static int mxf_parse_dnxhd_frame ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
2012-05-29 01:45:41 +03:00
{
MXFContext * mxf = s - > priv_data ;
MXFStreamContext * sc = st - > priv_data ;
2018-10-16 22:19:45 +02:00
int i , cid , frame_size = 0 ;
2012-05-29 01:45:41 +03:00
if ( mxf - > header_written )
return 1 ;
if ( pkt - > size < 43 )
2018-10-16 22:19:45 +02:00
return 0 ;
2012-05-29 01:45:41 +03:00
2018-10-16 22:19:45 +02:00
sc - > codec_ul = NULL ;
cid = AV_RB32 ( pkt - > data + 0x28 ) ;
for ( i = 0 ; i < FF_ARRAY_ELEMS ( mxf_dnxhd_codec_uls ) ; i + + ) {
if ( cid = = mxf_dnxhd_codec_uls [ i ] . cid ) {
sc - > codec_ul = & mxf_dnxhd_codec_uls [ i ] . codec_ul ;
break ;
}
}
if ( ! sc - > codec_ul )
return 0 ;
sc - > component_depth = 0 ;
switch ( pkt - > data [ 0x21 ] > > 5 ) {
case 1 : sc - > component_depth = 8 ; break ;
case 2 : sc - > component_depth = 10 ; break ;
case 3 : sc - > component_depth = 12 ; break ;
}
if ( ! sc - > component_depth )
return 0 ;
2012-05-29 01:45:41 +03:00
2018-09-08 15:26:31 +02:00
if ( ( frame_size = avpriv_dnxhd_get_frame_size ( cid ) ) = = DNXHD_VARIABLE ) {
frame_size = avpriv_dnxhd_get_hr_frame_size ( cid , st - > codecpar - > width , st - > codecpar - > height ) ;
}
if ( frame_size < 0 )
2018-10-16 22:19:45 +02:00
return 0 ;
2015-05-04 17:44:14 +02:00
if ( ( sc - > interlaced = avpriv_dnxhd_get_interlaced ( cid ) ) < 0 )
2018-10-16 22:19:45 +02:00
return 0 ;
2012-05-29 01:45:41 +03:00
2018-10-16 22:19:45 +02:00
if ( cid > = 1270 ) { // RI raster
av_reduce ( & sc - > aspect_ratio . num , & sc - > aspect_ratio . den ,
st - > codecpar - > width , st - > codecpar - > height ,
INT_MAX ) ;
} else {
sc - > aspect_ratio = ( AVRational ) { 16 , 9 } ;
2012-05-29 01:45:41 +03:00
}
2018-03-21 21:53:56 +02:00
sc - > frame_size = pkt - > size ;
2012-05-29 01:45:41 +03:00
return 1 ;
}
2019-06-21 00:40:31 +02:00
static const struct {
const UID container_ul ;
const UID codec_ul ;
} mxf_dv_uls [ ] = {
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x01 , 0x01 } , // IEC DV25 525/60
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x01 , 0x01 , 0x00 } } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x02 , 0x01 } , // IEC DV25 626/50
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x01 , 0x02 , 0x00 } } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x40 , 0x01 } , // DV25 525/60
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x01 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x41 , 0x01 } , // DV25 625/50
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x50 , 0x01 } , // DV50 525/60
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x03 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x51 , 0x01 } , // DV50 625/50
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x04 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x60 , 0x01 } , // DV100 1080/60
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x05 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x61 , 0x01 } , // DV100 1080/50
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x06 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x62 , 0x01 } , // DV100 720/60
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x07 , 0x00 } , } ,
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x0D , 0x01 , 0x03 , 0x01 , 0x02 , 0x02 , 0x63 , 0x01 } , // DV100 720/50
{ 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x01 , 0x04 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x08 , 0x00 } , } ,
} ;
2012-05-26 19:09:47 +03: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 ;
2019-06-21 00:40:31 +02:00
int apt , ul_index , stype , pal ;
2012-05-26 19:09:47 +03:00
if ( mxf - > header_written )
return 1 ;
// Check for minimal frame size
if ( pkt - > size < 120000 )
return - 1 ;
2019-06-21 00:40:31 +02:00
apt = pkt - > data [ 4 ] & 0x7 ;
2012-05-26 19:09:47 +03:00
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 ;
2017-09-14 16:05:31 +02:00
if ( ( vsc_pack [ 2 ] & 0x07 ) = = 0x02 ) {
2012-05-26 19:09:47 +03:00
sc - > aspect_ratio = ( AVRational ) { 16 , 9 } ;
2017-09-14 16:05:31 +02:00
} else {
2012-05-26 19:09:47 +03:00
sc - > aspect_ratio = ( AVRational ) { 4 , 3 } ;
2017-09-14 16:05:31 +02:00
}
2012-05-26 19:09:47 +03:00
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
2019-06-21 00:40:31 +02:00
ul_index = 8 + pal ;
2012-05-26 19:09:47 +03:00
if ( sc - > interlaced ) {
2012-09-01 13:35:14 +03:00
av_log ( s , AV_LOG_ERROR , " source marked as interlaced but codec profile is progressive \n " ) ;
2012-05-26 19:09:47 +03:00
sc - > interlaced = 0 ;
}
break ;
case 0x14 : // DV100 1080i
2019-06-21 00:40:31 +02:00
ul_index = 6 + pal ;
2012-05-26 19:09:47 +03:00
break ;
case 0x04 : // DV50
2019-06-21 00:40:31 +02:00
ul_index = 4 + pal ;
2012-05-26 19:09:47 +03:00
break ;
default : // DV25
2019-06-21 00:40:31 +02:00
if ( ! apt ) { // IEC
ul_index = 0 + pal ;
} else {
ul_index = 2 + pal ;
2017-09-12 22:17:12 +02:00
}
2012-05-26 19:09:47 +03:00
}
2019-06-21 00:40:31 +02:00
sc - > container_ul = & mxf_dv_uls [ ul_index ] . container_ul ;
sc - > codec_ul = & mxf_dv_uls [ ul_index ] . codec_ul ;
2018-03-21 21:53:56 +02:00
sc - > frame_size = pkt - > size ;
2012-05-26 19:09:47 +03:00
return 1 ;
}
2014-10-29 00:38:22 +02:00
static const struct {
UID uid ;
int frame_size ;
int profile ;
uint8_t interlaced ;
2018-10-18 22:37:05 +02:00
int intra_only ; // 1 or 0 when there are separate UIDs for Long GOP and Intra, -1 when Intra/LGOP detection can be ignored
2014-10-29 00:38:22 +02:00
} mxf_h264_codec_uls [ ] = {
2018-10-18 22:37:05 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x11 , 0x01 } , 0 , 66 , 0 , - 1 } , // AVC Baseline
2018-05-06 21:05:47 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x20 , 0x01 } , 0 , 77 , 0 , - 1 } , // AVC Main
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x30 , 0x01 } , 0 , 88 , 0 , - 1 } , // AVC Extended
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x40 , 0x01 } , 0 , 100 , 0 , - 1 } , // AVC High
2018-10-18 22:37:05 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x50 , 0x01 } , 0 , 110 , 0 , 0 } , // AVC High 10
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x60 , 0x01 } , 0 , 122 , 0 , 0 } , // AVC High 422
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x31 , 0x70 , 0x01 } , 0 , 244 , 0 , 0 } , // AVC High 444
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x20 , 0x01 } , 0 , 110 , 0 , 1 } , // AVC High 10 Intra
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x01 } , 232960 , 110 , 1 , 1 } , // AVC High 10 Intra RP2027 Class 50 1080/59.94i
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x02 } , 281088 , 110 , 1 , 1 } , // AVC High 10 Intra RP2027 Class 50 1080/50i
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x03 } , 232960 , 110 , 0 , 1 } , // AVC High 10 Intra RP2027 Class 50 1080/29.97p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x04 } , 281088 , 110 , 0 , 1 } , // AVC High 10 Intra RP2027 Class 50 1080/25p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x08 } , 116736 , 110 , 0 , 1 } , // AVC High 10 Intra RP2027 Class 50 720/59.94p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x21 , 0x09 } , 140800 , 110 , 0 , 1 } , // AVC High 10 Intra RP2027 Class 50 720/50p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x30 , 0x01 } , 0 , 122 , 0 , 1 } , // AVC High 422 Intra
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x01 } , 472576 , 122 , 1 , 1 } , // AVC High 422 Intra RP2027 Class 100 1080/59.94i
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x02 } , 568832 , 122 , 1 , 1 } , // AVC High 422 Intra RP2027 Class 100 1080/50i
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x03 } , 472576 , 122 , 0 , 1 } , // AVC High 422 Intra RP2027 Class 100 1080/29.97p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x04 } , 568832 , 122 , 0 , 1 } , // AVC High 422 Intra RP2027 Class 100 1080/25p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x08 } , 236544 , 122 , 0 , 1 } , // AVC High 422 Intra RP2027 Class 100 720/59.94p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0a , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x31 , 0x09 } , 284672 , 122 , 0 , 1 } , // AVC High 422 Intra RP2027 Class 100 720/50p
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x40 , 0x01 } , 0 , 244 , 0 , 1 } , // AVC High 444 Intra
2018-05-06 21:05:47 +02:00
{ { 0x06 , 0x0E , 0x2B , 0x34 , 0x04 , 0x01 , 0x01 , 0x0d , 0x04 , 0x01 , 0x02 , 0x02 , 0x01 , 0x32 , 0x50 , 0x01 } , 0 , 44 , 0 , - 1 } , // AVC CAVLC 444
2014-10-29 00:38:22 +02:00
} ;
static int mxf_parse_h264_frame ( AVFormatContext * s , AVStream * st ,
AVPacket * pkt , MXFIndexEntry * e )
{
MXFContext * mxf = s - > priv_data ;
MXFStreamContext * sc = st - > priv_data ;
2018-10-18 22:37:05 +02:00
H264SequenceParameterSet * sps = NULL ;
GetBitContext gb ;
2014-10-29 00:38:22 +02:00
const uint8_t * buf = pkt - > data ;
const uint8_t * buf_end = pkt - > data + pkt - > size ;
2018-10-18 22:37:05 +02:00
const uint8_t * nal_end ;
2014-10-29 00:38:22 +02:00
uint32_t state = - 1 ;
int extra_size = 512 ; // support AVC Intra files without SPS/PPS header
2018-10-18 22:37:05 +02:00
int i , frame_size , slice_type , intra_only = 0 ;
2014-10-29 00:38:22 +02:00
for ( ; ; ) {
buf = avpriv_find_start_code ( buf , buf_end , & state ) ;
if ( buf > = buf_end )
break ;
2018-10-18 22:37:05 +02:00
2014-10-29 00:38:22 +02:00
switch ( state & 0x1f ) {
2016-08-01 20:11:05 +02:00
case H264_NAL_SPS :
2014-10-29 00:38:22 +02:00
e - > flags | = 0x40 ;
2018-10-18 22:37:05 +02:00
if ( mxf - > header_written )
break ;
nal_end = ff_avc_find_startcode ( buf , buf_end ) ;
sps = ff_avc_decode_sps ( buf , nal_end - buf ) ;
if ( ! sps ) {
av_log ( s , AV_LOG_ERROR , " error parsing sps \n " ) ;
return 0 ;
}
sc - > aspect_ratio . num = st - > codecpar - > width * sps - > sar . num ;
sc - > aspect_ratio . den = st - > codecpar - > height * sps - > sar . den ;
av_reduce ( & sc - > aspect_ratio . num , & sc - > aspect_ratio . den ,
sc - > aspect_ratio . num , sc - > aspect_ratio . den , 1024 * 1024 ) ;
intra_only = ( sps - > constraint_set_flags > > 3 ) & 1 ;
sc - > interlaced = ! sps - > frame_mbs_only_flag ;
sc - > component_depth = sps - > bit_depth_luma ;
buf = nal_end ;
2014-10-29 00:38:22 +02:00
break ;
2016-08-01 20:11:05 +02:00
case H264_NAL_PPS :
2014-10-29 00:38:22 +02:00
if ( e - > flags & 0x40 ) { // sequence header present
e - > flags | = 0x80 ; // random access
extra_size = 0 ;
}
break ;
2018-10-18 22:37:05 +02:00
case H264_NAL_IDR_SLICE :
e - > flags | = 0x04 ; // IDR Picture
buf = buf_end ;
break ;
case H264_NAL_SLICE :
init_get_bits8 ( & gb , buf , buf_end - buf ) ;
get_ue_golomb_long ( & gb ) ; // skip first_mb_in_slice
slice_type = get_ue_golomb_31 ( & gb ) ;
switch ( slice_type % 5 ) {
case 0 :
e - > flags | = 0x20 ; // P Picture
e - > flags | = 0x06 ; // P Picture
break ;
case 1 :
e - > flags | = 0x30 ; // B Picture
e - > flags | = 0x03 ; // non-referenced B Picture
break ;
}
buf = buf_end ;
break ;
2014-10-29 00:38:22 +02:00
default :
break ;
}
}
if ( mxf - > header_written )
return 1 ;
2018-10-18 22:37:05 +02:00
if ( ! sps )
sc - > interlaced = st - > codecpar - > field_order ! = AV_FIELD_PROGRESSIVE ? 1 : 0 ;
sc - > codec_ul = NULL ;
2014-10-29 00:38:22 +02:00
frame_size = pkt - > size + extra_size ;
2018-10-18 22:37:05 +02:00
for ( i = 0 ; i < FF_ARRAY_ELEMS ( mxf_h264_codec_uls ) ; i + + ) {
2014-10-29 00:38:22 +02:00
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 ;
2018-05-06 21:05:47 +02:00
sc - > component_depth = 10 ; // AVC Intra is always 10 Bit
2018-10-18 22:37:05 +02:00
sc - > aspect_ratio = ( AVRational ) { 16 , 9 } ; // 16:9 is mandatory for broadcast HD
st - > codecpar - > profile = mxf_h264_codec_uls [ i ] . profile ;
sc - > avc_intra = 1 ;
mxf - > cbr_index = 1 ;
sc - > frame_size = pkt - > size ;
2018-05-06 21:05:47 +02:00
if ( sc - > interlaced )
sc - > field_dominance = 1 ; // top field first is mandatory for AVC Intra
2018-10-18 22:37:05 +02:00
break ;
} else if ( sps & & mxf_h264_codec_uls [ i ] . frame_size = = 0 & &
mxf_h264_codec_uls [ i ] . profile = = sps - > profile_idc & &
( mxf_h264_codec_uls [ i ] . intra_only < 0 | |
mxf_h264_codec_uls [ i ] . intra_only = = intra_only ) ) {
2014-10-29 00:38:22 +02:00
sc - > codec_ul = & mxf_h264_codec_uls [ i ] . uid ;
2018-10-18 22:37:05 +02:00
st - > codecpar - > profile = sps - > profile_idc ;
st - > codecpar - > level = sps - > level_idc ;
// continue to check for avc intra
2014-10-29 00:38:22 +02:00
}
}
2018-10-18 22:37:05 +02:00
av_free ( sps ) ;
if ( ! sc - > codec_ul ) {
2018-05-06 21:05:47 +02:00
av_log ( s , AV_LOG_ERROR , " h264 profile not supported \n " ) ;
2014-10-29 00:38:22 +02:00
return 0 ;
}
return 1 ;
}
2008-08-31 05:41:31 +03: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 19:16:30 +03: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 05:41:31 +03:00
} ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
static const UID * mxf_get_mpeg2_codec_ul ( AVCodecParameters * par )
2008-08-31 05:41:31 +03:00
{
2014-11-15 11:41:02 +02:00
int long_gop = 1 ;
2009-07-04 11:02:01 +03:00
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( par - > profile = = 4 ) { // Main
if ( par - > level = = 8 ) // Main
2009-07-04 11:02:01 +03:00
return & mxf_mpeg2_codec_uls [ 0 + long_gop ] ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
else if ( par - > level = = 4 ) // High
2009-07-04 11:02:01 +03:00
return & mxf_mpeg2_codec_uls [ 4 + long_gop ] ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
else if ( par - > level = = 6 ) // High 14
2011-09-16 19:16:30 +03:00
return & mxf_mpeg2_codec_uls [ 8 + long_gop ] ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
} else if ( par - > profile = = 0 ) { // 422
if ( par - > level = = 5 ) // Main
2009-07-04 11:02:01 +03:00
return & mxf_mpeg2_codec_uls [ 2 + long_gop ] ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
else if ( par - > level = = 2 ) // High
2009-07-04 11:02:01 +03:00
return & mxf_mpeg2_codec_uls [ 6 + long_gop ] ;
2008-08-31 05:41:31 +03:00
}
return NULL ;
}
2010-07-02 11:35:47 +03:00
static int mxf_parse_mpeg2_frame ( AVFormatContext * s , AVStream * st ,
AVPacket * pkt , MXFIndexEntry * e )
2009-01-31 08:32:12 +02: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 10:43:32 +03:00
if ( c = = 0x1b5 ) {
2009-05-15 07:43:44 +03:00
if ( ( pkt - > data [ i + 1 ] & 0xf0 ) = = 0x10 ) { // seq ext
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
st - > codecpar - > profile = pkt - > data [ i + 1 ] & 0x07 ;
st - > codecpar - > level = pkt - > data [ i + 2 ] > > 4 ;
2018-03-21 18:35:22 +02:00
sc - > low_delay = pkt - > data [ i + 6 ] > > 7 ;
2009-01-31 08:42:47 +02: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 15:21:41 +03:00
if ( sc - > interlaced )
sc - > field_dominance = 1 + ! ( pkt - > data [ i + 4 ] & 0x80 ) ; // top field first
2009-01-31 08:32:12 +02:00
break ;
}
2009-02-02 12:03:38 +02:00
} else if ( c = = 0x1b8 ) { // gop
2009-06-30 10:41:40 +03:00
if ( pkt - > data [ i + 4 ] > > 6 & 0x01 ) { // closed
2018-03-21 18:35:22 +02:00
if ( sc - > seq_closed_gop = = - 1 )
sc - > seq_closed_gop = 1 ;
2009-06-30 10:41:40 +03:00
sc - > closed_gop = 1 ;
2010-07-02 11:35:47 +03:00
if ( e - > flags & 0x40 ) // sequence header present
e - > flags | = 0x80 ; // random access
2018-03-21 18:35:22 +02:00
} else {
sc - > seq_closed_gop = 0 ;
sc - > closed_gop = 0 ;
2009-06-30 10:41:40 +03:00
}
2009-02-02 12:03:38 +02:00
} else if ( c = = 0x1b3 ) { // seq
2010-07-02 11:35:47 +03:00
e - > flags | = 0x40 ;
2009-05-15 07:44:37 +03: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 ,
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
st - > codecpar - > width , st - > codecpar - > height , 1024 * 1024 ) ;
2009-05-15 07:44:37 +03:00
}
2009-02-02 12:03:38 +02:00
} else if ( c = = 0x100 ) { // pic
int pict_type = ( pkt - > data [ i + 2 ] > > 3 ) & 0x07 ;
2010-07-02 11:35:47 +03:00
e - > temporal_ref = ( pkt - > data [ i + 1 ] < < 2 ) | ( pkt - > data [ i + 2 ] > > 6 ) ;
2016-04-27 19:45:23 +02:00
if ( pict_type = = 2 ) { // P-frame
2010-07-02 11:35:47 +03:00
e - > flags | = 0x22 ;
2016-04-27 19:45:23 +02:00
sc - > closed_gop = 0 ; // reset closed GOP, don't matter anymore
} else if ( pict_type = = 3 ) { // B-frame
2009-06-30 10:41:40 +03:00
if ( sc - > closed_gop )
2010-07-02 11:35:47 +03:00
e - > flags | = 0x13 ; // only backward prediction
2009-06-30 10:41:40 +03:00
else
2010-07-02 11:35:47 +03:00
e - > flags | = 0x33 ;
2009-02-02 12:03:38 +02: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 08:32:12 +02:00
}
}
2011-01-26 00:03:28 +02:00
if ( s - > oformat ! = & ff_mxf_d10_muxer )
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
sc - > codec_ul = mxf_get_mpeg2_codec_ul ( st - > codecpar ) ;
2009-01-31 08:32:12 +02:00
return ! ! sc - > codec_ul ;
}
2018-12-22 21:02:09 +02:00
static uint64_t mxf_parse_timestamp ( int64_t timestamp64 )
2009-02-05 22:15:18 +02:00
{
2018-12-22 21:02:09 +02:00
time_t timestamp = timestamp64 / 1000000 ;
2014-10-24 10:46:36 +03:00
struct tm tmbuf ;
struct tm * time = gmtime_r ( & timestamp , & tmbuf ) ;
2011-01-15 00:36:23 +02:00
if ( ! time )
return 0 ;
2009-02-05 22:15:18 +02: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 |
2018-12-22 21:02:09 +02:00
time - > tm_sec < < 8 |
( timestamp64 % 1000000 ) / 4000 ;
2009-02-05 22:15:18 +02:00
}
2009-03-11 08:15:00 +02:00
static void mxf_gen_umid ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2010-05-23 11:53:40 +03:00
uint32_t seed = av_get_random_seed ( ) ;
2009-03-11 08:15:00 +02:00
uint64_t umid = seed + 0x5294713400000000LL ;
AV_WB64 ( mxf - > umid , umid ) ;
AV_WB64 ( mxf - > umid + 8 , umid > > 8 ) ;
2013-09-29 15:33:40 +03:00
mxf - > instance_number = seed & 0xFFFFFF ;
2009-03-11 08:15:00 +02:00
}
2015-04-12 02:18:13 +02: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 05:50:25 +03:00
static int mxf_write_header ( AVFormatContext * s )
2008-08-19 15:36:17 +03:00
{
MXFContext * mxf = s - > priv_data ;
2012-01-16 16:19:37 +03:00
int i , ret ;
2008-10-22 00:40:24 +03:00
uint8_t present [ FF_ARRAY_ELEMS ( mxf_essence_container_uls ) ] = { 0 } ;
2011-07-07 12:25:03 +03:00
int64_t timestamp = 0 ;
2008-08-31 02:47:58 +03:00
2009-03-11 08:15:00 +02:00
if ( ! s - > nb_streams )
return - 1 ;
2017-09-14 16:05:31 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer & & s - > nb_streams ! = 1 ) {
2015-01-29 05:44:21 +02:00
av_log ( s , AV_LOG_ERROR , " there must be exactly one stream for mxf opatom \n " ) ;
return - 1 ;
}
2015-11-09 15:24:26 +02:00
if ( ! av_dict_get ( s - > metadata , " comment_ " , NULL , AV_DICT_IGNORE_SUFFIX ) )
mxf - > store_user_comments = 0 ;
2008-08-31 02:47:58 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
2008-08-31 03:39:34 +03:00
MXFStreamContext * sc = av_mallocz ( sizeof ( * sc ) ) ;
2008-08-31 02:47:58 +03:00
if ( ! sc )
return AVERROR ( ENOMEM ) ;
st - > priv_data = sc ;
2019-06-21 01:11:28 +02:00
sc - > index = - 1 ;
2009-01-31 08:18:25 +02:00
2016-04-10 21:58:15 +02:00
if ( ( ( i = = 0 ) ^ ( st - > codecpar - > codec_type = = AVMEDIA_TYPE_VIDEO ) ) & & s - > oformat ! = & ff_mxf_opatom_muxer ) {
2012-03-29 12:48:45 +03:00
av_log ( s , AV_LOG_ERROR , " there must be exactly one video stream and it must be the first one \n " ) ;
return - 1 ;
}
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( st - > codecpar - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2016-04-10 21:58:15 +02:00
const AVPixFmtDescriptor * pix_desc = av_pix_fmt_desc_get ( st - > codecpar - > format ) ;
2014-05-18 13:12:59 +03:00
// TODO: should be avg_frame_rate
2014-06-18 19:18:25 +03:00
AVRational rate , tbc = st - > time_base ;
2012-05-29 01:45:41 +03:00
// Default component depth to 8
sc - > component_depth = 8 ;
2015-05-16 20:02:01 +02:00
sc - > h_chroma_sub_sample = 2 ;
2018-03-21 18:35:22 +02:00
sc - > v_chroma_sub_sample = 2 ;
2015-05-19 01:11:09 +02:00
sc - > color_siting = 0xFF ;
2015-05-16 19:59:18 +02:00
2018-12-10 11:15:27 +02:00
if ( st - > codecpar - > sample_aspect_ratio . num & & st - > codecpar - > sample_aspect_ratio . den ) {
sc - > aspect_ratio = av_mul_q ( st - > codecpar - > sample_aspect_ratio ,
av_make_q ( st - > codecpar - > width , st - > codecpar - > height ) ) ;
}
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 ;
2018-03-21 20:32:32 +02:00
sc - > v_chroma_sub_sample = 1 < < pix_desc - > log2_chroma_h ;
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
2020-02-28 02:10:45 +02:00
mxf - > content_package_rate = ff_mxf_get_content_package_rate ( tbc ) ;
if ( ! mxf - > content_package_rate ) {
2012-08-03 11:20:44 +03:00
av_log ( s , AV_LOG_ERROR , " Unsupported video frame rate %d/%d \n " ,
tbc . den , tbc . num ) ;
return AVERROR ( EINVAL ) ;
2009-01-31 08:18:25 +02:00
}
2020-02-28 02:10:45 +02:00
mxf - > timecode_base = ( tbc . den + tbc . num / 2 ) / tbc . num ;
mxf - > time_base = tbc ;
2012-08-06 00:25:27 +03:00
rate = av_inv_q ( mxf - > time_base ) ;
2011-11-29 21:28:15 +03:00
avpriv_set_pts_info ( st , 64 , mxf - > time_base . num , mxf - > time_base . den ) ;
2015-04-12 02:18:13 +02:00
if ( ( ret = mxf_init_timecode ( s , st , rate ) ) < 0 )
2012-01-16 16:19:37 +03:00
return ret ;
2015-04-12 02:18:13 +02:00
2018-03-21 18:35:22 +02:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_MPEG2VIDEO ) {
sc - > seq_closed_gop = - 1 ; // unknown yet
}
2016-04-10 21:58:15 +02:00
sc - > video_bit_rate = st - > codecpar - > bit_rate ;
2018-03-21 21:53:56 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer | |
st - > codecpar - > codec_id = = AV_CODEC_ID_DNXHD | |
st - > codecpar - > codec_id = = AV_CODEC_ID_DVVIDEO )
mxf - > cbr_index = 1 ;
2011-01-26 00:03:28 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer ) {
2019-06-21 01:11:28 +02:00
int ntsc = mxf - > time_base . den ! = 25 ;
int ul_index ;
2017-08-29 02:13:20 +02:00
if ( st - > codecpar - > codec_id ! = AV_CODEC_ID_MPEG2VIDEO ) {
av_log ( s , AV_LOG_ERROR , " error MXF D-10 only support MPEG-2 Video \n " ) ;
return AVERROR ( EINVAL ) ;
}
2015-06-01 21:35:02 +02:00
if ( ( sc - > video_bit_rate = = 50000000 ) & & ( mxf - > time_base . den = = 25 ) ) {
2019-06-21 01:11:28 +02:00
ul_index = 0 ;
} else if ( ( sc - > video_bit_rate = = 49999840 | | sc - > video_bit_rate = = 50000000 ) & & ntsc ) {
ul_index = 1 ;
2013-09-09 11:02:12 +03:00
} else if ( sc - > video_bit_rate = = 40000000 ) {
2019-06-21 01:11:28 +02:00
ul_index = 2 + ntsc ;
2013-09-09 11:02:12 +03:00
} else if ( sc - > video_bit_rate = = 30000000 ) {
2019-06-21 01:11:28 +02:00
ul_index = 4 + ntsc ;
2012-10-21 18:36:53 +03:00
} else {
2009-02-13 09:28:20 +02:00
av_log ( s , AV_LOG_ERROR , " error MXF D-10 only support 30/40/50 mbit/s \n " ) ;
return - 1 ;
}
2019-06-21 01:11:28 +02:00
sc - > codec_ul = & mxf_d10_codec_uls [ ul_index ] ;
sc - > container_ul = & mxf_d10_container_uls [ ul_index ] ;
sc - > index = INDEX_D10_VIDEO ;
2015-05-24 02:43:26 +02:00
sc - > signal_standard = 1 ;
2018-04-06 18:09:54 +02:00
sc - > color_siting = 0 ;
2018-03-21 21:53:56 +02:00
sc - > frame_size = ( int64_t ) sc - > video_bit_rate *
mxf - > time_base . num / ( 8 * mxf - > time_base . den ) ;
2009-02-13 09:28:20 +02:00
}
2015-06-06 03:06:12 +02:00
if ( mxf - > signal_standard > = 0 )
sc - > signal_standard = mxf - > signal_standard ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
} else if ( st - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
if ( st - > codecpar - > sample_rate ! = 48000 ) {
2009-01-31 08:18:25 +02:00
av_log ( s , AV_LOG_ERROR , " only 48khz is implemented \n " ) ;
return - 1 ;
}
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avpriv_set_pts_info ( st , 64 , 1 , st - > codecpar - > sample_rate ) ;
2011-01-26 00:03:28 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer ) {
2009-02-13 09:28:20 +02:00
if ( st - > index ! = 1 ) {
av_log ( s , AV_LOG_ERROR , " MXF D-10 only support one audio track \n " ) ;
return - 1 ;
}
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( st - > codecpar - > codec_id ! = AV_CODEC_ID_PCM_S16LE & &
st - > codecpar - > codec_id ! = AV_CODEC_ID_PCM_S24LE ) {
2009-02-13 09:28:20 +02:00
av_log ( s , AV_LOG_ERROR , " MXF D-10 only support 16 or 24 bits le audio \n " ) ;
}
2019-06-21 01:11:28 +02:00
sc - > index = INDEX_D10_AUDIO ;
sc - > container_ul = ( ( MXFStreamContext * ) s - > streams [ 0 ] - > priv_data ) - > container_ul ;
2020-02-28 02:10:45 +02:00
sc - > frame_size = 4 + 8 * av_rescale_rnd ( st - > codecpar - > sample_rate , mxf - > time_base . num , mxf - > time_base . den , AV_ROUND_UP ) * 4 ;
2015-04-12 02:18:13 +02:00
} else if ( s - > oformat = = & ff_mxf_opatom_muxer ) {
AVRational tbc = av_inv_q ( mxf - > audio_edit_rate ) ;
2016-04-10 21:58:15 +02:00
if ( st - > codecpar - > codec_id ! = AV_CODEC_ID_PCM_S16LE & &
st - > codecpar - > codec_id ! = AV_CODEC_ID_PCM_S24LE ) {
2015-04-12 02:18:13 +02:00
av_log ( s , AV_LOG_ERROR , " Only pcm_s16le and pcm_s24le audio codecs are implemented \n " ) ;
return AVERROR_PATCHWELCOME ;
}
2016-04-10 21:58:15 +02:00
if ( st - > codecpar - > channels ! = 1 ) {
2015-04-12 02:18:13 +02:00
av_log ( s , AV_LOG_ERROR , " MXF OPAtom only supports single channel audio \n " ) ;
return AVERROR ( EINVAL ) ;
}
2020-02-28 02:10:45 +02:00
if ( ! ff_mxf_get_content_package_rate ( tbc ) ) {
2015-04-12 02:18:13 +02:00
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 ;
2020-02-28 02:10:45 +02:00
if ( ( ret = mxf_init_timecode ( s , st , av_inv_q ( tbc ) ) ) < 0 )
2015-04-12 02:18:13 +02:00
return ret ;
mxf - > timecode_base = ( tbc . den + tbc . num / 2 ) / tbc . num ;
2016-04-10 21:58:15 +02:00
mxf - > edit_unit_byte_count = ( av_get_bits_per_sample ( st - > codecpar - > codec_id ) * st - > codecpar - > channels ) > > 3 ;
2017-08-29 02:13:21 +02:00
sc - > index = INDEX_WAV ;
2015-04-12 02:18:13 +02:00
} else {
mxf - > slice_count = 1 ;
2020-02-28 02:10:45 +02:00
sc - > frame_size = st - > codecpar - > channels *
av_rescale_rnd ( st - > codecpar - > sample_rate , mxf - > time_base . num , mxf - > time_base . den , AV_ROUND_UP ) *
av_get_bits_per_sample ( st - > codecpar - > codec_id ) / 8 ;
2015-04-12 02:18:13 +02:00
}
2016-11-19 21:09:24 +02:00
} else if ( st - > codecpar - > codec_type = = AVMEDIA_TYPE_DATA ) {
AVDictionaryEntry * e = av_dict_get ( st - > metadata , " data_type " , NULL , 0 ) ;
if ( e & & ! strcmp ( e - > value , " vbi_vanc_smpte_436M " ) ) {
2018-10-16 22:19:45 +02:00
sc - > index = INDEX_S436M ;
2016-11-19 21:09:24 +02:00
} else {
av_log ( s , AV_LOG_ERROR , " track %d: unsupported data type \n " , i ) ;
return - 1 ;
}
if ( st - > index ! = s - > nb_streams - 1 ) {
av_log ( s , AV_LOG_ERROR , " data track must be placed last \n " ) ;
return - 1 ;
}
2009-01-31 08:18:25 +02:00
}
2008-08-31 05:46:50 +03:00
2019-06-21 01:11:28 +02:00
if ( sc - > index = = - 1 ) {
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
sc - > index = mxf_get_essence_container_ul_index ( st - > codecpar - > codec_id ) ;
2009-02-13 09:34:01 +02:00
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 09:28:20 +02:00
}
2008-08-31 05:41:31 +03:00
2019-06-21 01:11:28 +02:00
if ( ! sc - > codec_ul )
sc - > codec_ul = & mxf_essence_container_uls [ sc - > index ] . codec_ul ;
if ( ! sc - > container_ul )
sc - > container_ul = & mxf_essence_container_uls [ sc - > index ] . container_ul ;
2008-08-31 05:41:31 +03:00
2008-08-31 07:13:44 +03: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 04:33:28 +03:00
PRINT_KEY ( s , " track essence element key " , sc - > track_essence_element_key ) ;
2009-02-18 04:57:41 +02:00
if ( ! present [ sc - > index ] )
mxf - > essence_container_count + + ;
present [ sc - > index ] + + ;
2008-08-31 02:47:58 +03:00
}
2008-08-22 07:12:52 +03:00
2015-01-29 05:44:21 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer | | s - > oformat = = & ff_mxf_opatom_muxer ) {
2009-02-13 09:28:20 +02:00
mxf - > essence_container_count = 1 ;
}
2014-05-01 11:43:10 +03:00
if ( ! ( s - > flags & AVFMT_FLAG_BITEXACT ) )
2009-03-11 08:15:00 +02:00
mxf_gen_umid ( s ) ;
2009-01-31 08:18:25 +02: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 ] ;
2019-06-21 00:40:31 +02:00
if ( ! memcmp ( sc - > track_essence_element_key , mxf_essence_container_uls [ INDEX_DV ] . element_ul , 13 ) ) // DV
2012-05-26 19:09:47 +03:00
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 08:18:25 +02:00
}
2018-12-22 21:02:09 +02:00
if ( ff_parse_creation_time_metadata ( s , & timestamp , 0 ) > 0 )
2011-07-07 12:25:03 +03:00
mxf - > timestamp = mxf_parse_timestamp ( timestamp ) ;
2009-02-11 09:18:00 +02: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 03:35:36 +02:00
mxf - > timecode_track - > index = - 1 ;
2009-02-05 22:15:18 +02:00
2020-02-28 01:26:20 +02:00
if ( ff_audio_interleave_init ( s , 0 , av_inv_q ( mxf - > tc . rate ) ) < 0 )
2009-01-31 08:18:25 +02:00
return - 1 ;
2008-08-22 07:12:52 +03:00
return 0 ;
}
2009-02-08 04:34:56 +02: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 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2009-02-11 09:18:00 +02:00
unsigned frame ;
2009-02-08 04:34:56 +02:00
uint32_t time_code ;
2016-11-19 21:09:24 +02:00
int i , system_item_bitmap = 0x58 ; // UL, user date/time stamp, picture present
2009-02-08 04:34:56 +02:00
2012-01-16 16:19:37 +03:00
frame = mxf - > last_indexed_edit_unit + mxf - > edit_units_count ;
2009-02-08 04:34:56 +02:00
// write system metadata pack
2011-02-21 20:28:17 +02:00
avio_write ( pb , system_metadata_pack_key , 16 ) ;
2009-02-13 09:06:35 +02:00
klv_encode_ber4_length ( pb , 57 ) ;
2016-11-19 21:09:24 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
if ( s - > streams [ i ] - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO )
system_item_bitmap | = 0x4 ;
else if ( s - > streams [ i ] - > codecpar - > codec_type = = AVMEDIA_TYPE_DATA )
system_item_bitmap | = 0x2 ;
}
avio_w8 ( pb , system_item_bitmap ) ;
2018-03-21 22:13:51 +02:00
avio_w8 ( pb , mxf - > content_package_rate ) ; // content package rate
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0x00 ) ; // content package type
avio_wb16 ( pb , 0x00 ) ; // channel handle
2020-02-29 02:25:56 +02:00
avio_wb16 ( pb , frame & 0xFFFF ) ; // continuity count, supposed to overflow
2009-02-08 04:34:56 +02:00
if ( mxf - > essence_container_count > 1 )
2011-02-21 20:28:17 +02:00
avio_write ( pb , multiple_desc_ul , 16 ) ;
2009-02-13 09:46:03 +02:00
else {
MXFStreamContext * sc = s - > streams [ 0 ] - > priv_data ;
2019-06-21 00:40:31 +02:00
avio_write ( pb , * sc - > container_ul , 16 ) ;
2009-02-13 09:46:03 +02:00
}
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0 ) ;
avio_wb64 ( pb , 0 ) ;
avio_wb64 ( pb , 0 ) ; // creation date/time stamp
2009-02-08 04:34:56 +02:00
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0x81 ) ; // SMPTE 12M time code
2012-01-16 16:19:37 +03:00
time_code = av_timecode_get_smpte_from_framenum ( & mxf - > tc , frame ) ;
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , time_code ) ;
avio_wb32 ( pb , 0 ) ; // binary group data
avio_wb64 ( pb , 0 ) ;
2009-02-08 04:34:56 +02:00
// write system metadata package set
2011-02-21 20:28:17 +02:00
avio_write ( pb , system_metadata_package_set_key , 16 ) ;
2009-02-13 09:06:35 +02:00
klv_encode_ber4_length ( pb , 35 ) ;
2011-02-21 20:28:17 +02:00
avio_w8 ( pb , 0x83 ) ; // UMID
avio_wb16 ( pb , 0x20 ) ;
2009-03-11 08:15:00 +02:00
mxf_write_umid ( s , 1 ) ;
2009-02-08 04:34:56 +02:00
}
2009-02-13 09:28:20 +02:00
static void mxf_write_d10_audio_packet ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
int frame_size = pkt - > size / st - > codecpar - > block_align ;
2009-02-13 09:28:20 +02: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 20:28:17 +02:00
avio_w8 ( pb , ( frame_size = = 1920 ? 0 : ( mxf - > edit_units_count - 1 ) % 5 + 1 ) ) ;
avio_wl16 ( pb , frame_size ) ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
avio_w8 ( pb , ( 1 < < st - > codecpar - > channels ) - 1 ) ;
2009-02-13 09:28:20 +02:00
while ( samples < end ) {
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
for ( i = 0 ; i < st - > codecpar - > channels ; i + + ) {
2009-02-13 09:28:20 +02:00
uint32_t sample ;
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_PCM_S24LE ) {
2009-02-25 10:05:43 +02:00
sample = AV_RL24 ( samples ) < < 4 ;
2009-02-13 09:28:20 +02:00
samples + = 3 ;
} else {
2009-02-25 10:05:43 +02:00
sample = AV_RL16 ( samples ) < < 12 ;
2009-02-13 09:28:20 +02:00
samples + = 2 ;
}
2011-02-21 20:28:17 +02:00
avio_wl32 ( pb , sample | i ) ;
2009-02-13 09:28:20 +02:00
}
for ( ; i < 8 ; i + + )
2011-02-21 20:28:17 +02:00
avio_wl32 ( pb , i ) ;
2009-02-13 09:28:20 +02:00
}
}
2015-01-29 05:44:21 +02: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 ;
return 0 ;
}
2018-03-21 21:53:56 +02:00
static void mxf_compute_edit_unit_byte_count ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
int i ;
if ( s - > oformat = = & ff_mxf_opatom_muxer ) {
MXFStreamContext * sc = s - > streams [ 0 ] - > priv_data ;
mxf - > edit_unit_byte_count = sc - > frame_size ;
return ;
}
mxf - > edit_unit_byte_count = KAG_SIZE ; // system element
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVStream * st = s - > streams [ i ] ;
MXFStreamContext * sc = st - > priv_data ;
sc - > slice_offset = mxf - > edit_unit_byte_count ;
mxf - > edit_unit_byte_count + = 16 + 4 + sc - > frame_size ;
mxf - > edit_unit_byte_count + = klv_fill_size ( mxf - > edit_unit_byte_count ) ;
}
}
2008-08-31 05:50:25 +03:00
static int mxf_write_packet ( AVFormatContext * s , AVPacket * pkt )
2008-08-25 23:28:12 +03:00
{
2009-01-31 08:32:12 +02:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2008-08-25 23:28:12 +03:00
AVStream * st = s - > streams [ pkt - > stream_index ] ;
MXFStreamContext * sc = st - > priv_data ;
2010-07-02 11:35:47 +03:00
MXFIndexEntry ie = { 0 } ;
2013-08-02 20:21:24 +03:00
int err ;
2008-08-25 23:28:12 +03:00
2018-03-21 21:53:56 +02:00
if ( ! mxf - > cbr_index & & ! mxf - > edit_unit_byte_count & & ! ( mxf - > edit_units_count % EDIT_UNITS_PER_BODY ) ) {
2013-08-02 20:21:24 +03: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 12:03:38 +02:00
av_log ( s , AV_LOG_ERROR , " could not allocate index entries \n " ) ;
2013-08-02 20:21:24 +03:00
return err ;
2009-02-02 12:03:38 +02:00
}
}
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_MPEG2VIDEO ) {
2010-07-02 11:35:47 +03:00
if ( ! mxf_parse_mpeg2_frame ( s , st , pkt , & ie ) ) {
2009-02-02 12:03:38 +02:00
av_log ( s , AV_LOG_ERROR , " could not get mpeg2 profile and level \n " ) ;
return - 1 ;
2009-01-31 08:32:12 +02:00
}
2016-04-10 21:58:15 +02:00
} else if ( st - > codecpar - > codec_id = = AV_CODEC_ID_DNXHD ) {
2012-05-29 01:45:41 +03:00
if ( ! mxf_parse_dnxhd_frame ( s , st , pkt ) ) {
av_log ( s , AV_LOG_ERROR , " could not get dnxhd profile \n " ) ;
return - 1 ;
}
2018-12-05 19:10:37 +02:00
} else if ( st - > codecpar - > codec_id = = AV_CODEC_ID_PRORES ) {
if ( ! mxf_parse_prores_frame ( s , st , pkt ) ) {
av_log ( s , AV_LOG_ERROR , " could not get prores profile \n " ) ;
return - 1 ;
}
2016-04-10 21:58:15 +02:00
} else if ( st - > codecpar - > codec_id = = AV_CODEC_ID_DVVIDEO ) {
2012-05-26 19:09:47 +03:00
if ( ! mxf_parse_dv_frame ( s , st , pkt ) ) {
av_log ( s , AV_LOG_ERROR , " could not get dv profile \n " ) ;
return - 1 ;
}
2016-04-10 21:58:15 +02:00
} else if ( st - > codecpar - > codec_id = = AV_CODEC_ID_H264 ) {
2014-10-29 00:38:22 +02:00
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 12:03:38 +02:00
}
2018-03-21 21:53:56 +02:00
if ( mxf - > cbr_index ) {
if ( pkt - > size ! = sc - > frame_size & & st - > codecpar - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
av_log ( s , AV_LOG_ERROR , " track %d: frame size does not match index unit size, %d != %d \n " ,
st - > index , pkt - > size , sc - > frame_size ) ;
return - 1 ;
}
if ( ! mxf - > header_written )
mxf_compute_edit_unit_byte_count ( s ) ;
}
2015-01-29 05:44:21 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer )
return mxf_write_opatom_packet ( s , pkt , & ie ) ;
2009-02-02 12:03:38 +02:00
if ( ! mxf - > header_written ) {
2009-02-16 12:44:38 +02:00
if ( mxf - > edit_unit_byte_count ) {
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 1 , 2 , header_open_partition_key , 1 ) ) < 0 )
return err ;
2009-02-16 12:44:38 +02:00
mxf_write_klv_fill ( s ) ;
mxf_write_index_table_segment ( s ) ;
} else {
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 0 , 0 , header_open_partition_key , 1 ) ) < 0 )
return err ;
2009-02-16 12:44:38 +02:00
}
2009-01-31 08:32:12 +02:00
mxf - > header_written = 1 ;
}
2009-02-08 04:38:07 +02:00
if ( st - > index = = 0 ) {
2009-02-16 12:44:38 +02:00
if ( ! mxf - > edit_unit_byte_count & &
( ! mxf - > edit_units_count | | mxf - > edit_units_count > EDIT_UNITS_PER_BODY ) & &
2016-04-27 19:45:23 +02:00
! ( ie . flags & 0x33 ) ) { // I-frame, GOP start
2009-02-10 11:02:29 +02:00
mxf_write_klv_fill ( s ) ;
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 1 , 2 , body_partition_key , 0 ) ) < 0 )
return err ;
2009-02-10 11:02:29 +02:00
mxf_write_klv_fill ( s ) ;
mxf_write_index_table_segment ( s ) ;
}
2009-02-08 04:34:56 +02:00
mxf_write_klv_fill ( s ) ;
2009-02-10 09:23:51 +02:00
mxf_write_system_item ( s ) ;
2009-02-08 04:34:56 +02:00
2009-02-16 12:44:38 +02:00
if ( ! mxf - > edit_unit_byte_count ) {
mxf - > index_entries [ mxf - > edit_units_count ] . offset = mxf - > body_offset ;
2010-07-02 11:35:47 +03: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 12:44:38 +02:00
mxf - > body_offset + = KAG_SIZE ; // size of system element
}
2009-02-02 12:03:38 +02:00
mxf - > edit_units_count + + ;
2009-02-16 12:44:38 +02:00
} else if ( ! mxf - > edit_unit_byte_count & & st - > index = = 1 ) {
2015-12-13 17:13:22 +02:00
if ( ! mxf - > edit_units_count ) {
av_log ( s , AV_LOG_ERROR , " No packets in first stream \n " ) ;
return AVERROR_PATCHWELCOME ;
}
2009-02-14 00:38:05 +02: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 12:03:38 +02:00
}
2009-02-10 09:23:51 +02:00
mxf_write_klv_fill ( s ) ;
2011-02-21 20:28:17 +02:00
avio_write ( pb , sc - > track_essence_element_key , 16 ) ; // write key
2018-03-21 21:53:56 +02:00
if ( s - > oformat = = & ff_mxf_d10_muxer & &
st - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
mxf_write_d10_audio_packet ( s , st , pkt ) ;
2009-02-16 12:44:38 +02:00
} else {
klv_encode_ber4_length ( pb , pkt - > size ) ; // write length
2011-02-21 20:28:17 +02:00
avio_write ( pb , pkt - > data , pkt - > size ) ;
2009-02-16 12:44:38 +02:00
mxf - > body_offset + = 16 + 4 + pkt - > size + klv_fill_size ( 16 + 4 + pkt - > size ) ;
}
2008-08-25 23:28:12 +03:00
return 0 ;
}
2009-02-02 12:03:38 +02:00
static void mxf_write_random_index_pack ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-03-03 21:11:45 +02:00
uint64_t pos = avio_tell ( pb ) ;
2009-02-10 11:02:29 +02:00
int i ;
2009-02-02 12:03:38 +02:00
2011-02-21 20:28:17 +02:00
avio_write ( pb , random_index_pack_key , 16 ) ;
2012-10-24 18:06:49 +03:00
klv_encode_ber_length ( pb , 28 + 12LL * mxf - > body_partitions_count ) ;
2009-02-02 12:03:38 +02:00
2015-01-29 05:44:21 +02:00
if ( mxf - > edit_unit_byte_count & & s - > oformat ! = & ff_mxf_opatom_muxer )
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 1 ) ; // BodySID of header partition
2009-02-18 03:05:06 +02:00
else
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 0 ) ;
avio_wb64 ( pb , 0 ) ; // offset of header partition
2009-02-02 12:03:38 +02:00
2009-02-10 11:02:29 +02:00
for ( i = 0 ; i < mxf - > body_partitions_count ; i + + ) {
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 1 ) ; // BodySID
avio_wb64 ( pb , mxf - > body_partition_offset [ i ] ) ;
2009-02-10 11:02:29 +02:00
}
2011-02-21 20:28:17 +02:00
avio_wb32 ( pb , 0 ) ; // BodySID of footer partition
avio_wb64 ( pb , mxf - > footer_partition_offset ) ;
2009-02-02 12:03:38 +02:00
2011-03-03 21:11:45 +02:00
avio_wb32 ( pb , avio_tell ( pb ) - pos + 4 ) ;
2009-02-02 12:03:38 +02:00
}
2008-08-31 05:50:25 +03:00
static int mxf_write_footer ( AVFormatContext * s )
2008-08-22 07:12:52 +03:00
{
2008-08-31 06:36:25 +03:00
MXFContext * mxf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2020-01-26 12:27:38 +02:00
int i , err ;
2009-02-07 04:13:23 +02:00
2015-03-18 22:57:58 +02: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 */
2020-01-26 12:27:38 +02:00
return AVERROR_UNKNOWN ;
2015-03-18 22:57:58 +02:00
}
2009-02-11 09:18:00 +02:00
mxf - > duration = mxf - > last_indexed_edit_unit + mxf - > edit_units_count ;
2009-02-07 04:13:23 +02:00
mxf_write_klv_fill ( s ) ;
2011-03-03 21:11:45 +02:00
mxf - > footer_partition_offset = avio_tell ( pb ) ;
2015-01-29 05:44:21 +02:00
if ( mxf - > edit_unit_byte_count & & s - > oformat ! = & ff_mxf_opatom_muxer ) { // no need to repeat index
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 0 , 0 , footer_partition_key , 0 ) ) < 0 )
2020-01-26 12:27:38 +02:00
return err ;
2009-02-13 09:28:20 +02:00
} else {
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 0 , 2 , footer_partition_key , 0 ) ) < 0 )
2020-01-26 12:27:38 +02:00
return err ;
2009-02-13 09:34:01 +02:00
mxf_write_klv_fill ( s ) ;
mxf_write_index_table_segment ( s ) ;
2009-02-13 09:28:20 +02:00
}
2009-02-02 12:03:38 +02:00
2009-02-10 07:35:28 +02:00
mxf_write_klv_fill ( s ) ;
2009-02-02 12:03:38 +02:00
mxf_write_random_index_pack ( s ) ;
2016-09-27 16:26:37 +02:00
if ( s - > pb - > seekable & AVIO_SEEKABLE_NORMAL ) {
2017-09-14 16:05:31 +02:00
if ( s - > oformat = = & ff_mxf_opatom_muxer ) {
2015-01-29 05:44:21 +02:00
/* 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 )
2020-01-26 12:27:38 +02:00
return err ;
2015-01-29 05:44:21 +02:00
}
2011-02-28 15:57:54 +02:00
avio_seek ( pb , 0 , SEEK_SET ) ;
2015-01-29 05:44:21 +02:00
if ( mxf - > edit_unit_byte_count & & s - > oformat ! = & ff_mxf_opatom_muxer ) {
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 1 , 2 , header_closed_partition_key , 1 ) ) < 0 )
2020-01-26 12:27:38 +02:00
return err ;
2009-02-13 09:28:20 +02:00
mxf_write_klv_fill ( s ) ;
mxf_write_index_table_segment ( s ) ;
2009-02-16 12:44:38 +02:00
} else {
2013-08-02 20:21:24 +03:00
if ( ( err = mxf_write_partition ( s , 0 , 0 , header_closed_partition_key , 1 ) ) < 0 )
2020-01-26 12:27:38 +02:00
return err ;
2009-02-13 09:28:20 +02:00
}
2018-03-21 21:59:11 +02:00
// update footer partition offset
for ( i = 0 ; i < mxf - > body_partitions_count ; i + + ) {
avio_seek ( pb , mxf - > body_partition_offset [ i ] + 44 , SEEK_SET ) ;
avio_wb64 ( pb , mxf - > footer_partition_offset ) ;
}
2008-08-31 06:36:25 +03:00
}
2009-01-31 13:17:04 +02:00
2020-01-26 12:27:38 +02:00
return 0 ;
}
static void mxf_deinit ( AVFormatContext * s )
{
MXFContext * mxf = s - > priv_data ;
2009-01-31 13:17:04 +02:00
ff_audio_interleave_close ( s ) ;
2009-02-08 06:35:36 +02:00
av_freep ( & mxf - > index_entries ) ;
2009-02-10 11:02:29 +02:00
av_freep ( & mxf - > body_partition_offset ) ;
2020-01-26 12:27:38 +02:00
if ( mxf - > timecode_track ) {
av_freep ( & mxf - > timecode_track - > priv_data ) ;
av_freep ( & mxf - > timecode_track ) ;
}
2008-08-19 15:36:17 +03:00
}
2008-08-22 07:12:52 +03:00
2009-01-31 12:51:35 +02:00
static int mxf_interleave_get_packet ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush )
2009-01-31 08:18:25 +02:00
{
2010-01-29 08:38:00 +02:00
int i , stream_count = 0 ;
for ( i = 0 ; i < s - > nb_streams ; i + + )
stream_count + = ! ! s - > streams [ i ] - > last_in_packet_buffer ;
2009-01-31 08:18:25 +02:00
if ( stream_count & & ( s - > nb_streams = = stream_count | | flush ) ) {
2015-02-06 15:53:40 +02:00
AVPacketList * pktl = s - > internal - > packet_buffer ;
2009-02-02 12:04:36 +02:00
if ( s - > nb_streams ! = stream_count ) {
2009-02-12 07:32:40 +02:00
AVPacketList * last = NULL ;
2009-02-16 03:51:52 +02:00
// find last packet in edit unit
2009-02-02 12:04:36 +02:00
while ( pktl ) {
2009-02-16 03:51:52 +02:00
if ( ! stream_count | | pktl - > pkt . stream_index = = 0 )
2009-02-02 12:04:36 +02:00
break ;
2018-04-30 03:44:59 +02:00
// update last packet in packet buffer
if ( s - > streams [ pktl - > pkt . stream_index ] - > last_in_packet_buffer ! = pktl )
s - > streams [ pktl - > pkt . stream_index ] - > last_in_packet_buffer = pktl ;
2009-02-12 07:32:40 +02:00
last = pktl ;
2009-02-02 12:04:36 +02:00
pktl = pktl - > next ;
2009-02-16 03:51:52 +02:00
stream_count - - ;
2009-02-02 12:04:36 +02:00
}
2009-01-31 08:18:25 +02:00
// purge packet queue
while ( pktl ) {
AVPacketList * next = pktl - > next ;
2015-10-23 11:11:31 +02:00
av_packet_unref ( & pktl - > pkt ) ;
2009-01-31 08:18:25 +02:00
av_freep ( & pktl ) ;
pktl = next ;
}
2009-02-16 03:51:52 +02:00
if ( last )
last - > next = NULL ;
else {
2015-02-06 15:53:40 +02:00
s - > internal - > packet_buffer = NULL ;
s - > internal - > packet_buffer_end = NULL ;
2009-02-02 12:04:36 +02:00
goto out ;
2009-02-16 03:51:52 +02:00
}
2015-02-06 15:53:40 +02:00
pktl = s - > internal - > packet_buffer ;
2009-01-31 08:18:25 +02:00
}
2009-02-02 12:04:36 +02:00
* out = pktl - > pkt ;
2015-03-16 10:57:35 +02:00
av_log ( s , AV_LOG_TRACE , " out st:%d dts:% " PRId64 " \n " , ( * out ) . stream_index , ( * out ) . dts ) ;
2015-02-06 15:53:40 +02:00
s - > internal - > packet_buffer = pktl - > next ;
2009-09-16 23:04:04 +03: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 15:53:40 +02:00
if ( ! s - > internal - > packet_buffer )
s - > internal - > packet_buffer_end = NULL ;
2009-02-02 12:04:36 +02:00
av_freep ( & pktl ) ;
2009-01-31 08:18:25 +02:00
return 1 ;
} else {
2009-02-02 12:04:36 +02:00
out :
2009-01-31 08:18:25 +02:00
av_init_packet ( out ) ;
return 0 ;
}
}
2019-08-13 04:47:16 +02:00
static int mxf_compare_timestamps ( AVFormatContext * s , const AVPacket * next ,
const AVPacket * pkt )
2009-01-31 08:18:25 +02:00
{
2009-02-04 06:50:47 +02:00
MXFStreamContext * sc = s - > streams [ pkt - > stream_index ] - > priv_data ;
MXFStreamContext * sc2 = s - > streams [ next - > stream_index ] - > priv_data ;
2009-01-31 08:18:25 +02:00
2009-02-04 06:50:47 +02:00
return next - > dts > pkt - > dts | |
( next - > dts = = pkt - > dts & & sc - > order < sc2 - > order ) ;
2009-01-31 08:18:25 +02:00
}
static int mxf_interleave ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush )
{
2009-02-09 23:34:20 +02:00
return ff_audio_rechunk_interleave ( s , out , pkt , flush ,
2009-02-08 06:31:44 +02:00
mxf_interleave_get_packet , mxf_compare_timestamps ) ;
2009-01-31 08:18:25 +02:00
}
2015-06-06 03:06:12 +02:00
# define MXF_COMMON_OPTIONS \
2018-12-17 22:06:36 +02:00
{ " signal_standard " , " Force/set Signal Standard " , \
2015-06-06 03:06:12 +02:00
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-11-09 15:24:26 +02:00
{ " store_user_comments " , " " ,
offsetof ( MXFContext , store_user_comments ) , AV_OPT_TYPE_BOOL , { . i64 = 1 } , 0 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
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 ,
} ;
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
static const AVOption d10_options [ ] = {
2014-06-26 19:10:45 +03:00
{ " d10_channelcount " , " Force/set channelcount in generic sound essence descriptor " ,
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03: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
2015-11-09 15:24:26 +02:00
{ " store_user_comments " , " " ,
offsetof ( MXFContext , store_user_comments ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03: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-12 02:18:13 +02: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
2019-03-11 22:22:37 +02:00
{ " store_user_comments " , " " ,
offsetof ( MXFContext , store_user_comments ) , AV_OPT_TYPE_BOOL , { . i64 = 1 } , 0 , 1 , AV_OPT_FLAG_ENCODING_PARAM } ,
2015-04-12 02:18:13 +02: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-26 00:03:28 +02:00
AVOutputFormat ff_mxf_muxer = {
2011-07-16 23:18:12 +03:00
. name = " mxf " ,
2012-07-24 04:23:48 +03:00
. long_name = NULL_IF_CONFIG_SMALL ( " MXF (Material eXchange Format) " ) ,
2011-07-16 23:18:12 +03:00
. mime_type = " application/mxf " ,
. extensions = " mxf " ,
. priv_data_size = sizeof ( MXFContext ) ,
2012-08-05 12:11:04 +03:00
. audio_codec = AV_CODEC_ID_PCM_S16LE ,
. video_codec = AV_CODEC_ID_MPEG2VIDEO ,
2011-07-16 23:18:12 +03:00
. write_header = mxf_write_header ,
. write_packet = mxf_write_packet ,
. write_trailer = mxf_write_footer ,
2020-01-26 12:27:38 +02:00
. deinit = mxf_deinit ,
2011-07-16 23:18:12 +03:00
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
2015-05-22 14:02:51 +02:00
. priv_class = & mxf_muxer_class ,
2008-08-15 00:48:02 +03:00
} ;
2009-02-13 09:28:20 +02:00
2011-01-26 00:03:28 +02:00
AVOutputFormat ff_mxf_d10_muxer = {
2011-07-16 23:18:12 +03:00
. name = " mxf_d10 " ,
2012-07-24 04:23:48 +03:00
. long_name = NULL_IF_CONFIG_SMALL ( " MXF (Material eXchange Format) D-10 Mapping " ) ,
2011-07-16 23:18:12 +03:00
. mime_type = " application/mxf " ,
. priv_data_size = sizeof ( MXFContext ) ,
2012-08-05 12:11:04 +03:00
. audio_codec = AV_CODEC_ID_PCM_S16LE ,
. video_codec = AV_CODEC_ID_MPEG2VIDEO ,
2011-07-16 23:18:12 +03:00
. write_header = mxf_write_header ,
. write_packet = mxf_write_packet ,
. write_trailer = mxf_write_footer ,
2020-01-26 12:27:38 +02:00
. deinit = mxf_deinit ,
2011-07-16 23:18:12 +03:00
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
avformat/mxfenc: set/force channelcount in MXF D-10
There are interoperability issues with D-10 related to the channelcount property in the generic sound essence descriptor.
On one side, SMPTE 386M requires channel count to be 4 or 8, other values being prohibited.
The most widespread value is 8, which seems straightforward as it is the actual size of the allocated structure/disk space.
At the end, it appears that some vendors or workflows do require this descriptor to be 8, and otherwise just "fail".
On the other side, at least AVID and ffmpeg do write/set the channel count to the exact number of channels really "used",
usually 2 or 4, or any other value. And on the decoding side, ffmpeg (for example) make use of the channel count for probing
and only expose this limited number of audio streams
(which make sense but has strong impact on ffmpeg command line usage, output, and downstream workflow).
At the end, I find it pretty usefull to simply give ffmpeg the ability to force/set the channel count to any value the user wants.
(there are turnaround using complex filters, pans, amerge etc., but it is quite boring and requires the command line to be adapted to the input file properties)
Reviewed-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
2014-06-25 13:29:30 +03:00
. priv_class = & mxf_d10_muxer_class ,
2009-02-13 09:28:20 +02:00
} ;
2015-01-29 05:44:21 +02: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 ,
2020-01-26 12:27:38 +02:00
. deinit = mxf_deinit ,
2015-01-29 05:44:21 +02:00
. flags = AVFMT_NOTIMESTAMPS ,
. interleave_packet = mxf_interleave ,
2015-04-12 02:18:13 +02:00
. priv_class = & mxf_opatom_muxer_class ,
2015-01-29 05:44:21 +02:00
} ;