X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=2519707345410938ebf220b57e601b5d0cc61bc3;hb=5a9415533dd064d44605b3a3896a53377b7a5ca8;hp=afef53b79a6ff0aaa59a20ca4b3ba84b6a0a97bd;hpb=a47bd5d77e3f1dd8bb3d4ba0955bd7b1323c7d83;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index afef53b79a6..25197073454 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -74,6 +74,8 @@ typedef struct MOVParseTableEntry { static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom); static int mov_read_mfra(MOVContext *c, AVIOContext *f); +static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size, + int count, int duration); static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb, unsigned len, const char *key) @@ -889,6 +891,7 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) init_get_bits(&gb, buf, 8*ddts_size); if (c->fc->nb_streams < 1) { + av_free(buf); return 0; } st = c->fc->streams[c->fc->nb_streams-1]; @@ -896,6 +899,7 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->sample_rate = get_bits_long(&gb, 32); if (st->codecpar->sample_rate <= 0) { av_log(c->fc, AV_LOG_ERROR, "Invalid sample rate %d\n", st->codecpar->sample_rate); + av_free(buf); return AVERROR_INVALIDDATA; } skip_bits_long(&gb, 32); /* max bitrate */ @@ -923,6 +927,7 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) ((channel_layout_code & 0x8) ? AV_CH_LOW_FREQUENCY : 0); st->codecpar->channels = av_get_channel_layout_nb_channels(st->codecpar->channel_layout); + av_free(buf); return 0; } @@ -1236,8 +1241,8 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->time_scale = avio_rb32(pb); if (sc->time_scale <= 0) { - av_log(c->fc, AV_LOG_ERROR, "Invalid mdhd time scale %d\n", sc->time_scale); - return AVERROR_INVALIDDATA; + av_log(c->fc, AV_LOG_ERROR, "Invalid mdhd time scale %d, defaulting to 1\n", sc->time_scale); + sc->time_scale = 1; } st->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */ @@ -1266,8 +1271,8 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) mov_metadata_creation_time(&c->fc->metadata, creation_time); c->time_scale = avio_rb32(pb); /* time scale */ if (c->time_scale <= 0) { - av_log(c->fc, AV_LOG_ERROR, "Invalid mvhd time scale %d\n", c->time_scale); - return AVERROR_INVALIDDATA; + av_log(c->fc, AV_LOG_ERROR, "Invalid mvhd time scale %d, defaulting to 1\n", c->time_scale); + c->time_scale = 1; } av_log(c->fc, AV_LOG_TRACE, "time scale = %i\n", c->time_scale); @@ -2708,7 +2713,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - unsigned int i, entries, ctts_count = 0; + unsigned int i, j, entries, ctts_count = 0; if (c->fc->nb_streams < 1) return 0; @@ -2726,7 +2731,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (entries >= UINT_MAX / sizeof(*sc->ctts_data)) return AVERROR_INVALIDDATA; av_freep(&sc->ctts_data); - sc->ctts_data = av_realloc(NULL, entries * sizeof(*sc->ctts_data)); + sc->ctts_data = av_fast_realloc(NULL, &sc->ctts_allocated_size, entries * sizeof(*sc->ctts_data)); if (!sc->ctts_data) return AVERROR(ENOMEM); @@ -2741,9 +2746,9 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) continue; } - sc->ctts_data[ctts_count].count = count; - sc->ctts_data[ctts_count].duration = duration; - ctts_count++; + /* Expand entries such that we have a 1-1 mapping with samples. */ + for (j = 0; j < count; j++) + add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size, 1, duration); av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n", count, duration); @@ -3039,11 +3044,13 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int64_t edit_list_dts_entry_end = 0; int64_t edit_list_start_ctts_sample = 0; int64_t curr_cts; + int64_t curr_ctts = 0; + int64_t min_corrected_pts = -1; + int64_t empty_edits_sum_duration = 0; int64_t edit_list_index = 0; int64_t index; int64_t index_ctts_count; int flags; - unsigned int ctts_allocated_size = 0; int64_t start_dts = 0; int64_t edit_list_media_time_dts = 0; int64_t edit_list_start_encountered = 0; @@ -3053,6 +3060,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int first_non_zero_audio_edit = -1; int packet_skip_samples = 0; MOVIndexRange *current_index_range; + int i; if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) { return; @@ -3077,16 +3085,13 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) msc->ctts_count = 0; msc->ctts_index = 0; msc->ctts_sample = 0; + msc->ctts_allocated_size = 0; // If the dts_shift is positive (in case of negative ctts values in mov), // then negate the DTS by dts_shift - if (msc->dts_shift > 0) + if (msc->dts_shift > 0) { edit_list_dts_entry_end -= msc->dts_shift; - - // Offset the DTS by ctts[0] to make the PTS of the first frame 0 - if (ctts_data_old && ctts_count_old > 0) { - edit_list_dts_entry_end -= ctts_data_old[0].duration; - av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by ctts[%d].duration: %d\n", 0, ctts_data_old[0].duration); + av_log(mov->fc, AV_LOG_DEBUG, "Shifting DTS by %d because of negative CTTS.\n", msc->dts_shift); } start_dts = edit_list_dts_entry_end; @@ -3100,6 +3105,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) edit_list_dts_entry_end += edit_list_duration; num_discarded_begin = 0; if (edit_list_media_time == -1) { + empty_edits_sum_duration += edit_list_duration; continue; } @@ -3179,15 +3185,17 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // frames (pts) before or after edit list curr_cts = current->timestamp + msc->dts_shift; + curr_ctts = 0; if (ctts_data_old && ctts_index_old < ctts_count_old) { - av_log(mov->fc, AV_LOG_DEBUG, "shifted frame pts, curr_cts: %"PRId64" @ %"PRId64", ctts: %d, ctts_count: %"PRId64"\n", - curr_cts, ctts_index_old, ctts_data_old[ctts_index_old].duration, ctts_count_old); - curr_cts += ctts_data_old[ctts_index_old].duration; + curr_ctts = ctts_data_old[ctts_index_old].duration; + av_log(mov->fc, AV_LOG_DEBUG, "stts: %"PRId64" ctts: %"PRId64", ctts_index: %"PRId64", ctts_count: %"PRId64"\n", + curr_cts, curr_ctts, ctts_index_old, ctts_count_old); + curr_cts += curr_ctts; ctts_sample_old++; if (ctts_sample_old == ctts_data_old[ctts_index_old].count) { if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, - &ctts_allocated_size, + &msc->ctts_allocated_size, ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample, ctts_data_old[ctts_index_old].duration) == -1) { av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", @@ -3244,14 +3252,21 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } } } - } else if (edit_list_start_encountered == 0) { - edit_list_start_encountered = 1; - // Make timestamps strictly monotonically increasing for audio, by rewriting timestamps for - // discarded packets. - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && frame_duration_buffer) { - fix_index_entry_timestamps(st, st->nb_index_entries, edit_list_dts_counter, - frame_duration_buffer, num_discarded_begin); - av_freep(&frame_duration_buffer); + } else { + if (min_corrected_pts < 0) { + min_corrected_pts = edit_list_dts_counter + curr_ctts + msc->dts_shift; + } else { + min_corrected_pts = FFMIN(min_corrected_pts, edit_list_dts_counter + curr_ctts + msc->dts_shift); + } + if (edit_list_start_encountered == 0) { + edit_list_start_encountered = 1; + // Make timestamps strictly monotonically increasing for audio, by rewriting timestamps for + // discarded packets. + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && frame_duration_buffer) { + fix_index_entry_timestamps(st, st->nb_index_entries, edit_list_dts_counter, + frame_duration_buffer, num_discarded_begin); + av_freep(&frame_duration_buffer); + } } } @@ -3279,7 +3294,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) if (ctts_data_old && ctts_sample_old != 0) { if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, - &ctts_allocated_size, + &msc->ctts_allocated_size, ctts_sample_old - edit_list_start_ctts_sample, ctts_data_old[ctts_index_old].duration) == -1) { av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", @@ -3292,6 +3307,19 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } } } + // If there are empty edits, then min_corrected_pts might be positive intentionally. So we subtract the + // sum duration of emtpy edits here. + min_corrected_pts -= empty_edits_sum_duration; + + // If the minimum pts turns out to be greater than zero after fixing the index, then we subtract the + // dts by that amount to make the first pts zero. + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && min_corrected_pts > 0) { + av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", min_corrected_pts); + for (i = 0; i < st->nb_index_entries; ++i) { + st->index_entries[i].timestamp -= min_corrected_pts; + } + } + // Update av stream length st->duration = edit_list_dts_entry_end - start_dts; @@ -3727,8 +3755,9 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) c->trak_index = -1; /* sanity checks */ - if (sc->chunk_count && (!sc->stts_count || !sc->stsc_count || - (!sc->sample_size && !sc->sample_count))) { + if ((sc->chunk_count && (!sc->stts_count || !sc->stsc_count || + (!sc->sample_size && !sc->sample_count))) || + (!sc->chunk_count && sc->sample_count)) { av_log(c->fc, AV_LOG_ERROR, "stream %d, missing mandatory atoms, broken header\n", st->index); return 0; @@ -4236,7 +4265,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) int64_t dts; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; - int flags, distance, i, err; + int flags, distance, i; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -4256,29 +4285,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) entries = avio_rb32(pb); av_log(c->fc, AV_LOG_TRACE, "flags 0x%x entries %u\n", flags, entries); - /* Always assume the presence of composition time offsets. - * Without this assumption, for instance, we cannot deal with a track in fragmented movies that meet the following. - * 1) in the initial movie, there are no samples. - * 2) in the first movie fragment, there is only one sample without composition time offset. - * 3) in the subsequent movie fragments, there are samples with composition time offset. */ - if (!sc->ctts_count && sc->sample_count) - { - /* Complement ctts table if moov atom doesn't have ctts atom. */ - ctts_data = av_realloc(NULL, sizeof(*sc->ctts_data)); - if (!ctts_data) - return AVERROR(ENOMEM); - sc->ctts_data = ctts_data; - sc->ctts_data[sc->ctts_count].count = sc->sample_count; - sc->ctts_data[sc->ctts_count].duration = 0; - sc->ctts_count++; - } if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data)) return AVERROR_INVALIDDATA; - if ((err = av_reallocp_array(&sc->ctts_data, entries + sc->ctts_count, - sizeof(*sc->ctts_data))) < 0) { - sc->ctts_count = 0; - return err; - } if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb); if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); dts = sc->track_end - sc->time_offset; @@ -4289,26 +4297,28 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) unsigned sample_size = frag->size; int sample_flags = i ? frag->flags : first_sample_flags; unsigned sample_duration = frag->duration; + unsigned ctts_duration = 0; int keyframe = 0; + int ctts_index = 0; + int old_nb_index_entries = st->nb_index_entries; if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(pb); if (flags & MOV_TRUN_SAMPLE_SIZE) sample_size = avio_rb32(pb); if (flags & MOV_TRUN_SAMPLE_FLAGS) sample_flags = avio_rb32(pb); - sc->ctts_data[sc->ctts_count].count = 1; - sc->ctts_data[sc->ctts_count].duration = (flags & MOV_TRUN_SAMPLE_CTS) ? - avio_rb32(pb) : 0; - mov_update_dts_shift(sc, sc->ctts_data[sc->ctts_count].duration); + if (flags & MOV_TRUN_SAMPLE_CTS) ctts_duration = avio_rb32(pb); + + mov_update_dts_shift(sc, ctts_duration); if (frag->time != AV_NOPTS_VALUE) { if (c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { int64_t pts = frag->time; av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64 " sc->dts_shift %d ctts.duration %d" " sc->time_offset %"PRId64" flags & MOV_TRUN_SAMPLE_CTS %d\n", pts, - sc->dts_shift, sc->ctts_data[sc->ctts_count].duration, + sc->dts_shift, ctts_duration, sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS); dts = pts - sc->dts_shift; if (flags & MOV_TRUN_SAMPLE_CTS) { - dts -= sc->ctts_data[sc->ctts_count].duration; + dts -= ctts_duration; } else { dts -= sc->time_offset; } @@ -4320,7 +4330,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) } frag->time = AV_NOPTS_VALUE; } - sc->ctts_count++; + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) keyframe = 1; else @@ -4329,13 +4339,44 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); if (keyframe) distance = 0; - err = av_add_index_entry(st, offset, dts, sample_size, distance, - keyframe ? AVINDEX_KEYFRAME : 0); - if (err < 0) { + ctts_index = av_add_index_entry(st, offset, dts, sample_size, distance, + keyframe ? AVINDEX_KEYFRAME : 0); + if (ctts_index >= 0 && old_nb_index_entries < st->nb_index_entries) { + unsigned int size_needed = st->nb_index_entries * sizeof(*sc->ctts_data); + unsigned int request_size = size_needed > sc->ctts_allocated_size ? + FFMAX(size_needed, 2 * sc->ctts_allocated_size) : size_needed; + unsigned int old_ctts_size = sc->ctts_allocated_size; + ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, request_size); + if (!ctts_data) { + av_freep(&sc->ctts_data); + return AVERROR(ENOMEM); + } + sc->ctts_data = ctts_data; + + // In case there were samples without ctts entries, ensure they get + // zero valued entries. This ensures clips which mix boxes with and + // without ctts entries don't pickup uninitialized data. + memset((uint8_t*)(sc->ctts_data) + old_ctts_size, 0, sc->ctts_allocated_size - old_ctts_size); + + if (ctts_index != old_nb_index_entries) { + memmove(sc->ctts_data + ctts_index + 1, sc->ctts_data + ctts_index, + sizeof(*sc->ctts_data) * (sc->ctts_count - ctts_index)); + if (ctts_index <= sc->current_sample) { + // if we inserted a new item before the current sample, move the + // counter ahead so it is still pointing to the same sample. + sc->current_sample++; + } + } + + sc->ctts_data[ctts_index].count = 1; + sc->ctts_data[ctts_index].duration = ctts_duration; + sc->ctts_count++; + } else { av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); } - av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %u, offset %"PRIx64", dts %"PRId64", " - "size %u, distance %d, keyframe %d\n", st->index, sc->sample_count+i, + + av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " + "size %u, distance %d, keyframe %d\n", st->index, ctts_index, offset, dts, sample_size, distance, keyframe); distance++; dts += sample_duration; @@ -4612,6 +4653,128 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_vpcc(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + int version, color_range, color_primaries, color_trc, color_space; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams - 1]; + + if (atom.size < 5) { + av_log(c->fc, AV_LOG_ERROR, "Empty VP Codec Configuration box\n"); + return AVERROR_INVALIDDATA; + } + + version = avio_r8(pb); + if (version != 1) { + av_log(c->fc, AV_LOG_WARNING, "Unsupported VP Codec Configuration box version %d\n", version); + return 0; + } + avio_skip(pb, 3); /* flags */ + + avio_skip(pb, 2); /* profile + level */ + color_range = avio_r8(pb); /* bitDepth, chromaSubsampling, videoFullRangeFlag */ + color_primaries = avio_r8(pb); + color_trc = avio_r8(pb); + color_space = avio_r8(pb); + if (avio_rb16(pb)) /* codecIntializationDataSize */ + return AVERROR_INVALIDDATA; + + if (!av_color_primaries_name(color_primaries)) + color_primaries = AVCOL_PRI_UNSPECIFIED; + if (!av_color_transfer_name(color_trc)) + color_trc = AVCOL_TRC_UNSPECIFIED; + if (!av_color_space_name(color_space)) + color_space = AVCOL_SPC_UNSPECIFIED; + + st->codecpar->color_range = (color_range & 1) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + st->codecpar->color_primaries = color_primaries; + st->codecpar->color_trc = color_trc; + st->codecpar->color_space = color_space; + + return 0; +} + +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + const int chroma_den = 50000; + const int luma_den = 10000; + int i, j, version; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 5) { + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); + return AVERROR_INVALIDDATA; + } + + version = avio_r8(pb); + if (version) { + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); + return 0; + } + avio_skip(pb, 3); /* flags */ + + sc->mastering = av_mastering_display_metadata_alloc(); + if (!sc->mastering) + return AVERROR(ENOMEM); + + for (i = 0; i < 3; i++) + for (j = 0; j < 2; j++) + sc->mastering->display_primaries[i][j] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + for (i = 0; i < 2; i++) + sc->mastering->white_point[i] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->max_luminance = + av_make_q(lrint(((double)avio_rb32(pb) / (1 << 8)) * luma_den), luma_den); + sc->mastering->min_luminance = + av_make_q(lrint(((double)avio_rb32(pb) / (1 << 14)) * luma_den), luma_den); + + sc->mastering->has_primaries = 1; + sc->mastering->has_luminance = 1; + + return 0; +} + +static int mov_read_coll(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + int version; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 5) { + av_log(c->fc, AV_LOG_ERROR, "Empty Content Light Level box\n"); + return AVERROR_INVALIDDATA; + } + + version = avio_r8(pb); + if (version) { + av_log(c->fc, AV_LOG_WARNING, "Unsupported Content Light Level box version %d\n", version); + return 0; + } + avio_skip(pb, 3); /* flags */ + + sc->coll = av_content_light_metadata_alloc(&sc->coll_size); + if (!sc->coll) + return AVERROR(ENOMEM); + + sc->coll->MaxCLL = avio_rb16(pb); + sc->coll->MaxFALL = avio_rb16(pb); + + return 0; +} + static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -5398,6 +5561,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */ { MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */ { MKTAG('d','O','p','s'), mov_read_dops }, +{ MKTAG('S','m','D','m'), mov_read_smdm }, +{ MKTAG('C','o','L','L'), mov_read_coll }, +{ MKTAG('v','p','c','C'), mov_read_vpcc }, { 0, NULL } }; @@ -5415,7 +5581,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size < 0) atom.size = INT64_MAX; - while (total_size + 8 <= atom.size && !avio_feof(pb)) { + while (total_size <= atom.size - 8 && !avio_feof(pb)) { int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL; a.size = atom.size; a.type=0; @@ -5822,6 +5988,8 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->stereo3d); av_freep(&sc->spherical); + av_freep(&sc->mastering); + av_freep(&sc->coll); } if (mov->dv_demux) { @@ -5926,6 +6094,13 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) } for (i = 0; i < index->item_count; i++) { int64_t time, offset; + + if (avio_feof(f)) { + index->item_count = 0; + av_freep(&index->items); + return AVERROR_INVALIDDATA; + } + if (version == 1) { time = avio_rb64(f); offset = avio_rb64(f); @@ -6172,11 +6347,36 @@ static int mov_read_header(AVFormatContext *s) sc->spherical = NULL; } + if (sc->mastering) { + err = av_stream_add_side_data(st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + (uint8_t *)sc->mastering, + sizeof(*sc->mastering)); + if (err < 0) + return err; + + sc->mastering = NULL; + } + if (sc->coll) { + err = av_stream_add_side_data(st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, + (uint8_t *)sc->coll, + sc->coll_size); + if (err < 0) + return err; + + sc->coll = NULL; + } break; } } ff_configure_buffers_for_index(s, AV_TIME_BASE); + for (i = 0; i < mov->fragment_index_count; i++) { + MOVFragmentIndex *idx = mov->fragment_index_data[i]; + for (j = 0; j < idx->item_count; j++) + if (idx->items[j].moof_offset <= mov->fragment.moof_offset) + idx->items[j].headers_read = 1; + } + return 0; }