#include "config.h"
extern AVOutputFormat ff_mxf_d10_muxer;
+extern AVOutputFormat ff_mxf_opatom_muxer;
#define EDIT_UNITS_PER_BODY 250
#define KAG_SIZE 512
* 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 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 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 };
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
*/
// operational pattern
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
mxf_write_local_tag(pb, 8 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count), 0x3B0A);
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,
sizeof(*mxf->body_partition_offset))) < 0) {
mxf->body_partitions_count = 0;
}
// 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));
// write partition value
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
- 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
else
avio_wb64(pb, 0);
avio_wb32(pb, index_byte_count ? indexsid : 0); // indexSID
// 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);
- } else
+ else
avio_wb64(pb, 0);
avio_wb32(pb, bodysid); // bodySID
// 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
mxf_write_essence_container_refs(s);
avio_seek(pb, pos, SEEK_SET);
}
- avio_flush(pb);
+ if(key)
+ avio_flush(pb);
return 0;
}
sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
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;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
sc->index = ul_index + 16;
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];
if (!s->nb_streams)
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++) {
AVStream *st = s->streams[i];
MXFStreamContext *sc = av_mallocz(sizeof(*sc));
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;
}
}
}
+static int mxf_write_opatom_body_partition(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
+ MXFStreamContext *sc = st->priv_data;
+ const uint8_t *key = NULL;
+
+ int err;
+
+ if (!mxf->header_written)
+ key = body_partition_key;
+
+ if ((err = mxf_write_partition(s, 1, 0, key, 0)) < 0)
+ return err;
+ mxf_write_klv_fill(s);
+ avio_write(pb, sc->track_essence_element_key, 16);
+ klv_encode_ber9_length(pb, mxf->body_offset);
+ return 0;
+}
+
+static int mxf_write_opatom_packet(AVFormatContext *s, AVPacket *pkt, MXFIndexEntry *ie)
+{
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ int err;
+
+ if (!mxf->header_written) {
+ if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0)
+ return err;
+ mxf_write_klv_fill(s);
+
+ if ((err = mxf_write_opatom_body_partition(s)) < 0)
+ return err;
+ mxf->header_written = 1;
+ }
+
+ if (!mxf->edit_unit_byte_count) {
+ mxf->index_entries[mxf->edit_units_count].offset = mxf->body_offset;
+ mxf->index_entries[mxf->edit_units_count].flags = ie->flags;
+ mxf->index_entries[mxf->edit_units_count].temporal_ref = ie->temporal_ref;
+ }
+ mxf->edit_units_count++;
+ avio_write(pb, pkt->data, pkt->size);
+ mxf->body_offset += pkt->size;
+
+ avio_flush(pb);
+
+ return 0;
+}
+
static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MXFContext *mxf = s->priv_data;
}
}
+ if (s->oformat == &ff_mxf_opatom_muxer)
+ return mxf_write_opatom_packet(s, pkt, &ie);
+
if (!mxf->header_written) {
if (mxf->edit_unit_byte_count) {
if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
avio_write(pb, random_index_pack_key, 16);
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
else
avio_wb32(pb, 0);
mxf_write_klv_fill(s);
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)
return err;
} else {
mxf_write_random_index_pack(s);
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);
- 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)
return err;
mxf_write_klv_fill(s);
stream_count += !!s->streams[i]->last_in_packet_buffer;
if (stream_count && (s->nb_streams == stream_count || flush)) {
- AVPacketList *pktl = s->packet_buffer;
+ AVPacketList *pktl = s->internal->packet_buffer;
if (s->nb_streams != stream_count) {
AVPacketList *last = NULL;
// find last packet in edit unit
if (last)
last->next = NULL;
else {
- s->packet_buffer = NULL;
- s->packet_buffer_end= NULL;
+ s->internal->packet_buffer = NULL;
+ s->internal->packet_buffer_end= NULL;
goto out;
}
- pktl = s->packet_buffer;
+ pktl = s->internal->packet_buffer;
}
*out = pktl->pkt;
av_dlog(s, "out st:%d dts:%"PRId64"\n", (*out).stream_index, (*out).dts);
- s->packet_buffer = pktl->next;
+ s->internal->packet_buffer = 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;
- if(!s->packet_buffer)
- s->packet_buffer_end= NULL;
+ if(!s->internal->packet_buffer)
+ s->internal->packet_buffer_end= NULL;
av_freep(&pktl);
return 1;
} else {
.interleave_packet = mxf_interleave,
.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,
+};