return;
}
for(i = start; i <= start + size; i++)
- c->pal[i] = 0xFF << 24 | bytestream_get_be24(&c->stream);
- c->pal[i] = bytestream2_get_be24(&c->stream);
++ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&c->stream);
}
static inline int check_pixel(uint8_t *buf, uint8_t *start, uint8_t *end)
int i, j;
int flags;
uint32_t size;
- int rest = buf_size;
int offset = 0;
+ bytestream2_init(&c->stream, avpkt->data, avpkt->size);
+
if(c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
- c->pic.reference = 1;
+ c->pic.reference = 3;
if(avctx->get_buffer(avctx, &c->pic) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
- c->stream = buf;
- flags = bytestream_get_le16(&c->stream);
- rest -= 2;
+ flags = bytestream2_get_le16(&c->stream);
if(flags & VB_HAS_GMC){
- i = (int16_t)bytestream_get_le16(&c->stream);
- j = (int16_t)bytestream_get_le16(&c->stream);
+ i = (int16_t)bytestream2_get_le16(&c->stream);
+ j = (int16_t)bytestream2_get_le16(&c->stream);
offset = i + j * avctx->width;
- rest -= 4;
- }
- if(rest < 0){
- av_log(avctx, AV_LOG_ERROR, "not enough data\n");
- return -1;
}
if(flags & VB_HAS_VIDEO){
- size = bytestream_get_le32(&c->stream);
- if(size > rest || size<4){
+ size = bytestream2_get_le32(&c->stream);
++ if(size > bytestream2_get_bytes_left(&c->stream)+4 || size<4){
+ av_log(avctx, AV_LOG_ERROR, "Frame size invalid\n");
+ return -1;
+ }
- vb_decode_framedata(c, c->stream, size, offset);
- c->stream += size - 4;
- rest -= size;
+ vb_decode_framedata(c, offset);
+ bytestream2_skip(&c->stream, size - 4);
}
if(flags & VB_HAS_PALETTE){
- size = bytestream_get_le32(&c->stream);
- if(size > rest){
- av_log(avctx, AV_LOG_ERROR, "Palette size is too big\n");
- return -1;
- }
+ size = bytestream2_get_le32(&c->stream);
vb_decode_palette(c, size);
- rest -= size;
}
memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
for (k = 0; k < source_package->tracks_count; k++) {
if (!(temp_track = mxf_resolve_strong_ref(mxf, &source_package->tracks_refs[k], Track))) {
av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track strong ref\n");
- ret = -1;
- return AVERROR_INVALIDDATA;
++ ret = AVERROR_INVALIDDATA;
+ goto fail_and_free;
}
if (temp_track->track_id == component->source_track_id) {
source_track = temp_track;
uint64_t klv_end = avio_tell(pb) + klv->length;
if (!ctx)
- return -1;
+ return AVERROR(ENOMEM);
- while (avio_tell(pb) + 4 < klv_end) {
+ while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) {
+ int ret;
int tag = avio_rb16(pb);
int size = avio_rb16(pb); /* KLV specified by 0x53 */
uint64_t next = avio_tell(pb) + size;
}
if (ctx_size && tag == 0x3C0A)
avio_read(pb, ctx->uid, 16);
- else if (read_child(ctx, pb, tag, size, uid, -1) < 0)
- return -1;
- else if ((ret = read_child(ctx, pb, tag, size, uid)) < 0)
++ else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0)
+ return ret;
+ /* 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) {
+ av_log(mxf->fc, AV_LOG_ERROR, "local tag %#04x extends past end of local set @ %#"PRIx64"\n",
+ tag, klv->offset);
+ return AVERROR_INVALIDDATA;
+ } else if (avio_tell(pb) <= next) /* only seek forward, else this can loop for a long time */
avio_seek(pb, next, SEEK_SET);
}
if (ctx_size) ctx->type = type;
int res;
if (klv.key[5] == 0x53) {
res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);
- } else
- res = metadata->read(mxf, s->pb, 0, 0, NULL);
+ } else {
+ uint64_t next = avio_tell(s->pb) + klv.length;
+ res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
+
+ /* only seek forward, else this can loop for a long time */
+ if (avio_tell(s->pb) > next) {
+ av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n",
+ klv.offset);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_seek(s->pb, next, SEEK_SET);
+ }
if (res < 0) {
av_log(s, AV_LOG_ERROR, "error reading header metadata\n");
- return -1;
+ return res;
}
break;
}
if (!metadata->read)
avio_skip(s->pb, klv.length);
}
- return mxf_parse_structural_metadata(mxf);
+ /* FIXME avoid seek */
+ if (!essence_offset) {
+ av_log(s, AV_LOG_ERROR, "no essence\n");
+ return AVERROR_INVALIDDATA;
+ }
+ avio_seek(s->pb, essence_offset, SEEK_SET);
+
+ mxf_compute_essence_containers(mxf);
+
+ /* we need to do this before computing the index tables
+ * to be able to fill in zero IndexDurations with st->duration */
+ if ((ret = mxf_parse_structural_metadata(mxf)) < 0)
+ return ret;
+
+ if ((ret = mxf_compute_index_tables(mxf)) < 0)
+ return ret;
+
+ if (mxf->nb_index_tables > 1) {
+ /* TODO: look up which IndexSID to use via EssenceContainerData */
+ av_log(mxf->fc, AV_LOG_INFO, "got %i index tables - only the first one (IndexSID %i) will be used\n",
+ mxf->nb_index_tables, mxf->index_tables[0].index_sid);
+ } else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom) {
+ av_log(mxf->fc, AV_LOG_ERROR, "cannot demux OPAtom without an index\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
+/**
+ * Computes DTS and PTS for the given video packet based on its offset.
+ */
+static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt)
+{
+ int64_t last_ofs = -1, next_ofs;
+ MXFIndexTable *t = &mxf->index_tables[0];
+
+ /* this is called from the OP1a demuxing logic, which means there may be no index tables */
+ if (mxf->nb_index_tables <= 0)
+ return;
+
+ /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */
+ while (mxf->current_edit_unit >= 0) {
+ if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0)
+ break;
+
+ if (next_ofs <= last_ofs) {
+ /* large next_ofs didn't change or current_edit_unit wrapped around
+ * this fixes the infinite loop on zzuf3.mxf */
+ av_log(mxf->fc, AV_LOG_ERROR, "next_ofs didn't change. not deriving packet timestamps\n");
+ return;
+ }
+
+ if (next_ofs > pkt->pos)
+ break;
+
+ last_ofs = next_ofs;
+ mxf->current_edit_unit++;
+ }
+
+ if (mxf->current_edit_unit < 0 || mxf->current_edit_unit >= t->nb_ptses)
+ return;
+
+ pkt->dts = mxf->current_edit_unit + t->first_dts;
+ pkt->pts = t->ptses[mxf->current_edit_unit];
+}
+
+static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
+{
+ KLVPacket klv;
+
+ while (!url_feof(s->pb)) {
++ int ret;
+ if (klv_read_packet(&klv, s->pb) < 0)
+ return -1;
+ PRINT_KEY(s, "read packet", klv.key);
+ av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
+ if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
- int res = mxf_decrypt_triplet(s, pkt, &klv);
- if (res < 0) {
++ ret = mxf_decrypt_triplet(s, pkt, &klv);
++ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
- return -1;
++ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+ }
+ if (IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
+ IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) {
+ int index = mxf_get_stream_index(s, &klv);
+ if (index < 0) {
+ av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12));
+ goto skip;
+ }
+ if (s->streams[index]->discard == AVDISCARD_ALL)
+ goto skip;
+ /* check for 8 channels AES3 element */
+ if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) {
+ if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) {
+ av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n");
- return -1;
++ return AVERROR_INVALIDDATA;
+ }
+ } else {
- int ret = av_get_packet(s->pb, pkt, klv.length);
++ ret = av_get_packet(s->pb, pkt, klv.length);
+ if (ret < 0)
+ return ret;
+ }
+ pkt->stream_index = index;
+ pkt->pos = klv.offset;
+
+ if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ mxf_packet_timestamps(s->priv_data, pkt); /* offset -> EditUnit -> DTS/PTS */
+
+ return 0;
+ } else
+ skip:
+ avio_skip(s->pb, klv.length);
+ }
+ return AVERROR_EOF;
+}
+
+static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MXFContext *mxf = s->priv_data;
+ int ret, size;
+ int64_t ret64, pos, next_pos;
+ AVStream *st;
+ MXFIndexTable *t;
+
+ if (mxf->op != OPAtom)
+ return mxf_read_packet_old(s, pkt);
+
+ /* OPAtom - clip wrapped demuxing */
+ /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */
+ st = s->streams[0];
+ t = &mxf->index_tables[0];
+
+ if (mxf->current_edit_unit >= st->duration)
+ return AVERROR_EOF;
+
+ if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0)
+ return ret;
+
+ /* compute size by finding the next edit unit or the end of the essence container
+ * not pretty, but it works */
+ if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_pos, 0)) < 0 &&
+ (next_pos = mxf_essence_container_end(mxf, t->body_sid)) <= 0) {
+ av_log(s, AV_LOG_ERROR, "unable to compute the size of the last packet\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((size = next_pos - pos) <= 0) {
+ av_log(s, AV_LOG_ERROR, "bad size: %i\n", size);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0)
+ return ret64;
+
+ if ((ret = av_get_packet(s->pb, pkt, size)) != size)
+ return ret < 0 ? ret : AVERROR_EOF;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses &&
+ mxf->current_edit_unit >= 0 && mxf->current_edit_unit < t->nb_ptses) {
+ pkt->dts = mxf->current_edit_unit + t->first_dts;
+ pkt->pts = t->ptses[mxf->current_edit_unit];
+ }
+
+ pkt->stream_index = 0;
+ mxf->current_edit_unit++;
+
+ return 0;
}
static int mxf_read_close(AVFormatContext *s)
{
AVStream *st = s->streams[stream_index];
int64_t seconds;
+ MXFContext* mxf = s->priv_data;
+ int64_t seekpos;
+ int ret;
+ MXFIndexTable *t;
+ if (mxf->index_tables <= 0) {
if (!s->bit_rate)
- return -1;
+ return AVERROR_INVALIDDATA;
if (sample_time < 0)
sample_time = 0;
seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);