X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=df30ed35230d4227bcdcfd6494bd8b8ed6ab748f;hb=0be8e661743705eb4c4369943867f462df0fa1ca;hp=40acf78a65a0eb599b789cc6d3f4c4bcd669d610;hpb=a448a5d1c4620aa58ec138fbffd46d18d42d53e0;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index 40acf78a65a..df30ed35230 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -26,7 +26,7 @@ //#define MOV_EXPORT_ALL_METADATA #include "libavutil/intreadwrite.h" -#include "libavutil/intfloat_readwrite.h" +#include "libavutil/intfloat.h" #include "libavutil/mathematics.h" #include "libavutil/avstring.h" #include "libavutil/dict.h" @@ -36,7 +36,9 @@ #include "riff.h" #include "isom.h" #include "libavcodec/get_bits.h" +#include "libavcodec/timecode.h" #include "id3v1.h" +#include "mov_chan.h" #if CONFIG_ZLIB #include @@ -314,18 +316,16 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size >= 8) { a.size = avio_rb32(pb); a.type = avio_rl32(pb); + total_size += 8; + if (a.size == 1) { /* 64 bit extended size */ + a.size = avio_rb64(pb) - 8; + total_size += 8; + } } av_dlog(c->fc, "type: %08x '%.4s' parent:'%.4s' sz: %"PRId64" %"PRId64" %"PRId64"\n", a.type, (char*)&a.type, (char*)&atom.type, a.size, total_size, atom.size); - total_size += 8; - if (a.size == 1) { /* 64 bit extended size */ - a.size = avio_rb64(pb) - 8; - total_size += 8; - } if (a.size == 0) { - a.size = atom.size - total_size; - if (a.size <= 8) - break; + a.size = atom.size - total_size + 8; } a.size -= 8; if (a.size < 0) @@ -432,6 +432,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 16); for (type = 0; type != -1 && avio_tell(pb) < next; ) { + if(url_feof(pb)) + return AVERROR_EOF; type = avio_rb16(pb); len = avio_rb16(pb); av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len); @@ -570,6 +572,59 @@ static int mov_read_dac3(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + uint8_t version; + uint32_t flags, layout_tag, bitmap, num_descr, label_mask; + int i; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + if (atom.size < 16) + return 0; + + version = avio_r8(pb); + flags = avio_rb24(pb); + + layout_tag = avio_rb32(pb); + bitmap = avio_rb32(pb); + num_descr = avio_rb32(pb); + + if (atom.size < 16ULL + num_descr * 20ULL) + return 0; + + av_dlog(c->fc, "chan: size=%" PRId64 " version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n", + atom.size, version, flags, layout_tag, bitmap, num_descr); + + label_mask = 0; + for (i = 0; i < num_descr; i++) { + uint32_t label, cflags; + float coords[3]; + label = avio_rb32(pb); // mChannelLabel + cflags = avio_rb32(pb); // mChannelFlags + AV_WN32(&coords[0], avio_rl32(pb)); // mCoordinates[0] + AV_WN32(&coords[1], avio_rl32(pb)); // mCoordinates[1] + AV_WN32(&coords[2], avio_rl32(pb)); // mCoordinates[2] + if (layout_tag == 0) { + uint32_t mask_incr = ff_mov_get_channel_label(label); + if (mask_incr == 0) { + label_mask = 0; + break; + } + label_mask |= mask_incr; + } + } + if (layout_tag == 0) + st->codec->channel_layout = label_mask; + else + st->codec->channel_layout = ff_mov_get_channel_layout(layout_tag, bitmap); + + return 0; +} + static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -752,6 +807,7 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); /* current time */ avio_rb32(pb); /* next track ID */ + c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale); return 0; } @@ -811,6 +867,40 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + unsigned mov_field_order; + enum AVFieldOrder decoded_field_order = AV_FIELD_UNKNOWN; + + if (c->fc->nb_streams < 1) // will happen with jp2 files + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + if (atom.size < 2) + return AVERROR_INVALIDDATA; + mov_field_order = avio_rb16(pb); + if ((mov_field_order & 0xFF00) == 0x0100) + decoded_field_order = AV_FIELD_PROGRESSIVE; + else if ((mov_field_order & 0xFF00) == 0x0200) { + switch (mov_field_order & 0xFF) { + case 0x01: decoded_field_order = AV_FIELD_TT; + break; + case 0x06: decoded_field_order = AV_FIELD_BB; + break; + case 0x09: decoded_field_order = AV_FIELD_TB; + break; + case 0x0E: decoded_field_order = AV_FIELD_BT; + break; + } + } + if (decoded_field_order == AV_FIELD_UNKNOWN && mov_field_order) { + av_log(NULL, AV_LOG_ERROR, "Unknown MOV field order 0x%04x\n", mov_field_order); + } + st->codec->field_order = decoded_field_order; + + return 0; +} + /* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom, enum CodecID codec_id) @@ -852,11 +942,6 @@ static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_extradata(c, pb, atom, CODEC_ID_AVS); } -static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom) -{ - return mov_read_extradata(c, pb, atom, CODEC_ID_MJPEG); -} - static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom) { return mov_read_extradata(c, pb, atom, CODEC_ID_JPEG2000); @@ -904,6 +989,15 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((uint64_t)atom.size > (1<<30)) return -1; + if (atom.size >= 10) { + // Broken files created by legacy versions of Libav and FFmpeg will + // wrap a whole fiel atom inside of a glbl atom. + unsigned size = avio_rb32(pb); + unsigned type = avio_rl32(pb); + avio_seek(pb, -8, SEEK_CUR); + if (type == MKTAG('f','i','e','l') && size == atom.size) + return mov_read_default(c, pb, atom); + } av_free(st->codec->extradata); st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) @@ -957,6 +1051,8 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) entries = avio_rb32(pb); + if (!entries) + return 0; if (entries >= UINT_MAX/sizeof(int64_t)) return -1; @@ -1036,6 +1132,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) avio_rb32(pb); /* reserved */ avio_rb16(pb); /* reserved */ dref_id = avio_rb16(pb); + }else if (size <= 0){ + av_log(c->fc, AV_LOG_ERROR, "invalid size %d in stsd\n", size); + return -1; } if (st->codec->codec_tag && @@ -1124,7 +1223,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) (color_depth == 8)) { /* for palette traversal */ unsigned int color_start, color_count, color_end; - unsigned char r, g, b; + unsigned char a, r, g, b; if (color_greyscale) { int color_index, color_dec; @@ -1139,7 +1238,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) }else r = g = b = color_index; sc->palette[j] = - (r << 16) | (g << 8) | (b); + (0xFFU << 24) | (r << 16) | (g << 8) | (b); color_index -= color_dec; if (color_index < 0) color_index = 0; @@ -1160,7 +1259,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) g = color_table[j * 3 + 1]; b = color_table[j * 3 + 2]; sc->palette[j] = - (r << 16) | (g << 8) | (b); + (0xFFU << 24) | (r << 16) | (g << 8) | (b); } } else { /* load the palette from the file */ @@ -1170,10 +1269,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) if ((color_start <= 255) && (color_end <= 255)) { for (j = color_start; j <= color_end; j++) { - /* each R, G, or B component is 16 bits; - * only use the top 8 bits; skip alpha bytes - * up front */ - avio_r8(pb); + /* each A, R, G, or B component is 16 bits; + * only use the top 8 bits */ + a = avio_r8(pb); avio_r8(pb); r = avio_r8(pb); avio_r8(pb); @@ -1182,7 +1280,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) b = avio_r8(pb); avio_r8(pb); sc->palette[j] = - (r << 16) | (g << 8) | (b); + (a << 24 ) | (r << 16) | (g << 8) | (b); } } } @@ -1215,7 +1313,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) avio_rb32(pb); /* bytes per sample */ } else if (version==2) { avio_rb32(pb); /* sizeof struct only */ - st->codec->sample_rate = av_int2dbl(avio_rb64(pb)); /* float 64 */ + st->codec->sample_rate = av_int2double(avio_rb64(pb)); /* float 64 */ st->codec->channels = avio_rb32(pb); avio_rb32(pb); /* always 0x7F000000 */ st->codec->bits_per_coded_sample = avio_rb32(pb); /* bits per channel if sound is uncompressed */ @@ -1284,9 +1382,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) val = avio_rb32(pb); /* flags */ if (val & 1) st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; - avio_rb32(pb); - avio_rb32(pb); - st->codec->time_base.den = avio_r8(pb); + avio_rb32(pb); /* time scale */ + avio_rb32(pb); /* frame duration */ + st->codec->time_base.den = avio_r8(pb); /* number of frame */ st->codec->time_base.num = 1; } /* other codec type, just skip (rtp, mp4s, ...) */ @@ -1398,6 +1496,8 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dlog(c->fc, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); + if (!entries) + return 0; if (entries >= UINT_MAX / sizeof(*sc->stsc_data)) return -1; sc->stsc_data = av_malloc(entries * sizeof(*sc->stsc_data)); @@ -1513,6 +1613,8 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) return -1; } + if (!entries) + return 0; if (entries >= UINT_MAX / sizeof(int) || entries >= (UINT_MAX - 4) / field_size) return -1; sc->sample_sizes = av_malloc(entries * sizeof(int)); @@ -1579,7 +1681,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sample_duration = avio_rb32(pb); /* sample_duration < 0 is invalid based on the spec */ if (sample_duration < 0) { - av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d", sample_duration); + av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d\n", sample_duration); sample_duration = 1; } sc->stts_data[i].count= sample_count; @@ -1615,6 +1717,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dlog(c->fc, "track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries); + if (!entries) + return 0; if (entries >= UINT_MAX / sizeof(*sc->ctts_data)) return -1; sc->ctts_data = av_malloc(entries * sizeof(*sc->ctts_data)); @@ -1675,6 +1779,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) current_dts -= sc->dts_shift; + if (!sc->sample_count) + return; if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries)) return; st->index_entries = av_malloc(sc->sample_count*sizeof(*st->index_entries)); @@ -2338,7 +2444,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom) +static int mov_read_chan2(MOVContext *c, AVIOContext *pb, MOVAtom atom) { if (atom.size < 16) return 0; @@ -2401,7 +2507,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */ { MKTAG('w','f','e','x'), mov_read_wfex }, { MKTAG('c','m','o','v'), mov_read_cmov }, -{ MKTAG('c','h','a','n'), mov_read_chan }, +{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */ { 0, NULL } }; @@ -2519,6 +2625,46 @@ finish: avio_seek(sc->pb, cur_pos, SEEK_SET); } +static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, + uint32_t value) +{ + char buf[16]; + struct ff_timecode tc = { + .drop = st->codec->flags2 & CODEC_FLAG2_DROP_FRAME_TIMECODE, + .rate = (AVRational){st->codec->time_base.den, + st->codec->time_base.num}, + }; + + if (avpriv_check_timecode_rate(s, tc.rate, tc.drop) < 0) + return AVERROR(EINVAL); + av_dict_set(&st->metadata, "timecode", + avpriv_timecode_to_string(buf, &tc, value), 0); + return 0; +} + +static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) +{ + MOVStreamContext *sc = st->priv_data; + int64_t cur_pos = avio_tell(sc->pb); + uint32_t value; + + if (!st->nb_index_entries) + return -1; + + avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); + value = avio_rb32(s->pb); + + /* Assume Counter flag is set to 1 in tmcd track (even though it is likely + * not the case) and thus assume "frame number format" instead of QT one. + * No sample with tmcd track can be found with a QT timecode at the moment, + * despite what the tmcd track "suggests" (Counter flag set to 0 means QT + * format). */ + parse_timecode_in_framenum_format(s, st, value); + + avio_seek(sc->pb, cur_pos, SEEK_SET); + return 0; +} + static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) { MOVContext *mov = s->priv_data; @@ -2544,8 +2690,14 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) } av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); - if (pb->seekable && mov->chapter_track > 0) - mov_read_chapters(s); + if (pb->seekable) { + int i; + if (mov->chapter_track > 0) + mov_read_chapters(s); + for (i = 0; i < s->nb_streams; i++) + if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd")) + mov_read_timecode_track(s, s->streams[i]); + } return 0; }