AVRational aspect_ratio; ///< display aspect ratio
int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing
int video_bit_rate;
+ int slice_offset;
+ int frame_size; ///< frame size in bytes
+ 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
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
INDEX_DV100_1080_50,
INDEX_DV100_720_60,
INDEX_DV100_720_50,
- INDEX_DNXHD_1080p_10bit_HIGH,
- INDEX_DNXHD_1080p_8bit_MEDIUM,
- INDEX_DNXHD_1080p_8bit_HIGH,
- INDEX_DNXHD_1080i_10bit_HIGH,
- INDEX_DNXHD_1080i_8bit_MEDIUM,
- INDEX_DNXHD_1080i_8bit_HIGH,
- INDEX_DNXHD_720p_10bit,
- INDEX_DNXHD_720p_8bit_HIGH,
- INDEX_DNXHD_720p_8bit_MEDIUM,
- INDEX_DNXHD_720p_8bit_LOW,
+ INDEX_DNXHD,
INDEX_JPEG2000,
INDEX_H264,
+ INDEX_S436M,
+ INDEX_PRORES,
};
static const struct {
{ AV_CODEC_ID_PCM_S24LE, INDEX_AES3 },
{ AV_CODEC_ID_PCM_S16LE, INDEX_AES3 },
{ AV_CODEC_ID_DVVIDEO, INDEX_DV },
- { AV_CODEC_ID_DNXHD, INDEX_DNXHD_1080p_10bit_HIGH },
+ { AV_CODEC_ID_DNXHD, INDEX_DNXHD },
{ AV_CODEC_ID_JPEG2000, INDEX_JPEG2000 },
{ AV_CODEC_ID_H264, INDEX_H264 },
+ { AV_CODEC_ID_PRORES, INDEX_PRORES },
{ AV_CODEC_ID_NONE }
};
static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
+static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x08,0x00 },
mxf_write_cdci_desc },
- // DNxHD 1080p 10bit high
+ // DNxHD
{ { 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 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x01,0x00,0x00 },
mxf_write_cdci_desc },
- // DNxHD 1080p 8bit medium
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x03,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 1080p 8bit high
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x04,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 1080i 10bit high
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x07,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 1080i 8bit medium
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x08,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 1080i 8bit high
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x09,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 720p 10bit
- { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x10,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 720p 8bit high
- { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x11,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 720p 8bit medium
- { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x12,0x00,0x00 },
- mxf_write_cdci_desc },
- // DNxHD 720p 8bit low
- { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
- { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x13,0x00,0x00 },
- mxf_write_cdci_desc },
// 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,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
mxf_write_mpegvideo_desc },
+ // 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 },
+ // 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 },
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
AVStream *timecode_track;
int timecode_base; ///< rounded time code base (25 or 30)
int edit_unit_byte_count; ///< fixed edit unit byte count
+ int content_package_rate; ///< content package rate in system element, see SMPTE 326M
uint64_t body_offset;
uint32_t instance_number;
uint8_t umid[16]; ///< unique material identifier
AVRational audio_edit_rate;
int store_user_comments;
int track_instance_count; // used to generate MXFTrack uuids
+ int cbr_index; ///< use a constant bitrate index
} MXFContext;
static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd };
{ 0x320D, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x03,0x02,0x05,0x00,0x00,0x00}}, /* Video Line Map */
{ 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 */
+ { 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 */
{ 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 */
+ { 0x320A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0D,0x00,0x00,0x00}}, /* Display X offset */
{ 0x320B, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0E,0x00,0x00,0x00}}, /* Presentation Y offset */
+ { 0x3217, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x03,0x02,0x07,0x00,0x00,0x00}}, /* Display F2 offset */
{ 0x320E, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x00,0x00,0x00}}, /* Aspect Ratio */
{ 0x3210, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x02,0x01,0x01,0x01,0x02,0x00}}, /* Transfer characteristic */
{ 0x3213, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x18,0x01,0x02,0x00,0x00,0x00,0x00}}, /* Image Start Offset */
{ 0x3F0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x04,0x04,0x02,0x05,0x00,0x00,0x00}}, /* Index Entry Array */
// MPEG video Descriptor
{ 0x8000, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x0B,0x00,0x00}}, /* BitRate */
+ { 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 */
{ 0x8007, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x0A,0x00,0x00}}, /* ProfileAndLevel */
+ { 0x8008, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x09,0x00,0x00}}, /* BPictureCount */
// 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 */
mxf_write_refs_count(pb, DESCRIPTOR_COUNT(c->essence_container_count));
av_log(s,AV_LOG_DEBUG, "essence container count:%d\n", c->essence_container_count);
- for (i = 0; i < c->essence_container_count; i++) {
+ for (i = 0; i < s->nb_streams; i++) {
MXFStreamContext *sc = s->streams[i]->priv_data;
+ // check first track of essence container type and only write it once
+ if (sc->track_essence_element_key[15] != 0)
+ continue;
avio_write(pb, mxf_essence_container_uls[sc->index].container_ul, 16);
+ if (c->essence_container_count == 1)
+ break;
}
if (c->essence_container_count > 1)
mxf_write_uuid(pb, SubDescriptor, i);
}
-static void mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key, unsigned size)
+static int64_t mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key)
{
MXFContext *mxf = s->priv_data;
MXFStreamContext *sc = st->priv_data;
AVIOContext *pb = s->pb;
+ int64_t pos;
avio_write(pb, key, 16);
- klv_encode_ber4_length(pb, size+20+8+12+20);
+ klv_encode_ber4_length(pb, 0);
+ pos = avio_tell(pb);
mxf_write_local_tag(pb, 16, 0x3C0A);
mxf_write_uuid(pb, SubDescriptor, st->index);
mxf_write_local_tag(pb, 16, 0x3004);
avio_write(pb, mxf_essence_container_uls[sc->index].container_ul, 16);
+
+ return pos;
}
+static const UID mxf_s436m_anc_descriptor_key = { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5c,0x00 };
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 };
static const UID mxf_aes3_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 };
switch (trc){
case AVCOL_TRC_GAMMA28 :
case AVCOL_TRC_GAMMA22 :
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00}), 16);
return 0;
case AVCOL_TRC_BT709 :
case AVCOL_TRC_SMPTE170M :
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00}), 16);
return 0;
case AVCOL_TRC_SMPTE240M :
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00}), 16);
return 0;
case AVCOL_TRC_BT1361_ECG:
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00}), 16);
return 0;
case AVCOL_TRC_LINEAR :
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00}), 16);
return 0;
case AVCOL_TRC_SMPTE428 :
- memcpy(ul, (UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00}, 16);
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00}), 16);
return 0;
default:
return -1;
}
}
-static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size)
+static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key)
{
MXFStreamContext *sc = st->priv_data;
AVIOContext *pb = s->pb;
int stored_height = (st->codecpar->height+15)/16*16;
int display_height;
int f1, f2;
- unsigned desc_size = size+8+8+8+8+8+8+8+5+16+4+12+20+5 + 6;
UID transfer_ul = {0};
+ int64_t pos = mxf_write_generic_desc(s, st, key);
- if (sc->interlaced && sc->field_dominance)
- desc_size += 5;
- if (sc->signal_standard)
- desc_size += 5;
- if (sc->v_chroma_sub_sample)
- desc_size += 8;
- if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED)
- desc_size += 8 * 3;
- if (s->oformat == &ff_mxf_d10_muxer)
- desc_size += 8 + 8 + 8;
- if (get_trc(transfer_ul, st->codecpar->color_trc) >= 0)
- desc_size += 20;
-
- mxf_write_generic_desc(s, st, key, desc_size);
+ get_trc(transfer_ul, st->codecpar->color_trc);
mxf_write_local_tag(pb, 4, 0x3203);
avio_wb32(pb, stored_width);
avio_wb32(pb, 0);
}
+ //Sampled width
+ mxf_write_local_tag(pb, 4, 0x3205);
+ avio_wb32(pb, st->codecpar->width);
+
+ //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);
+
mxf_write_local_tag(pb, 4, 0x3209);
avio_wb32(pb, st->codecpar->width);
mxf_write_local_tag(pb, 4, 0x3208);
avio_wb32(pb, display_height>>sc->interlaced);
- // presentation Y offset
+ // display X offset
+ mxf_write_local_tag(pb, 4, 0x320A);
+ avio_wb32(pb, 0);
+
+ // display Y offset
mxf_write_local_tag(pb, 4, 0x320B);
avio_wb32(pb, (st->codecpar->height - display_height)>>sc->interlaced);
+ if (sc->interlaced) {
+ //Display F2 Offset
+ mxf_write_local_tag(pb, 4, 0x3217);
+ avio_wb32(pb, -((st->codecpar->height - display_height)&1));
+ }
+
// component depth
mxf_write_local_tag(pb, 4, 0x3301);
avio_wb32(pb, sc->component_depth);
avio_wb32(pb, sc->h_chroma_sub_sample);
// vertical subsampling
- if (sc->v_chroma_sub_sample) {
- mxf_write_local_tag(pb, 4, 0x3308);
- avio_wb32(pb, sc->v_chroma_sub_sample);
- }
+ mxf_write_local_tag(pb, 4, 0x3308);
+ avio_wb32(pb, sc->v_chroma_sub_sample);
// color siting
mxf_write_local_tag(pb, 1, 0x3303);
default: f1 = 0; f2 = 0; break;
}
- if (!sc->interlaced) {
+ if (!sc->interlaced && f2) {
f2 = 0;
f1 *= 2;
}
avio_w8(pb, sc->field_dominance);
}
+ 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);
}
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
{
- mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key, 0);
+ int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
+}
+
+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);
}
static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st)
AVIOContext *pb = s->pb;
MXFStreamContext *sc = st->priv_data;
int profile_and_level = (st->codecpar->profile<<4) | st->codecpar->level;
+ int64_t pos = mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key);
if (st->codecpar->codec_id != AV_CODEC_ID_H264) {
- mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5);
-
// bit rate
mxf_write_local_tag(pb, 4, 0x8000);
avio_wb32(pb, sc->video_bit_rate);
if (!st->codecpar->profile)
profile_and_level |= 0x80; // escape bit
avio_w8(pb, profile_and_level);
- } else {
- mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 0);
+
+ // 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);
}
+
+ mxf_update_klv_size(pb, pos);
}
-static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size)
+static int64_t mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key)
{
AVIOContext *pb = s->pb;
MXFContext *mxf = s->priv_data;
int show_warnings = !mxf->footer_partition_offset;
- int duration_size = 0;
-
- if (s->oformat == &ff_mxf_opatom_muxer)
- duration_size = 12;
- if (s->oformat == &ff_mxf_d10_muxer)
- size += 5;
+ int64_t pos = mxf_write_generic_desc(s, st, key);
- mxf_write_generic_desc(s, st, key, size+duration_size+5+12+8+8);
-
- if (duration_size > 0) {
+ if (s->oformat == &ff_mxf_opatom_muxer) {
mxf_write_local_tag(pb, 8, 0x3002);
avio_wb64(pb, mxf->body_offset / mxf->edit_unit_byte_count);
}
mxf_write_local_tag(pb, 4, 0x3D01);
avio_wb32(pb, av_get_bits_per_sample(st->codecpar->codec_id));
+
+ return pos;
}
-static void mxf_write_wav_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size)
+static int64_t mxf_write_wav_common(AVFormatContext *s, AVStream *st, const UID key)
{
AVIOContext *pb = s->pb;
-
- mxf_write_generic_sound_common(s, st, key, size+6+8);
+ int64_t pos = mxf_write_generic_sound_common(s, st, key);
mxf_write_local_tag(pb, 2, 0x3D0A);
avio_wb16(pb, st->codecpar->block_align);
// avg bytes per sec
mxf_write_local_tag(pb, 4, 0x3D09);
avio_wb32(pb, st->codecpar->block_align*st->codecpar->sample_rate);
+
+ return pos;
}
static void mxf_write_wav_desc(AVFormatContext *s, AVStream *st)
{
- mxf_write_wav_common(s, st, mxf_wav_descriptor_key, 0);
+ int64_t pos = mxf_write_wav_common(s, st, mxf_wav_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
}
static void mxf_write_aes3_desc(AVFormatContext *s, AVStream *st)
{
- mxf_write_wav_common(s, st, mxf_aes3_descriptor_key, 0);
+ int64_t pos = mxf_write_wav_common(s, st, mxf_aes3_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
}
static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st)
{
- mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key, 0);
+ int64_t pos = mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
}
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 };
AVIOContext *pb = s->pb;
int i, j, temporal_reordering = 0;
int key_index = mxf->last_key_index;
+ int prev_non_b_picture = 0;
+ int audio_frame_size = 0;
+ int64_t pos;
av_log(s, AV_LOG_DEBUG, "edit units count %d\n", mxf->edit_units_count);
avio_write(pb, index_table_segment_key, 16);
- if (mxf->edit_unit_byte_count) {
- klv_encode_ber_length(pb, 80);
- } else {
- klv_encode_ber_length(pb, 85 + 12+(s->nb_streams+1LL)*6 +
- 12+mxf->edit_units_count*(11+mxf->slice_count*4LL));
- }
+ klv_encode_ber4_length(pb, 0);
+ pos = avio_tell(pb);
// instance id
mxf_write_local_tag(pb, 16, 0x3C0A);
mxf_write_local_tag(pb, 4, 0x3F07);
avio_wb32(pb, 1);
- if (!mxf->edit_unit_byte_count) {
- // real slice count - 1
- mxf_write_local_tag(pb, 1, 0x3F08);
- avio_w8(pb, mxf->slice_count);
-
- // 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
- 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 (i == 0) { // video track
- avio_w8(pb, 0); // slice number
- avio_wb32(pb, KAG_SIZE); // system item size including klv fill
- } else { // audio track
- unsigned audio_frame_size = sc->aic.samples[0]*sc->aic.sample_size;
+ // 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
+ } else { // audio or data track
+ if (!audio_frame_size) {
+ audio_frame_size = sc->aic.samples[0]*sc->aic.sample_size;
audio_frame_size += klv_fill_size(audio_frame_size);
- avio_w8(pb, 1);
- avio_wb32(pb, (i-1)*audio_frame_size); // element delta
}
+ avio_w8(pb, 1);
+ avio_wb32(pb, (i-1)*audio_frame_size); // element delta
}
+ }
- mxf_write_local_tag(pb, 8 + mxf->edit_units_count*(11+mxf->slice_count*4), 0x3F0A);
+ if (!mxf->edit_unit_byte_count) {
+ MXFStreamContext *sc = s->streams[0]->priv_data;
+ mxf_write_local_tag(pb, 8 + mxf->edit_units_count*15, 0x3F0A);
avio_wb32(pb, mxf->edit_units_count); // num of entries
- avio_wb32(pb, 11+mxf->slice_count*4); // size of one entry
+ avio_wb32(pb, 15); // size of one entry
for (i = 0; i < mxf->edit_units_count; i++) {
int temporal_offset = 0;
if (!(mxf->index_entries[i].flags & 0x33)) { // I-frame
+ sc->max_gop = FFMAX(sc->max_gop, i - mxf->last_key_index);
mxf->last_key_index = key_index;
key_index = i;
}
avio_w8(pb, temporal_offset);
if ((mxf->index_entries[i].flags & 0x30) == 0x30) { // back and forward prediction
+ sc->b_picture_count = FFMAX(sc->b_picture_count, i - prev_non_b_picture);
avio_w8(pb, mxf->last_key_index - i);
} else {
avio_w8(pb, key_index - i); // key frame offset
if ((mxf->index_entries[i].flags & 0x20) == 0x20) // only forward
mxf->last_key_index = key_index;
+ prev_non_b_picture = i;
}
if (!(mxf->index_entries[i].flags & 0x33) && // I-frame
avio_wb64(pb, mxf->index_entries[i].offset);
if (s->nb_streams > 1)
avio_wb32(pb, mxf->index_entries[i].slice_offset);
+ else
+ avio_wb32(pb, 0);
}
mxf->last_key_index = key_index - mxf->edit_units_count;
mxf->last_indexed_edit_unit += mxf->edit_units_count;
mxf->edit_units_count = 0;
}
+
+ mxf_update_klv_size(pb, pos);
}
static void mxf_write_klv_fill(AVFormatContext *s)
if (!mxf->edit_unit_byte_count && mxf->edit_units_count)
index_byte_count = 85 + 12+(s->nb_streams+1)*6 +
- 12+mxf->edit_units_count*(11+mxf->slice_count*4);
+ 12+mxf->edit_units_count*15;
else if (mxf->edit_unit_byte_count && indexsid)
index_byte_count = 80;
else
avio_write(pb, body_partition_key, 16);
- klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
+ klv_encode_ber4_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
// write partition value
avio_wb16(pb, 1); // majorVersion
return 0;
}
-static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st,
-AVPacket *pkt)
+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, cid;
- uint8_t* header_cid;
- int frame_size = 0;
+ int i, profile;
if (mxf->header_written)
return 1;
- if (pkt->size < 43)
- 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;
- header_cid = pkt->data + 0x28;
- cid = header_cid[0] << 24 | header_cid[1] << 16 | header_cid[2] << 8 | header_cid[3];
+ sc->frame_size = pkt->size;
- if ((frame_size = avpriv_dnxhd_get_frame_size(cid)) < 0)
- return -1;
- if ((sc->interlaced = avpriv_dnxhd_get_interlaced(cid)) < 0)
- return AVERROR_INVALIDDATA;
+ return 1;
+}
- switch (cid) {
- case 1235:
- sc->index = INDEX_DNXHD_1080p_10bit_HIGH;
- sc->component_depth = 10;
- break;
- case 1237:
- sc->index = INDEX_DNXHD_1080p_8bit_MEDIUM;
- break;
- case 1238:
- sc->index = INDEX_DNXHD_1080p_8bit_HIGH;
- break;
- case 1241:
- sc->index = INDEX_DNXHD_1080i_10bit_HIGH;
- sc->component_depth = 10;
- break;
- case 1242:
- sc->index = INDEX_DNXHD_1080i_8bit_MEDIUM;
- break;
- case 1243:
- sc->index = INDEX_DNXHD_1080i_8bit_HIGH;
- break;
- case 1250:
- sc->index = INDEX_DNXHD_720p_10bit;
- sc->component_depth = 10;
- break;
- case 1251:
- sc->index = INDEX_DNXHD_720p_8bit_HIGH;
- break;
- case 1252:
- sc->index = INDEX_DNXHD_720p_8bit_MEDIUM;
- break;
- case 1253:
- sc->index = INDEX_DNXHD_720p_8bit_LOW;
- break;
- default:
- return -1;
- }
+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
+};
- sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
- sc->aspect_ratio = (AVRational){ 16, 9 };
+static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ int i, cid, frame_size = 0;
- if (s->oformat == &ff_mxf_opatom_muxer) {
- mxf->edit_unit_byte_count = frame_size;
+ if (mxf->header_written)
return 1;
- }
- mxf->edit_unit_byte_count = KAG_SIZE;
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- MXFStreamContext *sc = st->priv_data;
- if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
- mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size;
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
- } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
- mxf->edit_unit_byte_count += 16 + 4 + frame_size;
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
+ if (pkt->size < 43)
+ return 0;
+
+ 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;
+
+ 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)
+ return 0;
+
+ if ((sc->interlaced = avpriv_dnxhd_get_interlaced(cid)) < 0)
+ return 0;
+
+ 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 };
+ }
+
+ sc->frame_size = pkt->size;
return 1;
}
MXFContext *mxf = s->priv_data;
MXFStreamContext *sc = st->priv_data;
uint8_t *vs_pack, *vsc_pack;
- int i, ul_index, frame_size, stype, pal;
+ int ul_index, stype, pal;
const AVDVProfile *profile;
if (mxf->header_written)
switch (stype) {
case 0x18: // DV100 720p
ul_index = INDEX_DV100_720_50 + pal;
- frame_size = pal ? 288000 : 240000;
if (sc->interlaced) {
av_log(s, AV_LOG_ERROR, "source marked as interlaced but codec profile is progressive\n");
sc->interlaced = 0;
break;
case 0x14: // DV100 1080i
ul_index = INDEX_DV100_1080_50 + pal;
- frame_size = pal ? 576000 : 480000;
break;
case 0x04: // DV50
ul_index = INDEX_DV50_525_60 + pal;
- frame_size = pal ? 288000 : 240000;
break;
default: // DV25
if (profile && profile->pix_fmt == AV_PIX_FMT_YUV420P && pal) {
ul_index = INDEX_DV25_525_60_IEC + pal;
- frame_size = pal ? 144000 : 120000;
break;
}
ul_index = INDEX_DV25_525_60 + pal;
- frame_size = pal ? 144000 : 120000;
}
sc->index = ul_index;
sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
-
- if(s->oformat == &ff_mxf_opatom_muxer) {
- mxf->edit_unit_byte_count = frame_size;
- return 1;
- }
-
- mxf->edit_unit_byte_count = KAG_SIZE;
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- MXFStreamContext *sc = st->priv_data;
- if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
- mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size;
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
- } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
- mxf->edit_unit_byte_count += 16 + 4 + frame_size;
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
- }
- }
+ sc->frame_size = pkt->size;
return 1;
}
if ((pkt->data[i+1] & 0xf0) == 0x10) { // seq ext
st->codecpar->profile = pkt->data[i+1] & 0x07;
st->codecpar->level = pkt->data[i+2] >> 4;
+ sc->low_delay = pkt->data[i+6] >> 7;
} else if (i + 5 < pkt->size && (pkt->data[i+1] & 0xf0) == 0x80) { // pict coding ext
sc->interlaced = !(pkt->data[i+5] & 0x80); // progressive frame
if (sc->interlaced)
}
} else if (c == 0x1b8) { // gop
if (pkt->data[i+4]>>6 & 0x01) { // closed
+ if (sc->seq_closed_gop == -1)
+ sc->seq_closed_gop = 1;
sc->closed_gop = 1;
if (e->flags & 0x40) // sequence header present
e->flags |= 0x80; // random access
+ } else {
+ sc->seq_closed_gop = 0;
+ sc->closed_gop = 0;
}
} else if (c == 0x1b3) { // seq
e->flags |= 0x40;
return !!sc->codec_ul;
}
-static uint64_t mxf_parse_timestamp(time_t timestamp)
+static uint64_t mxf_parse_timestamp(int64_t timestamp64)
{
+ time_t timestamp = timestamp64 / 1000000;
struct tm tmbuf;
struct tm *time = gmtime_r(×tamp, &tmbuf);
if (!time)
(uint64_t) time->tm_mday << 32 |
time->tm_hour << 24 |
time->tm_min << 16 |
- time->tm_sec << 8;
+ time->tm_sec << 8 |
+ (timestamp64 % 1000000) / 4000;
}
static void mxf_gen_umid(AVFormatContext *s)
// Default component depth to 8
sc->component_depth = 8;
sc->h_chroma_sub_sample = 2;
+ sc->v_chroma_sub_sample = 2;
sc->color_siting = 0xFF;
+ 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));
+ }
+
if (pix_desc) {
sc->component_depth = pix_desc->comp[0].depth;
sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
tbc.den, tbc.num);
return AVERROR(EINVAL);
}
+ mxf->content_package_rate = ff_mxf_get_content_package_rate(tbc);
mxf->time_base = spf->time_base;
rate = av_inv_q(mxf->time_base);
avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den);
if((ret = mxf_init_timecode(s, st, rate)) < 0)
return ret;
+ if (st->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ sc->seq_closed_gop = -1; // unknown yet
+ }
+
sc->video_bit_rate = st->codecpar->bit_rate;
+
+ 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;
+
if (s->oformat == &ff_mxf_d10_muxer) {
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 -1;
}
- mxf->edit_unit_byte_count = KAG_SIZE; // system element
- mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)sc->video_bit_rate *
- mxf->time_base.num / (8*mxf->time_base.den);
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
- mxf->edit_unit_byte_count += 16 + 4 + 4 + spf->samples_per_frame[0]*8*4;
- mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
-
sc->signal_standard = 1;
+ sc->color_siting = 0;
+ sc->frame_size = (int64_t)sc->video_bit_rate *
+ mxf->time_base.num / (8*mxf->time_base.den);
}
if (mxf->signal_standard >= 0)
sc->signal_standard = mxf->signal_standard;
av_log(s, AV_LOG_ERROR, "MXF D-10 only support 16 or 24 bits le audio\n");
}
sc->index = ((MXFStreamContext*)s->streams[0]->priv_data)->index + 1;
+ sc->frame_size = 4 + 8 * spf[0].samples_per_frame[0] * 4;
} else if (s->oformat == &ff_mxf_opatom_muxer) {
AVRational tbc = av_inv_q(mxf->audio_edit_rate);
sc->index = INDEX_WAV;
} else {
mxf->slice_count = 1;
+ sc->frame_size = (st->codecpar->channels * spf[0].samples_per_frame[0] *
+ av_get_bits_per_sample(st->codecpar->codec_id)) / 8;
+ }
+ } 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")) {
+ sc->index = INDEX_S436M;
+ } 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;
}
}
sc->order = AV_RB32(sc->track_essence_element_key+12);
}
- if (ff_parse_creation_time_metadata(s, ×tamp, 1) > 0)
+ if (ff_parse_creation_time_metadata(s, ×tamp, 0) > 0)
mxf->timestamp = mxf_parse_timestamp(timestamp);
mxf->duration = -1;
AVIOContext *pb = s->pb;
unsigned frame;
uint32_t time_code;
+ int i, system_item_bitmap = 0x58; // UL, user date/time stamp, picture present
frame = mxf->last_indexed_edit_unit + mxf->edit_units_count;
// write system metadata pack
avio_write(pb, system_metadata_pack_key, 16);
klv_encode_ber4_length(pb, 57);
- avio_w8(pb, 0x5c); // UL, user date/time stamp, picture and sound item present
- avio_w8(pb, 0x04); // content package rate
+
+ 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);
+ avio_w8(pb, mxf->content_package_rate); // content package rate
avio_w8(pb, 0x00); // content package type
avio_wb16(pb, 0x00); // channel handle
avio_wb16(pb, (mxf->tc.start + frame) & 0xFFFF); // continuity count, supposed to overflow
mxf_write_umid(s, 1);
}
-static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt)
-{
- MXFContext *mxf = s->priv_data;
- AVIOContext *pb = s->pb;
- MXFStreamContext *sc = st->priv_data;
- int packet_size = (uint64_t)sc->video_bit_rate*mxf->time_base.num /
- (8*mxf->time_base.den); // frame size
- int pad;
-
- packet_size += 16 + 4;
- packet_size += klv_fill_size(packet_size);
-
- klv_encode_ber4_length(pb, pkt->size);
- avio_write(pb, pkt->data, pkt->size);
-
- // ensure CBR muxing by padding to correct video frame size
- pad = packet_size - pkt->size - 16 - 4;
- if (pad > 20) {
- avio_write(s->pb, klv_fill_key, 16);
- pad -= 16 + 4;
- klv_encode_ber4_length(s->pb, pad);
- ffio_fill(s->pb, 0, pad);
- av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
- } else {
- av_log(s, AV_LOG_WARNING, "cannot fill d-10 video packet\n");
- ffio_fill(s->pb, 0, pad);
- }
-}
-
static void mxf_write_d10_audio_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
MXFContext *mxf = s->priv_data;
return 0;
}
+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);
+ }
+}
+
static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MXFContext *mxf = s->priv_data;
MXFIndexEntry ie = {0};
int err;
- if (!mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) {
+ if (!mxf->cbr_index && !mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) {
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;
av_log(s, AV_LOG_ERROR, "could not get dnxhd profile\n");
return -1;
}
+ } 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;
+ }
} else if (st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO) {
if (!mxf_parse_dv_frame(s, st, pkt)) {
av_log(s, AV_LOG_ERROR, "could not get dv profile\n");
}
}
+ 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);
+ }
+
if (s->oformat == &ff_mxf_opatom_muxer)
return mxf_write_opatom_packet(s, pkt, &ie);
mxf_write_klv_fill(s);
avio_write(pb, sc->track_essence_element_key, 16); // write key
- if (s->oformat == &ff_mxf_d10_muxer) {
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
- mxf_write_d10_video_packet(s, st, pkt);
- else
- mxf_write_d10_audio_packet(s, st, pkt);
+ if (s->oformat == &ff_mxf_d10_muxer &&
+ st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ mxf_write_d10_audio_packet(s, st, pkt);
} else {
klv_encode_ber4_length(pb, pkt->size); // write length
avio_write(pb, pkt->data, pkt->size);
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- int err = 0;
+ int i, err = 0;
if (!mxf->header_written ||
(s->oformat == &ff_mxf_opatom_muxer && !mxf->body_partition_offset)) {
if ((err = mxf_write_partition(s, 0, 0, header_closed_partition_key, 1)) < 0)
goto end;
}
+ // 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);
+ }
}
end:
while (pktl) {
if (!stream_count || pktl->pkt.stream_index == 0)
break;
+ // 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;
last = pktl;
pktl = pktl->next;
stream_count--;
// purge packet queue
while (pktl) {
AVPacketList *next = pktl->next;
-
- if(s->streams[pktl->pkt.stream_index]->last_in_packet_buffer == pktl)
- s->streams[pktl->pkt.stream_index]->last_in_packet_buffer= NULL;
av_packet_unref(&pktl->pkt);
av_freep(&pktl);
pktl = next;
}
#define MXF_COMMON_OPTIONS \
- { "signal_standard", "Force/set Sigal Standard",\
+ { "signal_standard", "Force/set Signal Standard",\
offsetof(MXFContext, signal_standard), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\
{ "bt601", "ITU-R BT.601 and BT.656, also SMPTE 125M (525 and 625 line interlaced)",\
0, AV_OPT_TYPE_CONST, {.i64 = 1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\