* Only tracks with associated descriptors will be decoded. "Highly Desirable" SMPTE 377M D.1
*/
-//#define DEBUG
+#include <stdint.h>
#include "libavutil/aes.h"
#include "libavutil/mathematics.h"
int width;
int height; /* Field height, not frame height */
int frame_layout; /* See MXFFrameLayout enum */
+#define MXF_TFF 1
+#define MXF_BFF 2
+ int field_dominance;
int channels;
int bits_per_sample;
unsigned int component_depth;
int linked_track_id;
uint8_t *extradata;
int extradata_size;
- enum PixelFormat pix_fmt;
+ enum AVPixelFormat pix_fmt;
} MXFDescriptor;
typedef struct {
data_ptr = pkt->data;
end_ptr = pkt->data + length;
buf_ptr = pkt->data + 4; /* skip SMPTE 331M header */
- for (; buf_ptr + st->codec->channels*4 < end_ptr; ) {
+ for (; end_ptr - buf_ptr >= st->codec->channels * 4; ) {
for (i = 0; i < st->codec->channels; i++) {
uint32_t sample = bytestream_get_le32(&buf_ptr);
if (st->codec->bits_per_coded_sample == 24)
int index;
if (!mxf->aesc && s->key && s->keylen == 16) {
- mxf->aesc = av_malloc(av_aes_size);
+ mxf->aesc = av_aes_alloc();
if (!mxf->aesc)
return AVERROR(ENOMEM);
av_aes_init(mxf->aesc, s->key, 128, 1);
int item_len = avio_rb32(pb);
if (item_len != 18) {
- av_log_ask_for_sample(pb, "unsupported primer pack item length %d\n",
- item_len);
+ avpriv_request_sample(pb, "Primer pack item length %d", item_len);
return AVERROR_PATCHWELCOME;
}
if (item_num > UINT_MAX / item_len)
static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFContext *mxf = arg;
- MXFPartition *partition, *tmp_part;
+ MXFPartition *partition;
UID op;
uint64_t footer_partition;
uint32_t nb_essence_containers;
+ int err;
- if (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions))
- return AVERROR(ENOMEM);
-
- tmp_part = av_realloc(mxf->partitions, (mxf->partitions_count + 1) * sizeof(*mxf->partitions));
- if (!tmp_part)
- return AVERROR(ENOMEM);
- mxf->partitions = tmp_part;
+ if ((err = av_reallocp_array(&mxf->partitions, mxf->partitions_count + 1,
+ sizeof(*mxf->partitions))) < 0) {
+ mxf->partitions_count = 0;
+ return err;
+ }
if (mxf->parsing_backward) {
/* insert the new partition pack in the middle
static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set)
{
- MXFMetadataSet **tmp;
- if (mxf->metadata_sets_count+1 >= UINT_MAX / sizeof(*mxf->metadata_sets))
- return AVERROR(ENOMEM);
- tmp = av_realloc(mxf->metadata_sets, (mxf->metadata_sets_count + 1) * sizeof(*mxf->metadata_sets));
- if (!tmp)
- return AVERROR(ENOMEM);
- mxf->metadata_sets = tmp;
+ int err;
+
+ if ((err = av_reallocp_array(&mxf->metadata_sets, mxf->metadata_sets_count + 1,
+ sizeof(*mxf->metadata_sets))) < 0) {
+ mxf->metadata_sets_count = 0;
+ return err;
+ }
mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set;
mxf->metadata_sets_count++;
return 0;
static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFDescriptor *descriptor = arg;
- descriptor->pix_fmt = PIX_FMT_NONE;
+ descriptor->pix_fmt = AV_PIX_FMT_NONE;
switch(tag) {
case 0x3F01:
descriptor->sub_descriptors_count = avio_rb32(pb);
descriptor->aspect_ratio.num = avio_rb32(pb);
descriptor->aspect_ratio.den = avio_rb32(pb);
break;
+ case 0x3212:
+ descriptor->field_dominance = avio_r8(pb);
+ break;
case 0x3301:
descriptor->component_depth = avio_rb32(pb);
break;
default:
/* Private uid used by SONY C0023S01.mxf */
if (IS_KLV_KEY(uid, mxf_sony_mpeg4_extradata)) {
+ av_free(descriptor->extradata);
+ descriptor->extradata_size = 0;
descriptor->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!descriptor->extradata)
return AVERROR(ENOMEM);
/* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */
static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE },
};
if (mxf->metadata_sets[i]->type == IndexTableSegment)
nb_segments++;
+ if (!nb_segments)
+ return AVERROR_INVALIDDATA;
+
*sorted_segments = av_mallocz(nb_segments * sizeof(**sorted_segments));
unsorted_segments = av_mallocz(nb_segments * sizeof(*unsorted_segments));
- if (!sorted_segments || !unsorted_segments) {
+ if (!*sorted_segments || !unsorted_segments) {
av_freep(sorted_segments);
av_free(unsorted_segments);
return AVERROR(ENOMEM);
/* sort segments by {BodySID, IndexSID, IndexStartPosition}, remove duplicates while we're at it */
for (i = 0; i < nb_segments; i++) {
int best = -1, best_body_sid = -1, best_index_sid = -1, best_index_start = -1;
+ uint64_t best_index_duration = 0;
for (j = 0; j < nb_segments; j++) {
MXFIndexTableSegment *s = unsorted_segments[j];
/* Require larger BosySID, IndexSID or IndexStartPosition then the previous entry. This removes duplicates.
* We want the smallest values for the keys than what we currently have, unless this is the first such entry this time around.
+ * If we come across an entry with the same IndexStartPosition but larger IndexDuration, then we'll prefer it over the one we currently have.
*/
if ((i == 0 || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) &&
- (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start)) {
+ (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start ||
+ (s->index_start_position == best_index_start && s->index_duration > best_index_duration))) {
best = j;
best_body_sid = s->body_sid;
best_index_sid = s->index_sid;
best_index_start = s->index_start_position;
+ best_index_duration = s->index_duration;
}
}
}
}
- if (mxf->nb_index_tables > INT_MAX / sizeof(MXFIndexTable) ||
- !(mxf->index_tables = av_mallocz(mxf->nb_index_tables *
- sizeof(MXFIndexTable)))) {
+ mxf->index_tables = av_mallocz_array(mxf->nb_index_tables,
+ sizeof(*mxf->index_tables));
+ if (!mxf->index_tables) {
av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n");
ret = AVERROR(ENOMEM);
goto finish_decoding_index;
for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) {
MXFIndexTable *t = &mxf->index_tables[j];
- if (t->nb_segments >
- (INT_MAX / sizeof(MXFIndexTableSegment *)) ||
- !(t->segments = av_mallocz(t->nb_segments *
- sizeof(MXFIndexTableSegment*)))) {
+ t->segments = av_mallocz_array(t->nb_segments,
+ sizeof(*t->segments));
+
+ if (!t->segments) {
av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment"
" pointer array\n");
ret = AVERROR(ENOMEM);
if (st->duration == -1)
st->duration = AV_NOPTS_VALUE;
st->start_time = component->start_position;
+ if (material_track->edit_rate.num <= 0 ||
+ material_track->edit_rate.den <= 0) {
+ av_log(mxf->fc, AV_LOG_WARNING,
+ "Invalid edit rate (%d/%d) found on stream #%d, "
+ "defaulting to 25/1\n",
+ material_track->edit_rate.num,
+ material_track->edit_rate.den, st->index);
+ material_track->edit_rate = (AVRational){25, 1};
+ }
avpriv_set_pts_info(st, 64, material_track->edit_rate.den, material_track->edit_rate.num);
PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul);
/* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul);
st->codec->codec_id = codec_ul->id;
- if (descriptor->extradata) {
- st->codec->extradata = descriptor->extradata;
- st->codec->extradata_size = descriptor->extradata_size;
- }
+
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
source_track->intra_only = mxf_is_intra_only(descriptor);
container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul);
"SegmentedFrame layout isn't currently supported\n");
break;
case FullFrame:
+ st->codec->field_order = AV_FIELD_PROGRESSIVE;
break;
case OneField:
/* Every other line is stored and needs to be duplicated. */
* It's also for compatibility with the old behavior. */
case SeparateFields:
case MixedFields:
+ switch (descriptor->field_dominance) {
+ case MXF_TFF:
+ st->codec->field_order = AV_FIELD_TT;
+ break;
+ case MXF_BFF:
+ st->codec->field_order = AV_FIELD_BB;
+ break;
+ default:
+ avpriv_request_sample(mxf->fc,
+ "Field dominance %d support",
+ descriptor->field_dominance);
+ break;
+ }
/* Turn field height into frame height. */
st->codec->height *= 2;
default:
}
if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
st->codec->pix_fmt = descriptor->pix_fmt;
- if (st->codec->pix_fmt == PIX_FMT_NONE) {
+ if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
pix_fmt_ul = mxf_get_codec_ul(ff_mxf_pixel_format_uls,
&descriptor->essence_codec_ul);
st->codec->pix_fmt = pix_fmt_ul->id;
- if (st->codec->pix_fmt == PIX_FMT_NONE) {
+ if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
/* support files created before RP224v10 by defaulting to UYVY422
if subsampling is 4:2:2 and component depth is 8-bit */
if (descriptor->horiz_subsampling == 2 &&
descriptor->vert_subsampling == 1 &&
descriptor->component_depth == 8) {
- st->codec->pix_fmt = PIX_FMT_UYVY422;
+ st->codec->pix_fmt = AV_PIX_FMT_UYVY422;
}
}
}
st->codec->channels = descriptor->channels;
st->codec->bits_per_coded_sample = descriptor->bits_per_sample;
- if (descriptor->sample_rate.den > 0)
+ if (descriptor->sample_rate.den > 0) {
st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den;
+ avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num);
+ } else {
+ av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) "
+ "found for stream #%d, time base forced to 1/48000\n",
+ descriptor->sample_rate.num, descriptor->sample_rate.den,
+ st->index);
+ avpriv_set_pts_info(st, 64, 1, 48000);
+ }
/* TODO: implement AV_CODEC_ID_RAWAUDIO */
if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
st->need_parsing = AVSTREAM_PARSE_FULL;
}
}
+ if (descriptor->extradata) {
+ st->codec->extradata = av_mallocz(descriptor->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (st->codec->extradata) {
+ memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size);
+ st->codec->extradata_size = descriptor->extradata_size;
+ }
+ } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
+ ret = ff_generate_avci_extradata(st);
+ if (ret < 0)
+ return ret;
+ }
if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
/* TODO: decode timestamps */
st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
/* Accept the 64k local set limit being exceeded (Avid). Don't accept
* it extending past the end of the KLV though (zzuf5.mxf). */
if (avio_tell(pb) > klv_end) {
+ if (ctx_size)
+ av_free(ctx);
+
av_log(mxf->fc, AV_LOG_ERROR,
"local tag %#04x extends past end of local set @ %#"PRIx64"\n",
tag, klv->offset);
/* if this check is hit then it's possible OPAtom was treated
* as OP1a truncate the packet since it's probably very large
* (>2 GiB is common) */
- av_log_ask_for_sample(s,
- "KLV for edit unit %i extends into next "
- "edit unit - OPAtom misinterpreted as "
- "OP1a?\n",
+ avpriv_request_sample(s,
+ "OPAtom misinterpreted as OP1a?"
+ "KLV for edit unit %i extending into "
+ "next edit unit",
mxf->current_edit_unit);
klv.length = next_ofs - avio_tell(s->pb);
}
for (i = 0; i < mxf->metadata_sets_count; i++) {
switch (mxf->metadata_sets[i]->type) {
+ case Descriptor:
+ av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->extradata);
+ break;
case MultipleDescriptor:
av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->sub_descriptors_refs);
break;
int ret;
MXFIndexTable *t;
- if (mxf->index_tables <= 0) {
+ if (mxf->nb_index_tables <= 0) {
if (!s->bit_rate)
return AVERROR_INVALIDDATA;
if (sample_time < 0)
sample_time = 0;
seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);
- if ((ret = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0)
- return ret;
+ seekpos = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET);
+ if (seekpos < 0)
+ return seekpos;
+
ff_update_cur_dts(s, st, sample_time);
+ mxf->current_edit_unit = sample_time;
} else {
t = &mxf->index_tables[0];