X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=69477a0abc76e90a27ddd33b6925c28891b2a3c1;hb=7b6012efaae549b8e624876dba9550cb003f98b1;hp=9462af743aeeb1503ff625b48b01e68ce02d2c51;hpb=856363710f035b128767b1deb3926b38a089fd91;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index 9462af743ae..69477a0abc7 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -196,17 +196,16 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) return 0; } - st = avformat_new_stream(c->fc, NULL); - if (!st) - return AVERROR(ENOMEM); sc = av_mallocz(sizeof(*sc)); if (!sc) return AVERROR(ENOMEM); - st->priv_data = sc; - - ret = av_get_packet(pb, &st->attached_pic, len); - if (ret < 0) + ret = ff_add_attached_pic(c->fc, NULL, pb, NULL, len); + if (ret < 0) { + av_free(sc); return ret; + } + st = c->fc->streams[c->fc->nb_streams - 1]; + st->priv_data = sc; if (st->attached_pic.size >= 8 && id != AV_CODEC_ID_BMP) { if (AV_RB64(st->attached_pic.data) == 0x89504e470d0a1a0a) { @@ -215,13 +214,6 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) id = AV_CODEC_ID_MJPEG; } } - - st->disposition |= AV_DISPOSITION_ATTACHED_PIC; - - st->attached_pic.stream_index = st->index; - st->attached_pic.flags |= AV_PKT_FLAG_KEY; - - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = id; return 0; @@ -288,6 +280,8 @@ static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len) return 0; n_hmmt = avio_rb32(pb); + if (n_hmmt > len / 4) + return AVERROR_INVALIDDATA; for (i = 0; i < n_hmmt && !pb->eof_reached; i++) { int moment_time = avio_rb32(pb); avpriv_new_chapter(c->fc, i, av_make_q(1, 1000), moment_time, AV_NOPTS_VALUE, NULL); @@ -402,7 +396,7 @@ retry: if (c->itunes_metadata && atom.size > 8) { int data_size = avio_rb32(pb); int tag = avio_rl32(pb); - if (tag == MKTAG('d','a','t','a') && data_size <= atom.size) { + if (tag == MKTAG('d','a','t','a') && data_size <= atom.size && data_size >= 16) { data_type = avio_rb32(pb); // type avio_rb32(pb); // unknown str_size = data_size - 16; @@ -588,6 +582,11 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) entries >= UINT_MAX / sizeof(*sc->drefs)) return AVERROR_INVALIDDATA; + for (i = 0; i < sc->drefs_count; i++) { + MOVDref *dref = &sc->drefs[i]; + av_freep(&dref->path); + av_freep(&dref->dir); + } av_free(sc->drefs); sc->drefs_count = 0; sc->drefs = av_mallocz(entries * sizeof(*sc->drefs)); @@ -942,6 +941,7 @@ static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ret; } +/* This atom overrides any previously set aspect ratio */ static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom) { const int num = avio_rb32(pb); @@ -952,13 +952,7 @@ static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; st = c->fc->streams[c->fc->nb_streams-1]; - if ((st->sample_aspect_ratio.den != 1 || st->sample_aspect_ratio.num) && // default - (den != st->sample_aspect_ratio.den || num != st->sample_aspect_ratio.num)) { - av_log(c->fc, AV_LOG_WARNING, - "sample aspect ratio already set to %d:%d, ignoring 'pasp' atom (%d:%d)\n", - st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, - num, den); - } else if (den != 0) { + if (den != 0) { av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, num, den, 32767); } @@ -1075,6 +1069,30 @@ fail: return ret; } +static int mov_aaxc_crypto(MOVContext *c) +{ + if (c->audible_key_size != 16) { + av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_key value needs to be 16 bytes!\n"); + return AVERROR(EINVAL); + } + + if (c->audible_iv_size != 16) { + av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_iv value needs to be 16 bytes!\n"); + return AVERROR(EINVAL); + } + + c->aes_decrypt = av_aes_alloc(); + if (!c->aes_decrypt) { + return AVERROR(ENOMEM); + } + + memcpy(c->file_key, c->audible_key, 16); + memcpy(c->file_iv, c->audible_iv, 16); + c->aax_mode = 1; + + return 0; +} + // Audible AAX (and AAX+) bytestream decryption static int aax_filter(uint8_t *input, int size, MOVContext *c) { @@ -1123,6 +1141,11 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dict_set(&c->fc->metadata, "compatible_brands", comp_brands_str, AV_DICT_DONT_STRDUP_VAL); + // Logic for handling Audible's .aaxc files + if (!strcmp(type, "aaxc")) { + mov_aaxc_crypto(c); + } + return 0; } @@ -1243,6 +1266,10 @@ static int64_t get_frag_time(MOVFragmentIndex *frag_index, if (track_id >= 0) { frag_stream_info = get_frag_stream_info(frag_index, index, track_id); + if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) + return frag_stream_info->sidx_pts; + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) + return frag_stream_info->first_tfra_pts; return frag_stream_info->sidx_pts; } @@ -1475,9 +1502,9 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "time scale = %i\n", c->time_scale); c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */ - // set the AVCodecContext duration because the duration of individual tracks + // set the AVFormatContext duration because the duration of individual tracks // may be inaccurate - if (c->time_scale > 0 && !c->trex_data) + if (!c->trex_data) c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale); avio_rb32(pb); /* preferred scale */ @@ -1767,8 +1794,8 @@ static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; den *= 2; case 1: - c->fc->streams[c->fc->nb_streams-1]->display_aspect_ratio.num = num; - c->fc->streams[c->fc->nb_streams-1]->display_aspect_ratio.den = den; + c->fc->streams[c->fc->nb_streams-1]->internal->display_aspect_ratio.num = num; + c->fc->streams[c->fc->nb_streams-1]->internal->display_aspect_ratio.den = den; default: return 0; } @@ -1997,8 +2024,10 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!entries) return 0; - if (sc->chunk_offsets) - av_log(c->fc, AV_LOG_WARNING, "Duplicated STCO atom\n"); + if (sc->chunk_offsets) { + av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicated STCO atom\n"); + return 0; + } av_free(sc->chunk_offsets); sc->chunk_count = 0; sc->chunk_offsets = av_malloc_array(entries, sizeof(*sc->chunk_offsets)); @@ -2066,6 +2095,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, uint8_t codec_name[32] = { 0 }; int64_t stsd_start; unsigned int len; + uint32_t id = 0; /* The first 16 bytes of the video sample description are already * read in ff_mov_read_stsd_entries() */ @@ -2073,7 +2103,8 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, avio_rb16(pb); /* version */ avio_rb16(pb); /* revision level */ - avio_rb32(pb); /* vendor */ + id = avio_rl32(pb); /* vendor */ + av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); avio_rb32(pb); /* temporal quality */ avio_rb32(pb); /* spatial quality */ @@ -2121,10 +2152,12 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, { int bits_per_sample, flags; uint16_t version = avio_rb16(pb); + uint32_t id = 0; AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE); avio_rb16(pb); /* revision level */ - avio_rb32(pb); /* vendor */ + id = avio_rl32(pb); /* vendor */ + av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); st->codecpar->channels = avio_rb16(pb); /* channel count */ st->codecpar->bits_per_coded_sample = avio_rb16(pb); /* sample size */ @@ -2219,7 +2252,7 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, } bits_per_sample = av_get_bits_per_sample(st->codecpar->codec_id); - if (bits_per_sample) { + if (bits_per_sample && (bits_per_sample >> 3) * (uint64_t)st->codecpar->channels <= INT_MAX) { st->codecpar->bits_per_coded_sample = bits_per_sample; sc->sample_size = (bits_per_sample >> 3) * st->codecpar->channels; } @@ -2312,19 +2345,6 @@ FF_DISABLE_DEPRECATION_WARNINGS st->codec->time_base = av_inv_q(st->avg_frame_rate); FF_ENABLE_DEPRECATION_WARNINGS #endif - /* adjust for per frame dur in counter mode */ - if (tmcd_ctx->tmcd_flags & 0x0008) { - int timescale = AV_RB32(st->codecpar->extradata + 8); - int framedur = AV_RB32(st->codecpar->extradata + 12); - st->avg_frame_rate.num *= timescale; - st->avg_frame_rate.den *= framedur; -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - st->codec->time_base.den *= timescale; - st->codec->time_base.num *= framedur; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } if (size > 30) { uint32_t len = AV_RB32(st->codecpar->extradata + 18); /* name atom length */ uint32_t format = AV_RB32(st->codecpar->extradata + 22); @@ -2569,7 +2589,7 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) entries = avio_rb32(pb); /* Each entry contains a size (4 bytes) and format (4 bytes). */ - if (entries <= 0 || entries > atom.size / 8) { + if (entries <= 0 || entries > atom.size / 8 || entries > 1024) { av_log(c->fc, AV_LOG_ERROR, "invalid STSD entries %d\n", entries); return AVERROR_INVALIDDATA; } @@ -2640,8 +2660,10 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!entries) return 0; - if (sc->stsc_data) - av_log(c->fc, AV_LOG_WARNING, "Duplicated STSC atom\n"); + if (sc->stsc_data) { + av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicated STSC atom\n"); + return 0; + } av_free(sc->stsc_data); sc->stsc_count = 0; sc->stsc_data = av_malloc_array(entries, sizeof(*sc->stsc_data)); @@ -2987,7 +3009,7 @@ static int mov_read_sdtp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_freep(&sc->sdtp_data); sc->sdtp_count = 0; - sc->sdtp_data = av_mallocz(entries); + sc->sdtp_data = av_malloc(entries); if (!sc->sdtp_data) return AVERROR(ENOMEM); @@ -3179,8 +3201,8 @@ static int find_prev_closest_index(AVStream *st, int64_t* ctts_sample) { MOVStreamContext *msc = st->priv_data; - AVIndexEntry *e_keep = st->index_entries; - int nb_keep = st->nb_index_entries; + AVIndexEntry *e_keep = st->internal->index_entries; + int nb_keep = st->internal->nb_index_entries; int64_t i = 0; int64_t index_ctts_count; @@ -3193,8 +3215,8 @@ static int find_prev_closest_index(AVStream *st, timestamp_pts -= msc->dts_shift; } - st->index_entries = e_old; - st->nb_index_entries = nb_old; + st->internal->index_entries = e_old; + st->internal->nb_index_entries = nb_old; *index = av_index_search_timestamp(st, timestamp_pts, flag | AVSEEK_FLAG_BACKWARD); // Keep going backwards in the index entries until the timestamp is the same. @@ -3247,14 +3269,14 @@ static int find_prev_closest_index(AVStream *st, } /* restore AVStream state*/ - st->index_entries = e_keep; - st->nb_index_entries = nb_keep; + st->internal->index_entries = e_keep; + st->internal->nb_index_entries = nb_keep; return *index >= 0 ? 0 : -1; } /** - * Add index entry with the given values, to the end of st->index_entries. - * Returns the new size st->index_entries if successful, else returns -1. + * Add index entry with the given values, to the end of st->internal->index_entries. + * Returns the new size st->internal->index_entries if successful, else returns -1. * * This function is similar to ff_add_index_entry in libavformat/utils.c * except that here we are always unconditionally adding an index entry to @@ -3268,27 +3290,27 @@ static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, { AVIndexEntry *entries, *ie; int64_t index = -1; - const size_t min_size_needed = (st->nb_index_entries + 1) * sizeof(AVIndexEntry); + const size_t min_size_needed = (st->internal->nb_index_entries + 1) * sizeof(AVIndexEntry); // Double the allocation each time, to lower memory fragmentation. // Another difference from ff_add_index_entry function. const size_t requested_size = - min_size_needed > st->index_entries_allocated_size ? - FFMAX(min_size_needed, 2 * st->index_entries_allocated_size) : + min_size_needed > st->internal->index_entries_allocated_size ? + FFMAX(min_size_needed, 2 * st->internal->index_entries_allocated_size) : min_size_needed; - if (st->nb_index_entries + 1U >= UINT_MAX / sizeof(AVIndexEntry)) + if (st->internal->nb_index_entries + 1U >= UINT_MAX / sizeof(AVIndexEntry)) return -1; - entries = av_fast_realloc(st->index_entries, - &st->index_entries_allocated_size, + entries = av_fast_realloc(st->internal->index_entries, + &st->internal->index_entries_allocated_size, requested_size); if (!entries) return -1; - st->index_entries= entries; + st->internal->index_entries= entries; - index= st->nb_index_entries++; + index= st->internal->nb_index_entries++; ie= &entries[index]; ie->pos = pos; @@ -3307,10 +3329,10 @@ static void fix_index_entry_timestamps(AVStream* st, int end_index, int64_t end_ int64_t* frame_duration_buffer, int frame_duration_buffer_size) { int i = 0; - av_assert0(end_index >= 0 && end_index <= st->nb_index_entries); + av_assert0(end_index >= 0 && end_index <= st->internal->nb_index_entries); for (i = 0; i < frame_duration_buffer_size; i++) { end_ts -= frame_duration_buffer[frame_duration_buffer_size - 1 - i]; - st->index_entries[end_index - 1 - i].timestamp = end_ts; + st->internal->index_entries[end_index - 1 - i].timestamp = end_ts; } } @@ -3362,14 +3384,14 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st) if (st->codecpar->video_delay <= 0 && msc->ctts_data && st->codecpar->codec_id == AV_CODEC_ID_H264) { st->codecpar->video_delay = 0; - for (ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { + for (ind = 0; ind < st->internal->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { // Point j to the last elem of the buffer and insert the current pts there. j = buf_start; buf_start = (buf_start + 1); if (buf_start == MAX_REORDER_DELAY + 1) buf_start = 0; - pts_buf[j] = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration; + pts_buf[j] = st->internal->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration; // The timestamps that are already in the sorted buffer, and are greater than the // current pts, are exactly the timestamps that need to be buffered to output PTS @@ -3449,7 +3471,7 @@ static void mov_current_sample_set(MOVStreamContext *sc, int current_sample) } /** - * Fix st->index_entries, so that it contains only the entries (and the entries + * Fix st->internal->index_entries, so that it contains only the entries (and the entries * which are needed to decode them) that fall in the edit list time ranges. * Also fixes the timestamps of the index entries to match the timeline * specified the edit lists. @@ -3457,8 +3479,8 @@ static void mov_current_sample_set(MOVStreamContext *sc, int current_sample) static void mov_fix_index(MOVContext *mov, AVStream *st) { MOVStreamContext *msc = st->priv_data; - AVIndexEntry *e_old = st->index_entries; - int nb_old = st->nb_index_entries; + AVIndexEntry *e_old = st->internal->index_entries; + int nb_old = st->internal->nb_index_entries; const AVIndexEntry *e_old_end = e_old + nb_old; const AVIndexEntry *current = NULL; MOVStts *ctts_data_old = msc->ctts_data; @@ -3503,9 +3525,9 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) current_index_range = msc->index_ranges - 1; // Clean AVStream from traces of old index - st->index_entries = NULL; - st->index_entries_allocated_size = 0; - st->nb_index_entries = 0; + st->internal->index_entries = NULL; + st->internal->index_entries_allocated_size = 0; + st->internal->nb_index_entries = 0; // Clean ctts fields of MOVStreamContext msc->ctts_data = NULL; @@ -3550,7 +3572,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } if (first_non_zero_audio_edit > 0) - st->skip_samples = msc->start_pad = 0; + st->internal->skip_samples = msc->start_pad = 0; } // While reordering frame index according to edit list we must handle properly @@ -3625,7 +3647,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) curr_cts < edit_list_media_time && curr_cts + frame_duration > edit_list_media_time && first_non_zero_audio_edit > 0) { packet_skip_samples = edit_list_media_time - curr_cts; - st->skip_samples += packet_skip_samples; + st->internal->skip_samples += packet_skip_samples; // Shift the index entry timestamp by packet_skip_samples to be correct. edit_list_dts_counter -= packet_skip_samples; @@ -3634,7 +3656,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Make timestamps strictly monotonically increasing for audio, by rewriting timestamps for // discarded packets. if (frame_duration_buffer) { - fix_index_entry_timestamps(st, st->nb_index_entries, edit_list_dts_counter, + fix_index_entry_timestamps(st, st->internal->nb_index_entries, edit_list_dts_counter, frame_duration_buffer, num_discarded_begin); av_freep(&frame_duration_buffer); } @@ -3658,7 +3680,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Increment skip_samples for the first non-zero audio edit list if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { - st->skip_samples += frame_duration; + st->internal->skip_samples += frame_duration; } } } @@ -3673,7 +3695,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Make timestamps strictly monotonically increasing by rewriting timestamps for // discarded packets. if (frame_duration_buffer) { - fix_index_entry_timestamps(st, st->nb_index_entries, edit_list_dts_counter, + fix_index_entry_timestamps(st, st->internal->nb_index_entries, edit_list_dts_counter, frame_duration_buffer, num_discarded_begin); av_freep(&frame_duration_buffer); } @@ -3734,8 +3756,8 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (msc->min_corrected_pts > 0) { av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", msc->min_corrected_pts); - for (i = 0; i < st->nb_index_entries; ++i) { - st->index_entries[i].timestamp -= msc->min_corrected_pts; + for (i = 0; i < st->internal->nb_index_entries; ++i) { + st->internal->index_entries[i].timestamp -= msc->min_corrected_pts; } } } @@ -3744,7 +3766,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Update av stream length, if it ends up shorter than the track's media duration st->duration = FFMIN(st->duration, edit_list_dts_entry_end - start_dts); - msc->start_pad = st->skip_samples; + msc->start_pad = st->internal->skip_samples; // Free the old index and the old CTTS structures av_free(e_old); @@ -3828,17 +3850,17 @@ static void mov_build_index(MOVContext *mov, AVStream *st) current_dts -= sc->dts_shift; last_dts = current_dts; - if (!sc->sample_count || st->nb_index_entries) + if (!sc->sample_count || st->internal->nb_index_entries) return; - if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries) + if (sc->sample_count >= UINT_MAX / sizeof(*st->internal->index_entries) - st->internal->nb_index_entries) return; - if (av_reallocp_array(&st->index_entries, - st->nb_index_entries + sc->sample_count, - sizeof(*st->index_entries)) < 0) { - st->nb_index_entries = 0; + if (av_reallocp_array(&st->internal->index_entries, + st->internal->nb_index_entries + sc->sample_count, + sizeof(*st->internal->index_entries)) < 0) { + st->internal->nb_index_entries = 0; return; } - st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries); + st->internal->index_entries_allocated_size = (st->internal->nb_index_entries + sc->sample_count) * sizeof(*st->internal->index_entries); if (ctts_data_old) { // Expand ctts entries such that we have a 1-1 mapping with samples @@ -3921,7 +3943,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) av_log(mov->fc, AV_LOG_ERROR, "Sample size %u is too large\n", sample_size); return; } - e = &st->index_entries[st->nb_index_entries++]; + e = &st->internal->index_entries[st->internal->nb_index_entries++]; e->pos = current_offset; e->timestamp = current_dts; e->size = sample_size; @@ -3930,7 +3952,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) av_log(mov->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %u, offset %"PRIx64", dts %"PRId64", " "size %u, distance %u, keyframe %d\n", st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries < 100) + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->internal->nb_index_entries < 100) ff_rfps_add_frame(mov->fc, st, current_dts); } @@ -4002,15 +4024,15 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } av_log(mov->fc, AV_LOG_TRACE, "chunk count %u\n", total); - if (total >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries) + if (total >= UINT_MAX / sizeof(*st->internal->index_entries) - st->internal->nb_index_entries) return; - if (av_reallocp_array(&st->index_entries, - st->nb_index_entries + total, - sizeof(*st->index_entries)) < 0) { - st->nb_index_entries = 0; + if (av_reallocp_array(&st->internal->index_entries, + st->internal->nb_index_entries + total, + sizeof(*st->internal->index_entries)) < 0) { + st->internal->nb_index_entries = 0; return; } - st->index_entries_allocated_size = (st->nb_index_entries + total) * sizeof(*st->index_entries); + st->internal->index_entries_allocated_size = (st->internal->nb_index_entries + total) * sizeof(*st->internal->index_entries); // populate index for (i = 0; i < sc->chunk_count; i++) { @@ -4045,7 +4067,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } - if (st->nb_index_entries >= total) { + if (st->internal->nb_index_entries >= total) { av_log(mov->fc, AV_LOG_ERROR, "wrong chunk count %u\n", total); return; } @@ -4053,7 +4075,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) av_log(mov->fc, AV_LOG_ERROR, "Sample size %u is too large\n", size); return; } - e = &st->index_entries[st->nb_index_entries++]; + e = &st->internal->index_entries[st->internal->nb_index_entries++]; e->pos = current_offset; e->timestamp = current_dts; e->size = size; @@ -4076,8 +4098,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } // Update start time of the stream. - if (st->start_time == AV_NOPTS_VALUE && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries > 0) { - st->start_time = st->index_entries[0].timestamp + sc->dts_shift; + if (st->start_time == AV_NOPTS_VALUE && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->internal->nb_index_entries > 0) { + st->start_time = st->internal->index_entries[0].timestamp + sc->dts_shift; if (sc->ctts_data) { st->start_time += sc->ctts_data[0].duration; } @@ -4380,7 +4402,7 @@ static int mov_read_keys(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - int64_t end = avio_tell(pb) + atom.size; + int64_t end = av_sat_add64(avio_tell(pb), atom.size); uint8_t *key = NULL, *val = NULL, *mean = NULL; int i; int ret = 0; @@ -4560,8 +4582,6 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) // save the matrix when it is not the default identity if (!IS_MATRIX_IDENT(res_display_matrix)) { - double rotate; - av_freep(&sc->display_matrix); sc->display_matrix = av_malloc(sizeof(int32_t) * 9); if (!sc->display_matrix) @@ -4570,18 +4590,6 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) sc->display_matrix[i * 3 + j] = res_display_matrix[i][j]; - -#if FF_API_OLD_ROTATE_API - rotate = av_display_rotation_get(sc->display_matrix); - if (!isnan(rotate)) { - char rotate_buf[64]; - rotate = -rotate; - if (rotate < 0) // for backward compatibility - rotate += 360; - snprintf(rotate_buf, sizeof(rotate_buf), "%g", rotate); - av_dict_set(&st->metadata, "rotate", rotate_buf, 0); - } -#endif } // transform the display width/height according to the matrix @@ -4593,7 +4601,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) disp_transform[i] = hypot(sc->display_matrix[0 + i], sc->display_matrix[3 + i]); - if (disp_transform[0] > 0 && disp_transform[1] > 0 && + if (disp_transform[0] > 1 && disp_transform[1] > 1 && disp_transform[0] < (1<<24) && disp_transform[1] < (1<<24) && fabs((disp_transform[0] / disp_transform[1]) - 1.0) > 0.01) st->sample_aspect_ratio = av_d2q( @@ -4775,7 +4783,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) // A valid index_entry means the trun for the fragment was read // and it's samples are in index_entries at the given position. // New index entries will be inserted before the index_entry found. - index_entry_pos = st->nb_index_entries; + index_entry_pos = st->internal->nb_index_entries; for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) { frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id); if (frag_stream_info && frag_stream_info->index_entry >= 0) { @@ -4784,7 +4792,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) break; } } - av_assert0(index_entry_pos <= st->nb_index_entries); + av_assert0(index_entry_pos <= st->internal->nb_index_entries); avio_r8(pb); /* version */ flags = avio_rb24(pb); @@ -4835,22 +4843,22 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "first sample flags 0x%x\n", first_sample_flags); // realloc space for new index entries - if((uint64_t)st->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { - entries = UINT_MAX / sizeof(AVIndexEntry) - st->nb_index_entries; + if((uint64_t)st->internal->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { + entries = UINT_MAX / sizeof(AVIndexEntry) - st->internal->nb_index_entries; av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); } if (entries == 0) return 0; - requested_size = (st->nb_index_entries + entries) * sizeof(AVIndexEntry); - new_entries = av_fast_realloc(st->index_entries, - &st->index_entries_allocated_size, + requested_size = (st->internal->nb_index_entries + entries) * sizeof(AVIndexEntry); + new_entries = av_fast_realloc(st->internal->index_entries, + &st->internal->index_entries_allocated_size, requested_size); if (!new_entries) return AVERROR(ENOMEM); - st->index_entries= new_entries; + st->internal->index_entries= new_entries; - requested_size = (st->nb_index_entries + entries) * sizeof(*sc->ctts_data); + requested_size = (st->internal->nb_index_entries + entries) * sizeof(*sc->ctts_data); old_ctts_allocated_size = sc->ctts_allocated_size; ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, requested_size); @@ -4864,12 +4872,12 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) memset((uint8_t*)(sc->ctts_data) + old_ctts_allocated_size, 0, sc->ctts_allocated_size - old_ctts_allocated_size); - if (index_entry_pos < st->nb_index_entries) { + if (index_entry_pos < st->internal->nb_index_entries) { // Make hole in index_entries and ctts_data for new samples - memmove(st->index_entries + index_entry_pos + entries, - st->index_entries + index_entry_pos, - sizeof(*st->index_entries) * - (st->nb_index_entries - index_entry_pos)); + memmove(st->internal->index_entries + index_entry_pos + entries, + st->internal->index_entries + index_entry_pos, + sizeof(*st->internal->index_entries) * + (st->internal->nb_index_entries - index_entry_pos)); memmove(sc->ctts_data + index_entry_pos + entries, sc->ctts_data + index_entry_pos, sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos)); @@ -4878,15 +4886,15 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } - st->nb_index_entries += entries; - sc->ctts_count = st->nb_index_entries; + st->internal->nb_index_entries += entries; + sc->ctts_count = st->internal->nb_index_entries; // Record the index_entry position in frag_index of this fragment if (frag_stream_info) frag_stream_info->index_entry = index_entry_pos; if (index_entry_pos > 0) - prev_dts = st->index_entries[index_entry_pos-1].timestamp; + prev_dts = st->internal->index_entries[index_entry_pos-1].timestamp; for (i = 0; i < entries && !pb->eof_reached; i++) { unsigned sample_size = frag->size; @@ -4935,11 +4943,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (prev_dts >= dts) index_entry_flags |= AVINDEX_DISCARD_FRAME; - st->index_entries[index_entry_pos].pos = offset; - st->index_entries[index_entry_pos].timestamp = dts; - st->index_entries[index_entry_pos].size= sample_size; - st->index_entries[index_entry_pos].min_distance= distance; - st->index_entries[index_entry_pos].flags = index_entry_flags; + st->internal->index_entries[index_entry_pos].pos = offset; + st->internal->index_entries[index_entry_pos].timestamp = dts; + st->internal->index_entries[index_entry_pos].size= sample_size; + st->internal->index_entries[index_entry_pos].min_distance= distance; + st->internal->index_entries[index_entry_pos].flags = index_entry_flags; sc->ctts_data[index_entry_pos].count = 1; sc->ctts_data[index_entry_pos].duration = ctts_duration; @@ -4966,16 +4974,16 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) // EOF found before reading all entries. Fix the hole this would // leave in index_entries and ctts_data int gap = entries - i; - memmove(st->index_entries + index_entry_pos, - st->index_entries + index_entry_pos + gap, - sizeof(*st->index_entries) * - (st->nb_index_entries - (index_entry_pos + gap))); + memmove(st->internal->index_entries + index_entry_pos, + st->internal->index_entries + index_entry_pos + gap, + sizeof(*st->internal->index_entries) * + (st->internal->nb_index_entries - (index_entry_pos + gap))); memmove(sc->ctts_data + index_entry_pos, sc->ctts_data + index_entry_pos + gap, sizeof(*sc->ctts_data) * (sc->ctts_count - (index_entry_pos + gap))); - st->nb_index_entries -= gap; + st->internal->nb_index_entries -= gap; sc->ctts_count -= gap; if (index_entry_pos < sc->current_sample) { sc->current_sample -= gap; @@ -4988,11 +4996,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) // fragment that overlap with AVINDEX_DISCARD_FRAME prev_dts = AV_NOPTS_VALUE; if (index_entry_pos > 0) - prev_dts = st->index_entries[index_entry_pos-1].timestamp; - for (i = index_entry_pos; i < st->nb_index_entries; i++) { - if (prev_dts < st->index_entries[i].timestamp) + prev_dts = st->internal->index_entries[index_entry_pos-1].timestamp; + for (i = index_entry_pos; i < st->internal->nb_index_entries; i++) { + if (prev_dts < st->internal->index_entries[i].timestamp) break; - st->index_entries[i].flags |= AVINDEX_DISCARD_FRAME; + st->internal->index_entries[i].flags |= AVINDEX_DISCARD_FRAME; } // If a hole was created to insert the new index_entries into, @@ -5018,8 +5026,9 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int64_t stream_size = avio_size(pb); - int64_t offset = avio_tell(pb) + atom.size, pts, timestamp; + int64_t offset = av_sat_add64(avio_tell(pb), atom.size), pts, timestamp; uint8_t version, is_complete; + int64_t offadd; unsigned i, j, track_id, item_count; AVStream *st = NULL; AVStream *ref_st = NULL; @@ -5057,11 +5066,15 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (version == 0) { pts = avio_rb32(pb); - offset += avio_rb32(pb); + offadd= avio_rb32(pb); } else { pts = avio_rb64(pb); - offset += avio_rb64(pb); + offadd= avio_rb64(pb); } + if (av_sat_add64(offset, offadd) != offset + (uint64_t)offadd) + return AVERROR_INVALIDDATA; + + offset += (uint64_t)offadd; avio_rb16(pb); // reserved @@ -5084,6 +5097,10 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (frag_stream_info) frag_stream_info->sidx_pts = timestamp; + if (av_sat_add64(offset, size) != offset + size || + av_sat_add64(pts, duration) != pts + (uint64_t)duration + ) + return AVERROR_INVALIDDATA; offset += size; pts += duration; } @@ -5521,6 +5538,10 @@ static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_ERROR, "Empty stereoscopic video box\n"); return AVERROR_INVALIDDATA; } + + if (sc->stereo3d) + return AVERROR_INVALIDDATA; + avio_skip(pb, 4); /* version + flags */ mode = avio_r8(pb); @@ -6344,7 +6365,8 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; uint8_t *side_data, *extra_data, *old_side_data; size_t side_data_size; - int ret = 0, old_side_data_size; + buffer_size_t old_side_data_size; + int ret = 0; unsigned int version, kid_count, extra_data_size, alloc_size = 0; if (c->fc->nb_streams < 1) @@ -6968,6 +6990,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) uint32_t type; avio_skip(pb, 4); type = avio_rl32(pb); + if (avio_feof(pb)) + break; avio_seek(pb, -8, SEEK_CUR); if (type == MKTAG('m','v','h','d') || type == MKTAG('c','m','o','v')) { @@ -7031,7 +7055,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) c->atom_depth --; return err; } - if (c->found_moov && c->found_mdat && + if (c->found_moov && c->found_mdat && a.size <= INT64_MAX - start_pos && ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) || start_pos + a.size == avio_size(pb))) { if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) @@ -7070,9 +7094,22 @@ static int mov_probe(const AVProbeData *p) /* check file header */ offset = 0; for (;;) { + int64_t size; + int minsize = 8; /* ignore invalid offset */ - if ((offset + 8) > (unsigned int)p->buf_size) + if ((offset + 8ULL) > (unsigned int)p->buf_size) break; + size = AV_RB32(p->buf + offset); + if (size == 1 && offset + 16 <= (unsigned int)p->buf_size) { + size = AV_RB64(p->buf+offset + 8); + minsize = 16; + } else if (size == 0) { + size = p->buf_size - offset; + } + if (size < minsize) { + offset += 4; + continue; + } tag = AV_RL32(p->buf + offset + 4); switch(tag) { /* check for obvious tags */ @@ -7082,12 +7119,7 @@ static int mov_probe(const AVProbeData *p) case MKTAG('p','n','o','t'): /* detect movs with preview pics like ew.mov and april.mov */ case MKTAG('u','d','t','a'): /* Packet Video PVAuthor adds this and a lot of more junk */ case MKTAG('f','t','y','p'): - if (AV_RB32(p->buf+offset) < 8 && - (AV_RB32(p->buf+offset) != 1 || - offset + 12 > (unsigned int)p->buf_size || - AV_RB64(p->buf+offset + 8) == 0)) { - score = FFMAX(score, AVPROBE_SCORE_EXTENSION); - } else if (tag == MKTAG('f','t','y','p') && + if (tag == MKTAG('f','t','y','p') && ( AV_RL32(p->buf + offset + 8) == MKTAG('j','p','2',' ') || AV_RL32(p->buf + offset + 8) == MKTAG('j','p','x',' ') )) { @@ -7095,7 +7127,6 @@ static int mov_probe(const AVProbeData *p) } else { score = AVPROBE_SCORE_MAX; } - offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; break; /* those are more common words, so rate then a bit less */ case MKTAG('e','d','i','w'): /* xdcam files have reverted first tags */ @@ -7104,7 +7135,6 @@ static int mov_probe(const AVProbeData *p) case MKTAG('j','u','n','k'): case MKTAG('p','i','c','t'): score = FFMAX(score, AVPROBE_SCORE_MAX - 5); - offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; break; case MKTAG(0x82,0x82,0x7f,0x7d): case MKTAG('s','k','i','p'): @@ -7112,11 +7142,11 @@ static int mov_probe(const AVProbeData *p) case MKTAG('p','r','f','l'): /* if we only find those cause probedata is too small at least rate them */ score = FFMAX(score, AVPROBE_SCORE_EXTENSION); - offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; break; - default: - offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; } + if (size > INT64_MAX - offset) + break; + offset += size; } if (score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) { /* moov atom in the header - we should make sure that this is not a @@ -7172,27 +7202,24 @@ static void mov_read_chapters(AVFormatContext *s) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS; - if (st->nb_index_entries) { + if (st->internal->nb_index_entries) { // Retrieve the first frame, if possible - AVIndexEntry *sample = &st->index_entries[0]; + AVIndexEntry *sample = &st->internal->index_entries[0]; if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { av_log(s, AV_LOG_ERROR, "Failed to retrieve first frame\n"); goto finish; } - if (av_get_packet(sc->pb, &st->attached_pic, sample->size) < 0) + if (ff_add_attached_pic(s, st, sc->pb, NULL, sample->size) < 0) goto finish; - - st->attached_pic.stream_index = st->index; - st->attached_pic.flags |= AV_PKT_FLAG_KEY; } } else { st->codecpar->codec_type = AVMEDIA_TYPE_DATA; st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; st->discard = AVDISCARD_ALL; - for (i = 0; i < st->nb_index_entries; i++) { - AVIndexEntry *sample = &st->index_entries[i]; - int64_t end = i+1 < st->nb_index_entries ? st->index_entries[i+1].timestamp : st->duration; + for (i = 0; i < st->internal->nb_index_entries; i++) { + AVIndexEntry *sample = &st->internal->index_entries[i]; + int64_t end = i+1 < st->internal->nb_index_entries ? st->internal->index_entries[i+1].timestamp : st->duration; uint8_t *title; uint16_t ch; int len, title_len; @@ -7265,10 +7292,10 @@ static int mov_read_rtmd_track(AVFormatContext *s, AVStream *st) int64_t cur_pos = avio_tell(sc->pb); int hh, mm, ss, ff, drop; - if (!st->nb_index_entries) + if (!st->internal->nb_index_entries) return -1; - avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); + avio_seek(sc->pb, st->internal->index_entries->pos, SEEK_SET); avio_skip(s->pb, 13); hh = avio_r8(s->pb); mm = avio_r8(s->pb); @@ -7290,10 +7317,10 @@ static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) int64_t cur_pos = avio_tell(sc->pb); uint32_t value; - if (!st->nb_index_entries) + if (!st->internal->nb_index_entries) return -1; - avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); + avio_seek(sc->pb, st->internal->index_entries->pos, SEEK_SET); value = avio_rb32(s->pb); if (sc->tmcd_flags & 0x0001) flags |= AV_TIMECODE_FLAG_DROPFRAME; @@ -7529,6 +7556,7 @@ static int mov_read_mfra(MOVContext *c, AVIOContext *f) goto fail; } while (!ret); ret = 0; + c->frag_index.complete = 1; fail: seek_ret = avio_seek(f, original_pos, SEEK_SET); if (seek_ret < 0) { @@ -7615,7 +7643,7 @@ static int mov_read_header(AVFormatContext *s) fix_timescale(mov, sc); if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->codec_id == AV_CODEC_ID_AAC) { - st->skip_samples = sc->start_pad; + st->internal->skip_samples = sc->start_pad; } if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, @@ -7757,8 +7785,8 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) for (i = 0; i < s->nb_streams; i++) { AVStream *avst = s->streams[i]; MOVStreamContext *msc = avst->priv_data; - if (msc->pb && msc->current_sample < avst->nb_index_entries) { - AVIndexEntry *current_sample = &avst->index_entries[msc->current_sample]; + if (msc->pb && msc->current_sample < avst->internal->nb_index_entries) { + AVIndexEntry *current_sample = &avst->internal->index_entries[msc->current_sample]; int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale); av_log(s, AV_LOG_TRACE, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts); if (!sample || (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && current_sample->pos < sample->pos) || @@ -7897,6 +7925,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) sc->ffindex, sample->pos); if (should_retry(sc->pb, ret64)) { mov_current_sample_dec(sc); + } else if (ret64 < 0) { + return (int)ret64; } return AVERROR_INVALIDDATA; } @@ -7961,8 +7991,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) sc->ctts_sample = 0; } } else { - int64_t next_dts = (sc->current_sample < st->nb_index_entries) ? - st->index_entries[sc->current_sample].timestamp : st->duration; + int64_t next_dts = (sc->current_sample < st->internal->nb_index_entries) ? + st->internal->index_entries[sc->current_sample].timestamp : st->duration; if (next_dts >= pkt->dts) pkt->duration = next_dts - pkt->dts; @@ -8043,7 +8073,7 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, sample = av_index_search_timestamp(st, timestamp, flags); av_log(s, AV_LOG_TRACE, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample); - if (sample < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp) + if (sample < 0 && st->internal->nb_index_entries && timestamp < st->internal->index_entries[0].timestamp) sample = 0; if (sample < 0) /* not sure what to do */ return AVERROR_INVALIDDATA; @@ -8081,6 +8111,22 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, return sample; } +static int64_t mov_get_skip_samples(AVStream *st, int sample) +{ + MOVStreamContext *sc = st->priv_data; + int64_t first_ts = st->internal->index_entries[0].timestamp; + int64_t ts = st->internal->index_entries[sample].timestamp; + int64_t off; + + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) + return 0; + + /* compute skip samples according to stream start_pad, seek ts and first ts */ + off = av_rescale_q(ts - first_ts, st->time_base, + (AVRational){1, st->codecpar->sample_rate}); + return FFMAX(sc->start_pad - off, 0); +} + static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) { MOVContext *mc = s->priv_data; @@ -8098,19 +8144,20 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti if (mc->seek_individually) { /* adjust seek timestamp to found sample timestamp */ - int64_t seek_timestamp = st->index_entries[sample].timestamp; + int64_t seek_timestamp = st->internal->index_entries[sample].timestamp; + st->internal->skip_samples = mov_get_skip_samples(st, sample); for (i = 0; i < s->nb_streams; i++) { int64_t timestamp; - MOVStreamContext *sc = s->streams[i]->priv_data; st = s->streams[i]; - st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0; if (stream_index == i) continue; timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base); - mov_seek_stream(s, st, timestamp, flags); + sample = mov_seek_stream(s, st, timestamp, flags); + if (sample >= 0) + st->internal->skip_samples = mov_get_skip_samples(st, sample); } } else { for (i = 0; i < s->nb_streams; i++) { @@ -8169,6 +8216,10 @@ static const AVOption mov_options[] = { AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS }, { "activation_bytes", "Secret bytes for Audible AAX files", OFFSET(activation_bytes), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM }, + { "audible_key", "AES-128 Key for Audible AAXC files", OFFSET(audible_key), + AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM }, + { "audible_iv", "AES-128 IV for Audible AAXC files", OFFSET(audible_iv), + AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM }, { "audible_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files! "Fixed key used for handling Audible AAX files", OFFSET(audible_fixed_key), AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"},