X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=7fd43a8fc5bae561e66c4895e4a9ae8f6bd743f4;hb=9b72cea4463dd2fabcd9ba1454a0855e521d0148;hp=a7d444b0eeea128e18312a4c6415380a24c396de;hpb=34a0a9746b2f441db7c45983838a88aa87a33834;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index a7d444b0eee..7fd43a8fc5b 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -46,9 +46,11 @@ #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" #include "libavutil/timecode.h" +#include "libavutil/dovi_meta.h" #include "libavcodec/ac3tab.h" #include "libavcodec/flac.h" #include "libavcodec/mpegaudiodecheader.h" +#include "libavcodec/mlp_parse.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" @@ -179,7 +181,6 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len, static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) { - AVPacket pkt; AVStream *st; MOVStreamContext *sc; enum AVCodecID id; @@ -203,12 +204,12 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) return AVERROR(ENOMEM); st->priv_data = sc; - ret = av_get_packet(pb, &pkt, len); + ret = av_get_packet(pb, &st->attached_pic, len); if (ret < 0) return ret; - if (pkt.size >= 8 && id != AV_CODEC_ID_BMP) { - if (AV_RB64(pkt.data) == 0x89504e470d0a1a0a) { + if (st->attached_pic.size >= 8 && id != AV_CODEC_ID_BMP) { + if (AV_RB64(st->attached_pic.data) == 0x89504e470d0a1a0a) { id = AV_CODEC_ID_PNG; } else { id = AV_CODEC_ID_MJPEG; @@ -217,7 +218,6 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) st->disposition |= AV_DISPOSITION_ATTACHED_PIC; - st->attached_pic = pkt; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; @@ -297,7 +297,7 @@ static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len) static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - char tmp_key[5]; + char tmp_key[AV_FOURCC_MAX_STRING_SIZE] = {0}; char key2[32], language[4] = {0}; char *str = NULL; const char *key = NULL; @@ -444,8 +444,7 @@ retry: str_size = atom.size; if (c->export_all && !key) { - snprintf(tmp_key, 5, "%.4s", (char*)&atom.type); - key = tmp_key; + key = av_fourcc_make_string(tmp_key, atom.type); } if (!key) @@ -588,7 +587,7 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) entries > (atom.size - 1) / MIN_DATA_ENTRY_BOX_SIZE + 1 || entries >= UINT_MAX / sizeof(*sc->drefs)) return AVERROR_INVALIDDATA; - sc->drefs_count = 0; + av_free(sc->drefs); sc->drefs_count = 0; sc->drefs = av_mallocz(entries * sizeof(*sc->drefs)); @@ -644,7 +643,7 @@ 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(avio_feof(pb)) + if (avio_feof(pb)) return AVERROR_EOF; type = avio_rb16(pb); len = avio_rb16(pb); @@ -857,26 +856,20 @@ static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - const uint32_t ddts_size = 20; +#define DDTS_SIZE 20 + uint8_t buf[DDTS_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; AVStream *st = NULL; - uint8_t *buf = NULL; uint32_t frame_duration_code = 0; uint32_t channel_layout_code = 0; GetBitContext gb; + int ret; - buf = av_malloc(ddts_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!buf) { - return AVERROR(ENOMEM); - } - if (avio_read(pb, buf, ddts_size) < ddts_size) { - av_free(buf); - return AVERROR_INVALIDDATA; - } + if ((ret = ffio_read_size(pb, buf, DDTS_SIZE)) < 0) + return ret; - init_get_bits(&gb, buf, 8*ddts_size); + 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]; @@ -884,7 +877,6 @@ 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 */ @@ -901,7 +893,7 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) (frame_duration_code == 3) ? 4096 : 0; if (channel_layout_code > 0xff) { - av_log(c->fc, AV_LOG_WARNING, "Unsupported DTS audio channel layout"); + av_log(c->fc, AV_LOG_WARNING, "Unsupported DTS audio channel layout\n"); } st->codecpar->channel_layout = ((channel_layout_code & 0x1) ? AV_CH_FRONT_CENTER : 0) | @@ -912,7 +904,6 @@ 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; } @@ -1004,6 +995,7 @@ static int mov_read_adrm(MOVContext *c, AVIOContext *pb, MOVAtom atom) sha = av_sha_alloc(); if (!sha) return AVERROR(ENOMEM); + av_free(c->aes_decrypt); c->aes_decrypt = av_aes_alloc(); if (!c->aes_decrypt) { ret = AVERROR(ENOMEM); @@ -1116,7 +1108,7 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0); comp_brand_size = atom.size - 8; - if (comp_brand_size < 0) + if (comp_brand_size < 0 || comp_brand_size == INT_MAX) return AVERROR_INVALIDDATA; comp_brands_str = av_malloc(comp_brand_size + 1); /* Add null terminator */ if (!comp_brands_str) @@ -1128,8 +1120,8 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ret; } comp_brands_str[comp_brand_size] = 0; - av_dict_set(&c->fc->metadata, "compatible_brands", comp_brands_str, 0); - av_freep(&comp_brands_str); + av_dict_set(&c->fc->metadata, "compatible_brands", + comp_brands_str, AV_DICT_DONT_STRDUP_VAL); return 0; } @@ -1315,7 +1307,7 @@ static int update_frag_index(MOVContext *c, int64_t offset) &c->frag_index.allocated_size, (c->frag_index.nb_items + 1) * sizeof(*c->frag_index.item)); - if(!item) + if (!item) return -1; c->frag_index.item = item; @@ -1326,12 +1318,15 @@ static int update_frag_index(MOVContext *c, int64_t offset) for (i = 0; i < c->fc->nb_streams; i++) { // Avoid building frag index if streams lack track id. - if (c->fc->streams[i]->id < 0) + if (c->fc->streams[i]->id < 0) { + av_free(frag_stream_info); return AVERROR_INVALIDDATA; + } frag_stream_info[i].id = c->fc->streams[i]->id; frag_stream_info[i].sidx_pts = AV_NOPTS_VALUE; frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE; + frag_stream_info[i].next_trun_dts = AV_NOPTS_VALUE; frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE; frag_stream_info[i].index_entry = -1; frag_stream_info[i].encryption_index = NULL; @@ -1393,14 +1388,14 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_default(c, pb, atom); } -static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time) +static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time, void *logctx) { if (time) { - if(time >= 2082844800) + if (time >= 2082844800) time -= 2082844800; /* seconds between 1904-01-01 and Epoch */ if ((int64_t)(time * 1000000ULL) / 1000000 != time) { - av_log(NULL, AV_LOG_DEBUG, "creation_time is not representable\n"); + av_log(logctx, AV_LOG_DEBUG, "creation_time is not representable\n"); return; } @@ -1440,7 +1435,7 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) creation_time = avio_rb32(pb); avio_rb32(pb); /* modification time */ } - mov_metadata_creation_time(&st->metadata, creation_time); + mov_metadata_creation_time(&st->metadata, creation_time, c->fc); sc->time_scale = avio_rb32(pb); if (sc->time_scale <= 0) { @@ -1471,7 +1466,7 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) creation_time = avio_rb32(pb); avio_rb32(pb); /* modification time */ } - mov_metadata_creation_time(&c->fc->metadata, creation_time); + mov_metadata_creation_time(&c->fc->metadata, creation_time, c->fc); 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, defaulting to 1\n", c->time_scale); @@ -1480,7 +1475,7 @@ 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) c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale); @@ -1543,6 +1538,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; + uint8_t *icc_profile; char color_parameter_type[5] = { 0 }; uint16_t color_primaries, color_trc, color_matrix; int ret; @@ -1555,41 +1551,50 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) return ret; if (strncmp(color_parameter_type, "nclx", 4) && - strncmp(color_parameter_type, "nclc", 4)) { + strncmp(color_parameter_type, "nclc", 4) && + strncmp(color_parameter_type, "prof", 4)) { av_log(c->fc, AV_LOG_WARNING, "unsupported color_parameter_type %s\n", color_parameter_type); return 0; } - color_primaries = avio_rb16(pb); - color_trc = avio_rb16(pb); - color_matrix = avio_rb16(pb); - - av_log(c->fc, AV_LOG_TRACE, - "%s: pri %d trc %d matrix %d", - color_parameter_type, color_primaries, color_trc, color_matrix); - - if (!strncmp(color_parameter_type, "nclx", 4)) { - uint8_t color_range = avio_r8(pb) >> 7; - av_log(c->fc, AV_LOG_TRACE, " full %"PRIu8"", color_range); - if (color_range) - st->codecpar->color_range = AVCOL_RANGE_JPEG; - else - st->codecpar->color_range = AVCOL_RANGE_MPEG; - } + if (!strncmp(color_parameter_type, "prof", 4)) { + icc_profile = av_stream_new_side_data(st, AV_PKT_DATA_ICC_PROFILE, atom.size - 4); + if (!icc_profile) + return AVERROR(ENOMEM); + ret = ffio_read_size(pb, icc_profile, atom.size - 4); + if (ret < 0) + return ret; + } else { + color_primaries = avio_rb16(pb); + color_trc = avio_rb16(pb); + color_matrix = avio_rb16(pb); - 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_matrix)) - color_matrix = AVCOL_SPC_UNSPECIFIED; + av_log(c->fc, AV_LOG_TRACE, + "%s: pri %d trc %d matrix %d", + color_parameter_type, color_primaries, color_trc, color_matrix); + + if (!strncmp(color_parameter_type, "nclx", 4)) { + uint8_t color_range = avio_r8(pb) >> 7; + av_log(c->fc, AV_LOG_TRACE, " full %"PRIu8"", color_range); + if (color_range) + st->codecpar->color_range = AVCOL_RANGE_JPEG; + else + st->codecpar->color_range = AVCOL_RANGE_MPEG; + } - 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"); + 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_matrix)) + 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; } @@ -1620,7 +1625,7 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } 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); + av_log(c->fc, AV_LOG_ERROR, "Unknown MOV field order 0x%04x\n", mov_field_order); } st->codecpar->field_order = decoded_field_order; @@ -1713,7 +1718,7 @@ static int mov_read_dpxe(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI); - if(ret == 0) + if (!ret) ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_DNXHD); return ret; } @@ -1797,19 +1802,19 @@ static int mov_read_aclr(MOVContext *c, AVIOContext *pb, MOVAtom atom) par->color_range = AVCOL_RANGE_JPEG; break; default: - av_log(c, AV_LOG_WARNING, "ignored unknown aclr value (%d)\n", range_value); + av_log(c->fc, AV_LOG_WARNING, "ignored unknown aclr value (%d)\n", range_value); break; } - ff_dlog(c, "color_range: %d\n", par->color_range); + ff_dlog(c->fc, "color_range: %d\n", par->color_range); } else { /* For some reason the whole atom was not added to the extradata */ - av_log(c, AV_LOG_ERROR, "aclr not decoded - incomplete atom\n"); + av_log(c->fc, AV_LOG_ERROR, "aclr not decoded - incomplete atom\n"); } } else { - av_log(c, AV_LOG_ERROR, "aclr not decoded - unable to add atom to extradata\n"); + av_log(c->fc, AV_LOG_ERROR, "aclr not decoded - unable to add atom to extradata\n"); } } else { - av_log(c, AV_LOG_WARNING, "aclr not decoded - unexpected size %"PRId64"\n", atom.size); + av_log(c->fc, AV_LOG_WARNING, "aclr not decoded - unexpected size %"PRId64"\n", atom.size); } } @@ -1837,7 +1842,6 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->codec_id == AV_CODEC_ID_QDMC || st->codecpar->codec_id == AV_CODEC_ID_SPEEX) { // pass all frma atom to codec, needed at least for QDMC and QDM2 - av_freep(&st->codecpar->extradata); ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size); if (ret < 0) return ret; @@ -1901,10 +1905,9 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_default(c, pb, atom); } if (st->codecpar->extradata_size > 1 && st->codecpar->extradata) { - av_log(c, AV_LOG_WARNING, "ignoring multiple glbl\n"); + av_log(c->fc, AV_LOG_WARNING, "ignoring multiple glbl\n"); return 0; } - av_freep(&st->codecpar->extradata); ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size); if (ret < 0) return ret; @@ -1937,7 +1940,6 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; avio_seek(pb, 6, SEEK_CUR); - av_freep(&st->codecpar->extradata); ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size - 7); if (ret < 0) return ret; @@ -1965,7 +1967,6 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; avio_skip(pb, 40); - av_freep(&st->codecpar->extradata); ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size - 40); if (ret < 0) return ret; @@ -1979,6 +1980,10 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVStreamContext *sc; unsigned int i, entries; + if (c->trak_index < 0) { + av_log(c->fc, AV_LOG_WARNING, "STCO outside TRAK\n"); + return 0; + } if (c->fc->nb_streams < 1) return 0; st = c->fc->streams[c->fc->nb_streams-1]; @@ -2254,7 +2259,7 @@ static int mov_rewrite_dvd_sub_extradata(AVStream *st) { char buf[256] = {0}; uint8_t *src = st->codecpar->extradata; - int i; + int i, ret; if (st->codecpar->extradata_size != 64) return 0; @@ -2274,12 +2279,9 @@ static int mov_rewrite_dvd_sub_extradata(AVStream *st) if (av_strlcat(buf, "\n", sizeof(buf)) >= sizeof(buf)) return 0; - av_freep(&st->codecpar->extradata); - st->codecpar->extradata_size = 0; - st->codecpar->extradata = av_mallocz(strlen(buf) + AV_INPUT_BUFFER_PADDING_SIZE); - if (!st->codecpar->extradata) - return AVERROR(ENOMEM); - st->codecpar->extradata_size = strlen(buf); + ret = ff_alloc_extradata(st->codecpar, strlen(buf)); + if (ret < 0) + return ret; memcpy(st->codecpar->extradata, buf, st->codecpar->extradata_size); return 0; @@ -2303,8 +2305,8 @@ static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb, int val; val = AV_RB32(st->codecpar->extradata + 4); tmcd_ctx->tmcd_flags = val; - st->avg_frame_rate.num = st->codecpar->extradata[16]; /* number of frame */ - st->avg_frame_rate.den = 1; + st->avg_frame_rate.num = AV_RB32(st->codecpar->extradata + 8); /* timescale */ + st->avg_frame_rate.den = AV_RB32(st->codecpar->extradata + 12); /* frameDuration */ #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS st->codec->time_base = av_inv_q(st->avg_frame_rate); @@ -2328,18 +2330,15 @@ FF_ENABLE_DEPRECATION_WARNINGS uint32_t format = AV_RB32(st->codecpar->extradata + 22); if (format == AV_RB32("name") && (int64_t)size >= (int64_t)len + 18) { uint16_t str_size = AV_RB16(st->codecpar->extradata + 26); /* string length */ - if (str_size > 0 && size >= (int)str_size + 26) { + if (str_size > 0 && size >= (int)str_size + 30 && + st->codecpar->extradata[30] /* Don't add empty string */) { char *reel_name = av_malloc(str_size + 1); if (!reel_name) return AVERROR(ENOMEM); memcpy(reel_name, st->codecpar->extradata + 30, str_size); reel_name[str_size] = 0; /* Add null terminator */ - /* don't add reel_name if emtpy string */ - if (*reel_name == 0) { - av_free(reel_name); - } else { - av_dict_set(&st->metadata, "reel_name", reel_name, AV_DICT_DONT_STRDUP_VAL); - } + av_dict_set(&st->metadata, "reel_name", reel_name, + AV_DICT_DONT_STRDUP_VAL); } } } @@ -2424,6 +2423,9 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, case AV_CODEC_ID_VP9: st->need_parsing = AVSTREAM_PARSE_FULL; break; + case AV_CODEC_ID_AV1: + st->need_parsing = AVSTREAM_PARSE_HEADERS; + break; default: break; } @@ -2536,11 +2538,8 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) /* 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); + sc->extradata[pseudo_stream_id] = st->codecpar->extradata; + st->codecpar->extradata = NULL; st->codecpar->extradata_size = 0; } sc->stsd_count++; @@ -2665,6 +2664,10 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stsc_data[i].id < 1) { av_log(c->fc, AV_LOG_WARNING, "STSC entry %d is invalid (first=%d count=%d id=%d)\n", i, sc->stsc_data[i].first, sc->stsc_data[i].count, sc->stsc_data[i].id); if (i+1 >= sc->stsc_count) { + if (sc->stsc_data[i].count == 0 && i > 0) { + sc->stsc_count --; + continue; + } sc->stsc_data[i].first = FFMAX(sc->stsc_data[i].first, first_min); if (i > 0 && sc->stsc_data[i].first <= sc->stsc_data[i-1].first) sc->stsc_data[i].first = FFMIN(sc->stsc_data[i-1].first + 1LL, INT_MAX); @@ -2763,8 +2766,7 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "keyframe_count = %u\n", entries); - if (!entries) - { + if (!entries) { sc->keyframe_absent = 1; if (!st->need_parsing && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) st->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -2867,6 +2869,11 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) for (i = 0; i < entries && !pb->eof_reached; i++) { sc->sample_sizes[i] = get_bits_long(&gb, field_size); + if (sc->sample_sizes[i] < 0) { + av_free(buf); + av_log(c->fc, AV_LOG_ERROR, "Invalid sample size %d\n", sc->sample_sizes[i]); + return AVERROR_INVALIDDATA; + } sc->data_size += sc->sample_sizes[i]; } @@ -2887,8 +2894,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; MOVStreamContext *sc; unsigned int i, entries, alloc_size = 0; - int64_t duration=0; - int64_t total_sample_count=0; + int64_t duration = 0; + int64_t total_sample_count = 0; if (c->fc->nb_streams < 1) return 0; @@ -2923,7 +2930,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stts_count = min_entries; sc->stts_data = stts_data; - sample_count=avio_rb32(pb); + sample_count = avio_rb32(pb); sample_duration = avio_rb32(pb); sc->stts_data[i].count= sample_count; @@ -2940,8 +2947,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (duration > 0 && duration <= INT64_MAX - sc->duration_for_fps && - total_sample_count <= INT64_MAX - sc->nb_frames_for_fps - ) { + total_sample_count <= INT_MAX - sc->nb_frames_for_fps) { sc->duration_for_fps += duration; sc->nb_frames_for_fps += total_sample_count; } @@ -2958,11 +2964,45 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static void mov_update_dts_shift(MOVStreamContext *sc, int duration) +static int mov_read_sdtp(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + int64_t i, 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 = atom.size - 4; + + av_log(c->fc, AV_LOG_TRACE, "track[%u].sdtp.entries = %" PRId64 "\n", + c->fc->nb_streams - 1, entries); + + if (sc->sdtp_data) + av_log(c->fc, AV_LOG_WARNING, "Duplicated SDTP atom\n"); + av_freep(&sc->sdtp_data); + sc->sdtp_count = 0; + + sc->sdtp_data = av_mallocz(entries); + if (!sc->sdtp_data) + return AVERROR(ENOMEM); + + for (i = 0; i < entries && !pb->eof_reached; i++) + sc->sdtp_data[i] = avio_r8(pb); + sc->sdtp_count = i; + + return 0; +} + +static void mov_update_dts_shift(MOVStreamContext *sc, int duration, void *logctx) { if (duration < 0) { if (duration == INT_MIN) { - av_log(NULL, AV_LOG_WARNING, "mov_update_dts_shift(): dts_shift set to %d\n", INT_MAX); + av_log(logctx, AV_LOG_WARNING, "mov_update_dts_shift(): dts_shift set to %d\n", INT_MAX); duration++; } sc->dts_shift = FFMAX(sc->dts_shift, -duration); @@ -2996,8 +3036,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); for (i = 0; i < entries && !pb->eof_reached; i++) { - int count =avio_rb32(pb); - int duration =avio_rb32(pb); + int count = avio_rb32(pb); + int duration = avio_rb32(pb); if (count <= 0) { av_log(c->fc, AV_LOG_TRACE, @@ -3020,7 +3060,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) } if (i+2fc); } sc->ctts_count = ctts_count; @@ -3237,13 +3277,13 @@ static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, FFMAX(min_size_needed, 2 * st->index_entries_allocated_size) : min_size_needed; - if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) + if (st->nb_index_entries + 1U >= UINT_MAX / sizeof(AVIndexEntry)) return -1; entries = av_fast_realloc(st->index_entries, &st->index_entries_allocated_size, requested_size); - if(!entries) + if (!entries) return -1; st->index_entries= entries; @@ -3288,12 +3328,12 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns FFMAX(min_size_needed, 2 * (*allocated_size)) : min_size_needed; - if((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1) + if ((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1) return -1; ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size); - if(!ctts_buf_new) + if (!ctts_buf_new) return -1; *ctts_data = ctts_buf_new; @@ -3306,7 +3346,8 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns } #define MAX_REORDER_DELAY 16 -static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { +static void mov_estimate_video_delay(MOVContext *c, AVStream* st) +{ MOVStreamContext *msc = st->priv_data; int ind; int ctts_ind = 0; @@ -3321,7 +3362,7 @@ 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->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); @@ -4119,10 +4160,10 @@ static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDr return AVERROR(ENOENT); } - if(strstr(ref->path + l + 1, "..") || - strstr(ref->path + l + 1, ":") || - (ref->nlvl_from > 1 && same_origin < 0) || - (filename[0] == '/' && src_path == src)) + if (strstr(ref->path + l + 1, "..") || + strstr(ref->path + l + 1, ":") || + (ref->nlvl_from > 1 && same_origin < 0) || + (filename[0] == '/' && src_path == src)) return AVERROR(ENOENT); } @@ -4377,6 +4418,9 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else break; + if (*p) + break; + *p = av_malloc(len + 1); if (!*p) { ret = AVERROR(ENOMEM); @@ -4418,7 +4462,10 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom) { while (atom.size > 8) { - uint32_t tag = avio_rl32(pb); + uint32_t tag; + if (avio_feof(pb)) + return AVERROR_EOF; + tag = avio_rl32(pb); atom.size -= 4; if (tag == MKTAG('h','d','l','r')) { avio_seek(pb, -8, SEEK_CUR); @@ -4561,8 +4608,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVFragment *frag = &c->fragment; MOVTrackExt *trex = NULL; int flags, track_id, i; - - c->fragment.found_tfhd = 1; + MOVFragmentStreamInfo * frag_stream_info; avio_r8(pb); /* version */ flags = avio_rb24(pb); @@ -4579,6 +4625,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_WARNING, "could not find corresponding trex (id %u)\n", track_id); return 0; } + c->fragment.found_tfhd = 1; frag->track_id = track_id; set_frag_stream(&c->frag_index, track_id); @@ -4595,6 +4642,10 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb) : trex->flags; av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags); + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) + frag_stream_info->next_trun_dts = AV_NOPTS_VALUE; + return 0; } @@ -4746,13 +4797,19 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); frag_stream_info = get_current_frag_stream_info(&c->frag_index); - if (frag_stream_info) - { - if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && + if (frag_stream_info) { + if (frag_stream_info->next_trun_dts != AV_NOPTS_VALUE) { + dts = frag_stream_info->next_trun_dts - sc->time_offset; + } else if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { pts = frag_stream_info->first_tfra_pts; av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64 ", using it for pts\n", pts); + } else if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && + c->use_mfra_for == FF_MOV_FLAG_MFRA_DTS) { + dts = frag_stream_info->first_tfra_pts; + av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64 + ", using it for dts\n", pts); } else if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) { // FIXME: sidx earliest_presentation_time is *PTS*, s.b. // pts = frag_stream_info->sidx_pts; @@ -4778,18 +4835,18 @@ 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((unsigned)st->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { + if((uint64_t)st->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { entries = UINT_MAX / sizeof(AVIndexEntry) - st->nb_index_entries; av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); } - if (entries <= 0) - return -1; + 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); - if(!new_entries) + if (!new_entries) return AVERROR(ENOMEM); st->index_entries= new_entries; @@ -4844,7 +4901,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_SAMPLE_FLAGS) sample_flags = avio_rb32(pb); if (flags & MOV_TRUN_SAMPLE_CTS) ctts_duration = avio_rb32(pb); - mov_update_dts_shift(sc, ctts_duration); + mov_update_dts_shift(sc, ctts_duration, c->fc); if (pts != AV_NOPTS_VALUE) { dts = pts - sc->dts_shift; if (flags & MOV_TRUN_SAMPLE_CTS) { @@ -4897,12 +4954,14 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->data_size += sample_size; if (sample_duration <= INT64_MAX - sc->duration_for_fps && - 1 <= INT64_MAX - sc->nb_frames_for_fps + 1 <= INT_MAX - sc->nb_frames_for_fps ) { sc->duration_for_fps += sample_duration; sc->nb_frames_for_fps ++; } } + if (frag_stream_info) + frag_stream_info->next_trun_dts = dts + sc->time_offset; if (i < entries) { // EOF found before reading all entries. Fix the hole this would // leave in index_entries and ctts_data @@ -4958,8 +5017,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; - uint8_t version; + uint8_t version, is_complete; unsigned i, j, track_id, item_count; AVStream *st = NULL; AVStream *ref_st = NULL; @@ -5017,7 +5077,7 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_PATCHWELCOME; } avio_rb32(pb); // sap_flags - timestamp = av_rescale_q(pts, st->time_base, timescale); + timestamp = av_rescale_q(pts, timescale, st->time_base); index = update_frag_index(c, offset); frag_stream_info = get_frag_stream_info(&c->frag_index, index, track_id); @@ -5032,7 +5092,24 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->has_sidx = 1; - if (offset == avio_size(pb)) { + // See if the remaining bytes are just an mfra which we can ignore. + is_complete = offset == stream_size; + if (!is_complete && (pb->seekable & AVIO_SEEKABLE_NORMAL)) { + int64_t ret; + int64_t original_pos = avio_tell(pb); + if (!c->have_read_mfra_size) { + if ((ret = avio_seek(pb, stream_size - 4, SEEK_SET)) < 0) + return ret; + c->mfra_size = avio_rb32(pb); + c->have_read_mfra_size = 1; + if ((ret = avio_seek(pb, original_pos, SEEK_SET)) < 0) + return ret; + } + if (offset + c->mfra_size == stream_size) + is_complete = 1; + } + + if (is_complete) { // Find first entry in fragment index that came from an sidx. // This will pretty much always be the first entry. for (i = 0; i < c->frag_index.nb_items; i++) { @@ -5162,7 +5239,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else { edit_count = atom.size / elst_entry_size; if (edit_count * elst_entry_size != atom.size) { - av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.", atom.size, edit_count); + av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.\n", atom.size, edit_count); } } } @@ -5697,12 +5774,9 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) st = c->fc->streams[c->fc->nb_streams - 1]; sc = st->priv_data; - ret = avio_read(pb, uuid, sizeof(uuid)); - if (ret < 0) { + ret = ffio_read_size(pb, uuid, sizeof(uuid)); + if (ret < 0) return ret; - } else if (ret != sizeof(uuid)) { - return AVERROR_INVALIDDATA; - } if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) { uint8_t *buffer, *ptr; char *endptr; @@ -5718,13 +5792,10 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!buffer) { return AVERROR(ENOMEM); } - ret = avio_read(pb, buffer, len); + ret = ffio_read_size(pb, buffer, len); if (ret < 0) { av_free(buffer); return ret; - } else if (ret != len) { - av_free(buffer); - return AVERROR_INVALIDDATA; } ptr = buffer; @@ -5755,17 +5826,14 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!buffer) { return AVERROR(ENOMEM); } - ret = avio_read(pb, buffer, len); + ret = ffio_read_size(pb, buffer, len); if (ret < 0) { av_free(buffer); return ret; - } else if (ret != len) { - av_free(buffer); - return AVERROR_INVALIDDATA; } buffer[len] = '\0'; - av_dict_set(&c->fc->metadata, "xmp", buffer, 0); - av_free(buffer); + av_dict_set(&c->fc->metadata, "xmp", + buffer, AV_DICT_DONT_STRDUP_VAL); } else { // skip all uuid atom, which makes it fast for long uuid-xmp file ret = avio_skip(pb, len); @@ -5905,7 +5973,7 @@ static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encry static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVStreamContext *sc, AVEncryptionInfo **sample, int use_subsamples) { - int i; + int i, ret; unsigned int subsample_count; AVSubsampleEncryptionInfo *subsamples; @@ -5919,11 +5987,11 @@ static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVSt return AVERROR(ENOMEM); if (sc->cenc.per_sample_iv_size != 0) { - if (avio_read(pb, (*sample)->iv, sc->cenc.per_sample_iv_size) != sc->cenc.per_sample_iv_size) { + if ((ret = ffio_read_size(pb, (*sample)->iv, sc->cenc.per_sample_iv_size)) < 0) { av_log(c->fc, AV_LOG_ERROR, "failed to read the initialization vector\n"); av_encryption_info_free(*sample); *sample = NULL; - return AVERROR_INVALIDDATA; + return ret; } } @@ -6291,16 +6359,17 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!info) return AVERROR(ENOMEM); - if (avio_read(pb, info->system_id, 16) != 16) { + if ((ret = ffio_read_size(pb, info->system_id, 16)) < 0) { av_log(c->fc, AV_LOG_ERROR, "Failed to read the system id\n"); - ret = AVERROR_INVALIDDATA; goto finish; } if (version > 0) { kid_count = avio_rb32(pb); - if (kid_count >= INT_MAX / sizeof(*key_ids)) - return AVERROR(ENOMEM); + if (kid_count >= INT_MAX / sizeof(*key_ids)) { + ret = AVERROR(ENOMEM); + goto finish; + } for (unsigned int i = 0; i < kid_count && !pb->eof_reached; i++) { unsigned int min_kid_count = FFMIN(FFMAX(i + 1, 1024), kid_count); @@ -6319,9 +6388,8 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) } info->num_key_ids = i + 1; - if (avio_read(pb, info->key_ids[i], 16) != 16) { + if ((ret = ffio_read_size(pb, info->key_ids[i], 16)) < 0) { av_log(c->fc, AV_LOG_ERROR, "Failed to read the key id\n"); - ret = AVERROR_INVALIDDATA; goto finish; } } @@ -6540,15 +6608,13 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv); - if (!sample->subsample_count) - { + if (!sample->subsample_count) { /* decrypt the whole packet */ av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size); return 0; } - for (i = 0; i < sample->subsample_count; i++) - { + for (i = 0; i < sample->subsample_count; i++) { if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) { av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n"); return AVERROR_INVALIDDATA; @@ -6639,6 +6705,7 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) { const int OPUS_SEEK_PREROLL_MS = 80; + int ret; AVStream *st; size_t size; uint16_t pre_skip; @@ -6659,8 +6726,8 @@ static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) /* OpusSpecificBox size plus magic for Ogg OpusHead header. */ size = atom.size + 8; - if (ff_alloc_extradata(st->codecpar, size)) - return AVERROR(ENOMEM); + if ((ret = ff_alloc_extradata(st->codecpar, size)) < 0) + return ret; AV_WL32(st->codecpar->extradata, MKTAG('O','p','u','s')); AV_WL32(st->codecpar->extradata + 4, MKTAG('H','e','a','d')); @@ -6684,6 +6751,95 @@ static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_dmlp(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + unsigned format_info; + int channel_assignment, channel_assignment1, channel_assignment2; + int ratebits; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + if (atom.size < 10) + return AVERROR_INVALIDDATA; + + format_info = avio_rb32(pb); + + ratebits = (format_info >> 28) & 0xF; + channel_assignment1 = (format_info >> 15) & 0x1F; + channel_assignment2 = format_info & 0x1FFF; + if (channel_assignment2) + channel_assignment = channel_assignment2; + else + channel_assignment = channel_assignment1; + + st->codecpar->frame_size = 40 << (ratebits & 0x7); + st->codecpar->sample_rate = mlp_samplerate(ratebits); + st->codecpar->channels = truehd_channels(channel_assignment); + st->codecpar->channel_layout = truehd_layout(channel_assignment); + + return 0; +} + +static int mov_read_dvcc_dvvc(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + uint32_t buf; + AVDOVIDecoderConfigurationRecord *dovi; + size_t dovi_size; + int ret; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + if ((uint64_t)atom.size > (1<<30) || atom.size < 4) + return AVERROR_INVALIDDATA; + + dovi = av_dovi_alloc(&dovi_size); + if (!dovi) + return AVERROR(ENOMEM); + + dovi->dv_version_major = avio_r8(pb); + dovi->dv_version_minor = avio_r8(pb); + + buf = avio_rb16(pb); + dovi->dv_profile = (buf >> 9) & 0x7f; // 7 bits + dovi->dv_level = (buf >> 3) & 0x3f; // 6 bits + dovi->rpu_present_flag = (buf >> 2) & 0x01; // 1 bit + dovi->el_present_flag = (buf >> 1) & 0x01; // 1 bit + dovi->bl_present_flag = buf & 0x01; // 1 bit + if (atom.size >= 24) { // 4 + 4 + 4 * 4 + buf = avio_r8(pb); + dovi->dv_bl_signal_compatibility_id = (buf >> 4) & 0x0f; // 4 bits + } else { + // 0 stands for None + // Dolby Vision V1.2.93 profiles and levels + dovi->dv_bl_signal_compatibility_id = 0; + } + + ret = av_stream_add_side_data(st, AV_PKT_DATA_DOVI_CONF, + (uint8_t *)dovi, dovi_size); + if (ret < 0) { + av_free(dovi); + return ret; + } + + av_log(c, AV_LOG_TRACE, "DOVI in dvcC/dvvC box, version: %d.%d, profile: %d, level: %d, " + "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d\n", + dovi->dv_version_major, dovi->dv_version_minor, + dovi->dv_profile, dovi->dv_level, + dovi->rpu_present_flag, + dovi->el_present_flag, + dovi->bl_present_flag, + dovi->dv_bl_signal_compatibility_id + ); + + return 0; +} + static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('A','C','L','R'), mov_read_aclr }, { MKTAG('A','P','R','G'), mov_read_avid }, @@ -6732,6 +6888,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('s','t','s','z'), mov_read_stsz }, /* sample size */ { MKTAG('s','t','t','s'), mov_read_stts }, { MKTAG('s','t','z','2'), mov_read_stsz }, /* compact sample size */ +{ MKTAG('s','d','t','p'), mov_read_sdtp }, /* independent and disposable samples */ { MKTAG('t','k','h','d'), mov_read_tkhd }, /* track header */ { MKTAG('t','f','d','t'), mov_read_tfdt }, { MKTAG('t','f','h','d'), mov_read_tfhd }, /* track fragment header */ @@ -6772,11 +6929,14 @@ 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('d','m','l','p'), mov_read_dmlp }, { MKTAG('S','m','D','m'), mov_read_smdm }, { MKTAG('C','o','L','L'), mov_read_coll }, { MKTAG('v','p','c','C'), mov_read_vpcc }, { MKTAG('m','d','c','v'), mov_read_mdcv }, { MKTAG('c','l','l','i'), mov_read_clli }, +{ MKTAG('d','v','c','C'), mov_read_dvcc_dvvc }, +{ MKTAG('d','v','v','C'), mov_read_dvcc_dvvc }, { 0, NULL } }; @@ -6801,26 +6961,24 @@ 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); - if (a.type == MKTAG('f','r','e','e') && + if (((a.type == MKTAG('f','r','e','e') && c->moov_retry) || + a.type == MKTAG('h','o','o','v')) && a.size >= 8 && - c->fc->strict_std_compliance < FF_COMPLIANCE_STRICT && - c->moov_retry) { - uint8_t buf[8]; - uint32_t *type = (uint32_t *)buf + 1; - if (avio_read(pb, buf, 8) != 8) - return AVERROR_INVALIDDATA; + c->fc->strict_std_compliance < FF_COMPLIANCE_STRICT) { + uint32_t type; + avio_skip(pb, 4); + type = avio_rl32(pb); avio_seek(pb, -8, SEEK_CUR); - if (*type == MKTAG('m','v','h','d') || - *type == MKTAG('c','m','o','v')) { - av_log(c->fc, AV_LOG_ERROR, "Detected moov in a free atom.\n"); + if (type == MKTAG('m','v','h','d') || + type == MKTAG('c','m','o','v')) { + av_log(c->fc, AV_LOG_ERROR, "Detected moov in a free or hoov atom.\n"); a.type = MKTAG('m','o','o','v'); } } if (atom.type != MKTAG('r','o','o','t') && - atom.type != MKTAG('m','o','o','v')) - { - if (a.type == MKTAG('t','r','a','k') || a.type == MKTAG('m','d','a','t')) - { + atom.type != MKTAG('m','o','o','v')) { + if (a.type == MKTAG('t','r','a','k') || + a.type == MKTAG('m','d','a','t')) { av_log(c->fc, AV_LOG_ERROR, "Broken file, trak/mdat not at top-level\n"); avio_skip(pb, -8); c->atom_depth --; @@ -6858,7 +7016,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html if (!parse && c->found_hdlr_mdta && atom.type == MKTAG('m','e','t','a') && - a.type == MKTAG('k','e','y','s')) { + a.type == MKTAG('k','e','y','s') && + c->meta_keys_count == 0) { parse = mov_read_keys; } @@ -6885,8 +7044,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, left); else if (left < 0) { av_log(c->fc, AV_LOG_WARNING, - "overread end of atom '%.4s' by %"PRId64" bytes\n", - (char*)&a.type, -left); + "overread end of atom '%s' by %"PRId64" bytes\n", + av_fourcc2str(a.type), -left); avio_seek(pb, left, SEEK_CUR); } } @@ -6901,7 +7060,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static int mov_probe(AVProbeData *p) +static int mov_probe(const AVProbeData *p) { int64_t offset; uint32_t tag; @@ -6959,25 +7118,26 @@ static int mov_probe(AVProbeData *p) offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; } } - if(score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) { + if (score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) { /* moov atom in the header - we should make sure that this is not a * MOV-packed MPEG-PS */ offset = moov_offset; - while(offset < (p->buf_size - 16)){ /* Sufficient space */ + while (offset < (p->buf_size - 16)) { /* Sufficient space */ /* We found an actual hdlr atom */ - if(AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') && - AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') && - AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')){ + if (AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') && + AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') && + AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')) { av_log(NULL, AV_LOG_WARNING, "Found media data tag MPEG indicating this is a MOV-packed MPEG-PS.\n"); /* We found a media handler reference atom describing an * MPEG-PS-in-MOV, return a * low score to force expanding the probe window until * mpegps_probe finds what it needs */ return 5; - }else + } else { /* Keep looking */ - offset+=2; + offset += 2; + } } } @@ -7014,17 +7174,15 @@ static void mov_read_chapters(AVFormatContext *s) st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS; if (st->nb_index_entries) { // Retrieve the first frame, if possible - AVPacket pkt; AVIndexEntry *sample = &st->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, &pkt, sample->size) < 0) + if (av_get_packet(sc->pb, &st->attached_pic, sample->size) < 0) goto finish; - st->attached_pic = pkt; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; } @@ -7195,6 +7353,7 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->sample_sizes); av_freep(&sc->keyframes); av_freep(&sc->stts_data); + av_freep(&sc->sdtp_data); av_freep(&sc->stps_data); av_freep(&sc->elst_data); av_freep(&sc->rap_group); @@ -7217,10 +7376,9 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->coll); } - if (mov->dv_demux) { - avformat_free_context(mov->dv_fctx); - mov->dv_fctx = NULL; - } + av_freep(&mov->dv_demux); + avformat_free_context(mov->dv_fctx); + mov->dv_fctx = NULL; if (mov->meta_keys) { for (i = 1; i < mov->meta_keys_count; i++) { @@ -7341,22 +7499,22 @@ static int mov_read_mfra(MOVContext *c, AVIOContext *f) int64_t stream_size = avio_size(f); int64_t original_pos = avio_tell(f); int64_t seek_ret; - int32_t mfra_size; int ret = -1; if ((seek_ret = avio_seek(f, stream_size - 4, SEEK_SET)) < 0) { ret = seek_ret; goto fail; } - mfra_size = avio_rb32(f); - if (mfra_size < 0 || mfra_size > stream_size) { + c->mfra_size = avio_rb32(f); + c->have_read_mfra_size = 1; + if (!c->mfra_size || c->mfra_size > stream_size) { av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (unreasonable size)\n"); goto fail; } - if ((seek_ret = avio_seek(f, -mfra_size, SEEK_CUR)) < 0) { + if ((seek_ret = avio_seek(f, -((int64_t) c->mfra_size), SEEK_CUR)) < 0) { ret = seek_ret; goto fail; } - if (avio_rb32(f) != mfra_size) { + if (avio_rb32(f) != c->mfra_size) { av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (size mismatch)\n"); goto fail; } @@ -7371,6 +7529,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) { @@ -7409,14 +7568,13 @@ static int mov_read_header(AVFormatContext *s) avio_seek(pb, 0, SEEK_SET); if ((err = mov_read_default(mov, pb, atom)) < 0) { av_log(s, AV_LOG_ERROR, "error reading header\n"); - mov_read_close(s); - return err; + goto fail; } } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++); if (!mov->found_moov) { av_log(s, AV_LOG_ERROR, "moov atom not found\n"); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); @@ -7456,7 +7614,8 @@ static int mov_read_header(AVFormatContext *s) AVStream *st = s->streams[i]; MOVStreamContext *sc = st->priv_data; fix_timescale(mov, sc); - if(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->codec_id == AV_CODEC_ID_AAC) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + st->codecpar->codec_id == AV_CODEC_ID_AAC) { st->skip_samples = sc->start_pad; } if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) @@ -7469,13 +7628,12 @@ static int mov_read_header(AVFormatContext *s) } if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE) { if ((err = mov_rewrite_dvd_sub_extradata(st)) < 0) - return err; + goto fail; } } if (mov->handbrake_version && mov->handbrake_version <= 1000000*0 + 1000*10 + 2 && // 0.10.2 - st->codecpar->codec_id == AV_CODEC_ID_MP3 - ) { + st->codecpar->codec_id == AV_CODEC_ID_MP3) { av_log(s, AV_LOG_VERBOSE, "Forcing full parsing for mp3 stream\n"); st->need_parsing = AVSTREAM_PARSE_FULL; } @@ -7489,8 +7647,8 @@ static int mov_read_header(AVFormatContext *s) if (sc->data_size > INT64_MAX / sc->time_scale / 8) { av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %"PRId64" * 8 * %d\n", sc->data_size, sc->time_scale); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->bit_rate = sc->data_size * 8 * sc->time_scale / st->duration; } @@ -7505,8 +7663,8 @@ static int mov_read_header(AVFormatContext *s) if (sc->data_size > INT64_MAX / sc->time_scale / 8) { av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %"PRId64" * 8 * %d\n", sc->data_size, sc->time_scale); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->bit_rate = sc->data_size * 8 * sc->time_scale / sc->duration_for_fps; @@ -7529,17 +7687,15 @@ static int mov_read_header(AVFormatContext *s) switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: err = ff_replaygain_export(st, s->metadata); - if (err < 0) { - mov_read_close(s); - return err; - } + if (err < 0) + goto fail; break; case AVMEDIA_TYPE_VIDEO: if (sc->display_matrix) { err = av_stream_add_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, (uint8_t*)sc->display_matrix, sizeof(int32_t) * 9); if (err < 0) - return err; + goto fail; sc->display_matrix = NULL; } @@ -7548,7 +7704,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->stereo3d, sizeof(*sc->stereo3d)); if (err < 0) - return err; + goto fail; sc->stereo3d = NULL; } @@ -7557,7 +7713,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->spherical, sc->spherical_size); if (err < 0) - return err; + goto fail; sc->spherical = NULL; } @@ -7566,7 +7722,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->mastering, sizeof(*sc->mastering)); if (err < 0) - return err; + goto fail; sc->mastering = NULL; } @@ -7575,7 +7731,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->coll, sc->coll_size); if (err < 0) - return err; + goto fail; sc->coll = NULL; } @@ -7589,6 +7745,9 @@ static int mov_read_header(AVFormatContext *s) mov->frag_index.item[i].headers_read = 1; return 0; +fail: + mov_read_close(s); + return err; } static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) @@ -7605,7 +7764,7 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) 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) || ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && - ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && + ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && dts != AV_NOPTS_VALUE && ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) || (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) { sample = current_sample; @@ -7639,7 +7798,8 @@ static int mov_switch_root(AVFormatContext *s, int64_t target, int index) mov->next_root_atom = 0; if (index < 0 || index >= mov->frag_index.nb_items) index = search_frag_moof_offset(&mov->frag_index, target); - if (index < mov->frag_index.nb_items) { + if (index < mov->frag_index.nb_items && + mov->frag_index.item[index].moof_offset == target) { if (index + 1 < mov->frag_index.nb_items) mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; if (mov->frag_index.item[index].headers_read) @@ -7682,6 +7842,27 @@ static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt) return 0; } +static int get_eia608_packet(AVIOContext *pb, AVPacket *pkt, int size) +{ + int new_size, ret; + + if (size <= 8) + return AVERROR_INVALIDDATA; + new_size = ((size - 8) / 2) * 3; + ret = av_new_packet(pkt, new_size); + if (ret < 0) + return ret; + + avio_skip(pb, 8); + for (int j = 0; j < new_size; j += 3) { + pkt->data[j] = 0xFC; + pkt->data[j+1] = avio_r8(pb); + pkt->data[j+2] = avio_r8(pb); + } + + return 0; +} + static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) { MOVContext *mov = s->priv_data; @@ -7721,18 +7902,34 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_INVALIDDATA; } - if( st->discard == AVDISCARD_NONKEY && 0==(sample->flags & AVINDEX_KEYFRAME) ) { + if (st->discard == AVDISCARD_NONKEY && !(sample->flags & AVINDEX_KEYFRAME)) { av_log(mov->fc, AV_LOG_DEBUG, "Nonkey frame from stream %d discarded due to AVDISCARD_NONKEY\n", sc->ffindex); goto retry; } - ret = av_get_packet(sc->pb, pkt, sample->size); + if (st->codecpar->codec_id == AV_CODEC_ID_EIA_608 && sample->size > 8) + ret = get_eia608_packet(sc->pb, pkt, sample->size); + else + ret = av_get_packet(sc->pb, pkt, sample->size); if (ret < 0) { if (should_retry(sc->pb, ret)) { mov_current_sample_dec(sc); } return ret; } +#if CONFIG_DV_DEMUXER + if (mov->dv_demux && sc->dv_audio_container) { + AVBufferRef *buf = pkt->buf; + ret = avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); + pkt->buf = buf; + av_packet_unref(pkt); + if (ret < 0) + return ret; + ret = avpriv_dv_get_packet(mov->dv_demux, pkt); + if (ret < 0) + return ret; + } +#endif if (sc->has_palette) { uint8_t *pal; @@ -7744,16 +7941,6 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) sc->has_palette = 0; } } -#if CONFIG_DV_DEMUXER - if (mov->dv_demux && sc->dv_audio_container) { - avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); - av_freep(&pkt->data); - pkt->size = 0; - ret = avpriv_dv_get_packet(mov->dv_demux, pkt); - if (ret < 0) - 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; @@ -7784,6 +7971,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) } if (st->discard == AVDISCARD_ALL) goto retry; + if (sc->sdtp_data && sc->current_sample <= sc->sdtp_count) { + uint8_t sample_flags = sc->sdtp_data[sc->current_sample - 1]; + uint8_t sample_is_depended_on = (sample_flags >> 2) & 0x3; + pkt->flags |= sample_is_depended_on == MOV_SAMPLE_DEPENDENCY_NO ? AV_PKT_FLAG_DISPOSABLE : 0; + } pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0; pkt->pos = sample->pos; @@ -7810,8 +8002,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) aax_filter(pkt->data, pkt->size, mov); ret = cenc_filter(mov, st, sc, pkt, current_index); - if (ret < 0) + if (ret < 0) { return ret; + } return 0; } @@ -7872,16 +8065,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++) { - int64_t 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; + if (sc->chunk_count) { + time_sample = 0; + for (i = 0; i < sc->stsc_count; i++) { + int64_t 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; + } + av_assert0(next == (int)next); + time_sample = next; } - av_assert0(next == (int)next); - time_sample = next; } return sample; @@ -7947,7 +8142,7 @@ static const AVOption mov_options[] = { OFFSET(use_absolute_path), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS}, {"seek_streams_individually", - "Seek each stream individually to the to the closest point", + "Seek each stream individually to the closest point", OFFSET(seek_individually), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS}, {"ignore_editlist", "Ignore the edit list atom.", OFFSET(ignore_editlist), AV_OPT_TYPE_BOOL, {.i64 = 0}, @@ -7998,11 +8193,11 @@ AVInputFormat ff_mov_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"), .priv_class = &mov_class, .priv_data_size = sizeof(MOVContext), - .extensions = "mov,mp4,m4a,3gp,3g2,mj2", + .extensions = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v", .read_probe = mov_probe, .read_header = mov_read_header, .read_packet = mov_read_packet, .read_close = mov_read_close, .read_seek = mov_read_seek, - .flags = AVFMT_NO_BYTE_SEEK, + .flags = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS, };