X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=6282d8f409ed182d8849dd6211cd0c1db4a6f635;hb=13b90ff2c12749aac58d22da4cb47c24b7a37b04;hp=485bb0bc0c723ec46b35e745b4c47e8e840a6333;hpb=2021326f995ff2eda5cd2aae600853f6eddb507d;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index 485bb0bc0c7..6282d8f409e 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -43,6 +43,7 @@ #include "libavutil/sha.h" #include "libavutil/timecode.h" #include "libavcodec/ac3tab.h" +#include "libavcodec/mpegaudiodecheader.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" @@ -1155,17 +1156,10 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time) { - char buffer[32]; if (time) { - struct tm *ptm, tmbuf; - time_t timet; if(time >= 2082844800) time -= 2082844800; /* seconds between 1904-01-01 and Epoch */ - timet = time; - ptm = gmtime_r(&timet, &tmbuf); - if (!ptm) return; - if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm)) - av_dict_set(metadata, "creation_time", buffer, 0); + avpriv_dict_set_timestamp(metadata, "creation_time", time * 1000000); } } @@ -1324,38 +1318,16 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->color_range = AVCOL_RANGE_JPEG; else st->codecpar->color_range = AVCOL_RANGE_MPEG; - /* 14496-12 references JPEG XR specs (rather than the more complete - * 23001-8) so some adjusting is required */ - if (color_primaries >= AVCOL_PRI_FILM) - color_primaries = AVCOL_PRI_UNSPECIFIED; - if ((color_trc >= AVCOL_TRC_LINEAR && - color_trc <= AVCOL_TRC_LOG_SQRT) || - color_trc >= AVCOL_TRC_BT2020_10) - color_trc = AVCOL_TRC_UNSPECIFIED; - if (color_matrix >= AVCOL_SPC_BT2020_NCL) - color_matrix = AVCOL_SPC_UNSPECIFIED; - st->codecpar->color_primaries = color_primaries; - st->codecpar->color_trc = color_trc; - st->codecpar->color_space = color_matrix; - } else if (!strncmp(color_parameter_type, "nclc", 4)) { - /* color primaries, Table 4-4 */ - switch (color_primaries) { - case 1: st->codecpar->color_primaries = AVCOL_PRI_BT709; break; - case 5: st->codecpar->color_primaries = AVCOL_PRI_SMPTE170M; break; - case 6: st->codecpar->color_primaries = AVCOL_PRI_SMPTE240M; break; - } - /* color transfer, Table 4-5 */ - switch (color_trc) { - case 1: st->codecpar->color_trc = AVCOL_TRC_BT709; break; - case 7: st->codecpar->color_trc = AVCOL_TRC_SMPTE240M; break; - } - /* color matrix, Table 4-6 */ - switch (color_matrix) { - case 1: st->codecpar->color_space = AVCOL_SPC_BT709; break; - case 6: st->codecpar->color_space = AVCOL_SPC_BT470BG; break; - case 7: st->codecpar->color_space = AVCOL_SPC_SMPTE240M; break; - } } + if (color_primaries >= AVCOL_PRI_NB) + color_primaries = AVCOL_PRI_UNSPECIFIED; + if (color_trc >= AVCOL_TRC_NB) + color_trc = AVCOL_TRC_UNSPECIFIED; + if (color_matrix >= AVCOL_SPC_NB) + color_matrix = AVCOL_SPC_UNSPECIFIED; + st->codecpar->color_primaries = color_primaries; + st->codecpar->color_trc = color_trc; + st->codecpar->color_space = color_matrix; av_log(c->fc, AV_LOG_TRACE, "\n"); return 0; @@ -2205,6 +2177,8 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb, if (codec_tag && (codec_tag != format && + // prores is allowed to have differing data format and codec tag + codec_tag != AV_RL32("apcn") && codec_tag != AV_RL32("apch") && (c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id : codec_tag != MKTAG('j','p','e','g')))) { /* Multiple fourcc, we skip JPEG. This is not correct, we should @@ -2215,8 +2189,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb, avio_skip(pb, size); return 1; } - if ( codec_tag == AV_RL32("avc1") || - codec_tag == AV_RL32("hvc1") || + if ( codec_tag == AV_RL32("hvc1") || codec_tag == AV_RL32("hev1") ) av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n"); @@ -2294,6 +2267,19 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) return ret; } else if (a.size > 0) avio_skip(pb, a.size); + + if (sc->extradata) { + int extra_size = st->codecpar->extradata_size; + + /* Move the current stream extradata to the stream context one. */ + sc->extradata_size[pseudo_stream_id] = extra_size; + sc->extradata[pseudo_stream_id] = av_malloc(extra_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!sc->extradata[pseudo_stream_id]) + return AVERROR(ENOMEM); + memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, extra_size); + av_freep(&st->codecpar->extradata); + st->codecpar->extradata_size = 0; + } } if (pb->eof_reached) @@ -2304,13 +2290,58 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { + AVStream *st; + MOVStreamContext *sc; + int ret; int entries; + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + avio_r8(pb); /* version */ avio_rb24(pb); /* flags */ - entries = avio_rb32(pb); + entries = avio_rb32(pb); /* entries */ + + if (entries <= 0) { + av_log(c->fc, AV_LOG_ERROR, "invalid STSD entries %d\n", entries); + return AVERROR_INVALIDDATA; + } + + if (sc->extradata) { + av_log(c->fc, AV_LOG_ERROR, "Duplicate STSD\n"); + return AVERROR_INVALIDDATA; + } + /* Prepare space for hosting multiple extradata. */ + sc->extradata = av_mallocz_array(entries, sizeof(*sc->extradata)); + sc->extradata_size = av_mallocz_array(entries, sizeof(*sc->extradata_size)); + if (!sc->extradata_size || !sc->extradata) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = ff_mov_read_stsd_entries(c, pb, entries); + if (ret < 0) + return ret; + + sc->stsd_count = entries; + + /* Restore back the primary extradata. */ + av_freep(&st->codecpar->extradata); + st->codecpar->extradata_size = sc->extradata_size[0]; + if (sc->extradata_size[0]) { + st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + AV_INPUT_BUFFER_PADDING_SIZE); + if (!st->codecpar->extradata) + return AVERROR(ENOMEM); + memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]); + } - return ff_mov_read_stsd_entries(c, pb, entries); + return 0; +fail: + av_freep(&sc->extradata); + av_freep(&sc->extradata_size); + return ret; } static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) @@ -2355,6 +2386,19 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +/* Compute the samples value for the stsc entry at the given index. */ +static inline int mov_get_stsc_samples(MOVStreamContext *sc, int index) +{ + int chunk_count; + + if (index < sc->stsc_count - 1) + chunk_count = sc->stsc_data[index + 1].first - sc->stsc_data[index].first; + else + chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1); + + return sc->stsc_data[index].count * chunk_count; +} + static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -2750,13 +2794,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st) empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale); sc->time_offset = start_time - empty_duration; current_dts = -sc->time_offset; - if (sc->ctts_count>0 && sc->stts_count>0 && - sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) { - /* more than 16 frames delay, dts are likely wrong - this happens with files created by iMovie */ - sc->wrong_dts = 1; - st->codecpar->video_delay = 1; - } } if (!unsupported && st->codecpar->codec_id == AV_CODEC_ID_AAC && start_time > 0) @@ -3212,7 +3249,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) } /* Do not need those anymore. */ av_freep(&sc->chunk_offsets); - av_freep(&sc->stsc_data); av_freep(&sc->sample_sizes); av_freep(&sc->keyframes); av_freep(&sc->stts_data); @@ -4773,6 +4809,12 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->rap_group); av_freep(&sc->display_matrix); + if (sc->extradata) + for (j = 0; j < sc->stsd_count; j++) + av_free(sc->extradata[j]); + av_freep(&sc->extradata); + av_freep(&sc->extradata_size); + av_freep(&sc->cenc.auxiliary_info); av_freep(&sc->cenc.auxiliary_info_sizes); av_aes_ctr_free(sc->cenc.aes_ctr); @@ -5190,6 +5232,29 @@ static int mov_switch_root(AVFormatContext *s, int64_t target) return 1; } +static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt) +{ + uint8_t *side, *extradata; + int extradata_size; + + /* Save the current index. */ + sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1; + + /* Notify the decoder that extradata changed. */ + extradata_size = sc->extradata_size[sc->last_stsd_index]; + extradata = sc->extradata[sc->last_stsd_index]; + if (extradata_size > 0 && extradata) { + side = av_packet_new_side_data(pkt, + AV_PKT_DATA_NEW_EXTRADATA, + extradata_size); + if (!side) + return AVERROR(ENOMEM); + memcpy(side, extradata, extradata_size); + } + + return 0; +} + static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) { MOVContext *mov = s->priv_data; @@ -5256,6 +5321,10 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } #endif + if (st->codecpar->codec_id == AV_CODEC_ID_MP3 && !st->need_parsing && pkt->size > 4) { + if (ff_mpa_check_header(AV_RB32(pkt->data)) < 0) + st->need_parsing = AVSTREAM_PARSE_FULL; + } } pkt->stream_index = sc->ffindex; @@ -5269,8 +5338,6 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) sc->ctts_index++; sc->ctts_sample = 0; } - if (sc->wrong_dts) - pkt->dts = AV_NOPTS_VALUE; } else { int64_t next_dts = (sc->current_sample < st->nb_index_entries) ? st->index_entries[sc->current_sample].timestamp : st->duration; @@ -5282,6 +5349,25 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0; pkt->pos = sample->pos; + /* Multiple stsd handling. */ + if (sc->stsc_data) { + /* Keep track of the stsc index for the given sample, then check + * if the stsd index is different from the last used one. */ + sc->stsc_sample++; + if (sc->stsc_index < sc->stsc_count - 1 && + mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) { + sc->stsc_index++; + sc->stsc_sample = 0; + /* Do not check indexes after a switch. */ + } else if (sc->stsc_data[sc->stsc_index].id > 0 && + sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count && + sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) { + ret = mov_change_extradata(sc, pkt); + if (ret < 0) + return ret; + } + } + if (mov->aax_mode) aax_filter(pkt->data, pkt->size, mov); @@ -5352,6 +5438,18 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, } } + /* adjust stsd index */ + time_sample = 0; + for (i = 0; i < sc->stsc_count; i++) { + int next = time_sample + mov_get_stsc_samples(sc, i); + if (next > sc->current_sample) { + sc->stsc_index = i; + sc->stsc_sample = sc->current_sample - time_sample; + break; + } + time_sample = next; + } + ret = mov_seek_auxiliary_info(s, sc); if (ret < 0) { return ret;