mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-28 12:32:17 +02:00
libavformat/mxfenc.c: added mxf opatom muxer
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
7c148f30f3
commit
6a8a3bfb87
@ -206,6 +206,7 @@ void av_register_all(void)
|
|||||||
REGISTER_DEMUXER (MVI, mvi);
|
REGISTER_DEMUXER (MVI, mvi);
|
||||||
REGISTER_MUXDEMUX(MXF, mxf);
|
REGISTER_MUXDEMUX(MXF, mxf);
|
||||||
REGISTER_MUXER (MXF_D10, mxf_d10);
|
REGISTER_MUXER (MXF_D10, mxf_d10);
|
||||||
|
REGISTER_MUXER (MXF_OPATOM, mxf_opatom);
|
||||||
REGISTER_DEMUXER (MXG, mxg);
|
REGISTER_DEMUXER (MXG, mxg);
|
||||||
REGISTER_DEMUXER (NC, nc);
|
REGISTER_DEMUXER (NC, nc);
|
||||||
REGISTER_DEMUXER (NISTSPHERE, nistsphere);
|
REGISTER_DEMUXER (NISTSPHERE, nistsphere);
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
extern AVOutputFormat ff_mxf_d10_muxer;
|
extern AVOutputFormat ff_mxf_d10_muxer;
|
||||||
|
extern AVOutputFormat ff_mxf_opatom_muxer;
|
||||||
|
|
||||||
#define EDIT_UNITS_PER_BODY 250
|
#define EDIT_UNITS_PER_BODY 250
|
||||||
#define KAG_SIZE 512
|
#define KAG_SIZE 512
|
||||||
@ -320,6 +321,7 @@ static const uint8_t umid_ul[] = { 0x06,0x0A,0x2B,0x34,0x01,0x01,0x
|
|||||||
* complete key for operation pattern, partitions, and primer pack
|
* complete key for operation pattern, partitions, and primer pack
|
||||||
*/
|
*/
|
||||||
static const uint8_t op1a_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x01,0x09,0x00 };
|
static const uint8_t op1a_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x01,0x09,0x00 };
|
||||||
|
static const uint8_t opatom_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x02,0x01,0x10,0x03,0x00,0x00 };
|
||||||
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 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 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 index_table_segment_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 };
|
||||||
@ -483,6 +485,12 @@ static void klv_encode_ber4_length(AVIOContext *pb, int len)
|
|||||||
avio_wb24(pb, len);
|
avio_wb24(pb, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void klv_encode_ber9_length(AVIOContext *pb, uint64_t len)
|
||||||
|
{
|
||||||
|
avio_w8(pb, 0x80 + 8);
|
||||||
|
avio_wb64(pb, len);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get essence container ul index
|
* Get essence container ul index
|
||||||
*/
|
*/
|
||||||
@ -601,7 +609,10 @@ static void mxf_write_preface(AVFormatContext *s)
|
|||||||
|
|
||||||
// operational pattern
|
// operational pattern
|
||||||
mxf_write_local_tag(pb, 16, 0x3B09);
|
mxf_write_local_tag(pb, 16, 0x3B09);
|
||||||
avio_write(pb, op1a_ul, 16);
|
if (s->oformat == &ff_mxf_opatom_muxer)
|
||||||
|
avio_write(pb, opatom_ul, 16);
|
||||||
|
else
|
||||||
|
avio_write(pb, op1a_ul, 16);
|
||||||
|
|
||||||
// write essence_container_refs
|
// write essence_container_refs
|
||||||
mxf_write_local_tag(pb, 8 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count), 0x3B0A);
|
mxf_write_local_tag(pb, 8 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count), 0x3B0A);
|
||||||
@ -1362,7 +1373,7 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
|
|||||||
index_byte_count += klv_fill_size(index_byte_count);
|
index_byte_count += klv_fill_size(index_byte_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memcmp(key, body_partition_key, 16)) {
|
if (key && !memcmp(key, body_partition_key, 16)) {
|
||||||
if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1,
|
if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1,
|
||||||
sizeof(*mxf->body_partition_offset))) < 0) {
|
sizeof(*mxf->body_partition_offset))) < 0) {
|
||||||
mxf->body_partitions_count = 0;
|
mxf->body_partitions_count = 0;
|
||||||
@ -1372,7 +1383,11 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write klv
|
// write klv
|
||||||
avio_write(pb, key, 16);
|
if (key)
|
||||||
|
avio_write(pb, key, 16);
|
||||||
|
else
|
||||||
|
avio_write(pb, body_partition_key, 16);
|
||||||
|
|
||||||
klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
|
klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
|
||||||
|
|
||||||
// write partition value
|
// write partition value
|
||||||
@ -1382,9 +1397,9 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
|
|||||||
|
|
||||||
avio_wb64(pb, partition_offset); // ThisPartition
|
avio_wb64(pb, partition_offset); // ThisPartition
|
||||||
|
|
||||||
if (!memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
|
if (key && !memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
|
||||||
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-2]); // PreviousPartition
|
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-2]); // PreviousPartition
|
||||||
else if (!memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
|
else if (key && !memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
|
||||||
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-1]); // PreviousPartition
|
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-1]); // PreviousPartition
|
||||||
else
|
else
|
||||||
avio_wb64(pb, 0);
|
avio_wb64(pb, 0);
|
||||||
@ -1400,15 +1415,18 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
|
|||||||
avio_wb32(pb, index_byte_count ? indexsid : 0); // indexSID
|
avio_wb32(pb, index_byte_count ? indexsid : 0); // indexSID
|
||||||
|
|
||||||
// BodyOffset
|
// BodyOffset
|
||||||
if (bodysid && mxf->edit_units_count && mxf->body_partitions_count) {
|
if (bodysid && mxf->edit_units_count && mxf->body_partitions_count && s->oformat != &ff_mxf_opatom_muxer)
|
||||||
avio_wb64(pb, mxf->body_offset);
|
avio_wb64(pb, mxf->body_offset);
|
||||||
} else
|
else
|
||||||
avio_wb64(pb, 0);
|
avio_wb64(pb, 0);
|
||||||
|
|
||||||
avio_wb32(pb, bodysid); // bodySID
|
avio_wb32(pb, bodysid); // bodySID
|
||||||
|
|
||||||
// operational pattern
|
// operational pattern
|
||||||
avio_write(pb, op1a_ul, 16);
|
if (s->oformat == &ff_mxf_opatom_muxer)
|
||||||
|
avio_write(pb, opatom_ul, 16);
|
||||||
|
else
|
||||||
|
avio_write(pb, op1a_ul, 16);
|
||||||
|
|
||||||
// essence container
|
// essence container
|
||||||
mxf_write_essence_container_refs(s);
|
mxf_write_essence_container_refs(s);
|
||||||
@ -1431,7 +1449,8 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
|
|||||||
avio_seek(pb, pos, SEEK_SET);
|
avio_seek(pb, pos, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
avio_flush(pb);
|
if(key)
|
||||||
|
avio_flush(pb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1498,6 +1517,11 @@ AVPacket *pkt)
|
|||||||
sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
|
sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
|
||||||
sc->aspect_ratio = (AVRational){ 16, 9 };
|
sc->aspect_ratio = (AVRational){ 16, 9 };
|
||||||
|
|
||||||
|
if(s->oformat == &ff_mxf_opatom_muxer){
|
||||||
|
mxf->edit_unit_byte_count = frame_size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
mxf->edit_unit_byte_count = KAG_SIZE;
|
mxf->edit_unit_byte_count = KAG_SIZE;
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVStream *st = s->streams[i];
|
AVStream *st = s->streams[i];
|
||||||
@ -1568,6 +1592,11 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
|
|||||||
sc->index = ul_index + 16;
|
sc->index = ul_index + 16;
|
||||||
sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
|
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;
|
mxf->edit_unit_byte_count = KAG_SIZE;
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVStream *st = s->streams[i];
|
AVStream *st = s->streams[i];
|
||||||
@ -1803,6 +1832,11 @@ static int mxf_write_header(AVFormatContext *s)
|
|||||||
if (!s->nb_streams)
|
if (!s->nb_streams)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (s->oformat == &ff_mxf_opatom_muxer && s->nb_streams !=1){
|
||||||
|
av_log(s, AV_LOG_ERROR, "there must be exactly one stream for mxf opatom\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
AVStream *st = s->streams[i];
|
AVStream *st = s->streams[i];
|
||||||
MXFStreamContext *sc = av_mallocz(sizeof(*sc));
|
MXFStreamContext *sc = av_mallocz(sizeof(*sc));
|
||||||
@ -1901,7 +1935,7 @@ static int mxf_write_header(AVFormatContext *s)
|
|||||||
present[sc->index]++;
|
present[sc->index]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->oformat == &ff_mxf_d10_muxer) {
|
if (s->oformat == &ff_mxf_d10_muxer || s->oformat == &ff_mxf_opatom_muxer) {
|
||||||
mxf->essence_container_count = 1;
|
mxf->essence_container_count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2046,6 +2080,60 @@ static void mxf_write_d10_audio_packet(AVFormatContext *s, AVStream *st, AVPacke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
AVStream *st = s->streams[pkt->stream_index];
|
||||||
|
MXFStreamContext *sc = st->priv_data;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!mxf->header_written) {
|
||||||
|
if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0)
|
||||||
|
return err;
|
||||||
|
mxf_write_klv_fill(s);
|
||||||
|
|
||||||
|
if ((err = mxf_write_opatom_body_partition(s)) < 0)
|
||||||
|
return err;
|
||||||
|
mxf->header_written = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mxf->edit_unit_byte_count) {
|
||||||
|
mxf->index_entries[mxf->edit_units_count].offset = mxf->body_offset;
|
||||||
|
mxf->index_entries[mxf->edit_units_count].flags = ie->flags;
|
||||||
|
mxf->index_entries[mxf->edit_units_count].temporal_ref = ie->temporal_ref;
|
||||||
|
}
|
||||||
|
mxf->edit_units_count++;
|
||||||
|
avio_write(pb, pkt->data, pkt->size);
|
||||||
|
mxf->body_offset += pkt->size;
|
||||||
|
|
||||||
|
avio_flush(pb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
|
static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
{
|
{
|
||||||
MXFContext *mxf = s->priv_data;
|
MXFContext *mxf = s->priv_data;
|
||||||
@ -2086,6 +2174,9 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->oformat == &ff_mxf_opatom_muxer)
|
||||||
|
return mxf_write_opatom_packet(s, pkt, &ie);
|
||||||
|
|
||||||
if (!mxf->header_written) {
|
if (!mxf->header_written) {
|
||||||
if (mxf->edit_unit_byte_count) {
|
if (mxf->edit_unit_byte_count) {
|
||||||
if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
|
if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
|
||||||
@ -2153,7 +2244,7 @@ static void mxf_write_random_index_pack(AVFormatContext *s)
|
|||||||
avio_write(pb, random_index_pack_key, 16);
|
avio_write(pb, random_index_pack_key, 16);
|
||||||
klv_encode_ber_length(pb, 28 + 12LL*mxf->body_partitions_count);
|
klv_encode_ber_length(pb, 28 + 12LL*mxf->body_partitions_count);
|
||||||
|
|
||||||
if (mxf->edit_unit_byte_count)
|
if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer)
|
||||||
avio_wb32(pb, 1); // BodySID of header partition
|
avio_wb32(pb, 1); // BodySID of header partition
|
||||||
else
|
else
|
||||||
avio_wb32(pb, 0);
|
avio_wb32(pb, 0);
|
||||||
@ -2180,7 +2271,7 @@ static int mxf_write_footer(AVFormatContext *s)
|
|||||||
|
|
||||||
mxf_write_klv_fill(s);
|
mxf_write_klv_fill(s);
|
||||||
mxf->footer_partition_offset = avio_tell(pb);
|
mxf->footer_partition_offset = avio_tell(pb);
|
||||||
if (mxf->edit_unit_byte_count) { // no need to repeat index
|
if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) { // no need to repeat index
|
||||||
if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0)
|
if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
@ -2194,8 +2285,15 @@ static int mxf_write_footer(AVFormatContext *s)
|
|||||||
mxf_write_random_index_pack(s);
|
mxf_write_random_index_pack(s);
|
||||||
|
|
||||||
if (s->pb->seekable) {
|
if (s->pb->seekable) {
|
||||||
|
if (s->oformat == &ff_mxf_opatom_muxer){
|
||||||
|
/* rewrite body partition to update lengths */
|
||||||
|
avio_seek(pb, mxf->body_partition_offset[0], SEEK_SET);
|
||||||
|
if ((err = mxf_write_opatom_body_partition(s)) < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
avio_seek(pb, 0, SEEK_SET);
|
avio_seek(pb, 0, SEEK_SET);
|
||||||
if (mxf->edit_unit_byte_count) {
|
if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) {
|
||||||
if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
|
if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
|
||||||
return err;
|
return err;
|
||||||
mxf_write_klv_fill(s);
|
mxf_write_klv_fill(s);
|
||||||
@ -2330,3 +2428,18 @@ AVOutputFormat ff_mxf_d10_muxer = {
|
|||||||
.interleave_packet = mxf_interleave,
|
.interleave_packet = mxf_interleave,
|
||||||
.priv_class = &mxf_d10_muxer_class,
|
.priv_class = &mxf_d10_muxer_class,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AVOutputFormat ff_mxf_opatom_muxer = {
|
||||||
|
.name = "mxf_opatom",
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format) Operational Pattern Atom"),
|
||||||
|
.mime_type = "application/mxf",
|
||||||
|
.extensions = "mxf",
|
||||||
|
.priv_data_size = sizeof(MXFContext),
|
||||||
|
.audio_codec = AV_CODEC_ID_PCM_S16LE,
|
||||||
|
.video_codec = AV_CODEC_ID_DNXHD,
|
||||||
|
.write_header = mxf_write_header,
|
||||||
|
.write_packet = mxf_write_packet,
|
||||||
|
.write_trailer = mxf_write_footer,
|
||||||
|
.flags = AVFMT_NOTIMESTAMPS,
|
||||||
|
.interleave_packet = mxf_interleave,
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user