diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-13 13:24:50 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-14 10:57:25 +0000 |
commit | af3d4809763ef308f08ced947a73b624729ac7ea (patch) | |
tree | 4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/third_party/ffmpeg/libavformat | |
parent | 0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff) | |
download | qtwebengine-chromium-af3d4809763ef308f08ced947a73b624729ac7ea.tar.gz |
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking.
Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a
Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/third_party/ffmpeg/libavformat')
163 files changed, 6390 insertions, 1073 deletions
diff --git a/chromium/third_party/ffmpeg/libavformat/4xm.c b/chromium/third_party/ffmpeg/libavformat/4xm.c index 8fdad185f47..260e080962d 100644 --- a/chromium/third_party/ffmpeg/libavformat/4xm.c +++ b/chromium/third_party/ffmpeg/libavformat/4xm.c @@ -111,7 +111,7 @@ static int parse_vtrk(AVFormatContext *s, st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_4XM; - st->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); st->codec->extradata_size = 4; diff --git a/chromium/third_party/ffmpeg/libavformat/Makefile b/chromium/third_party/ffmpeg/libavformat/Makefile index 993ec09837d..466da516ada 100644 --- a/chromium/third_party/ffmpeg/libavformat/Makefile +++ b/chromium/third_party/ffmpeg/libavformat/Makefile @@ -59,6 +59,7 @@ OBJS-$(CONFIG_SHARED) += log2_tab.o golomb_tab.o # muxers/demuxers OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o +OBJS-$(CONFIG_AA_DEMUXER) += aadec.o OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o apetag.o img2.o rawdec.o OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o OBJS-$(CONFIG_AC3_MUXER) += rawenc.o @@ -82,7 +83,9 @@ OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o OBJS-$(CONFIG_APNG_MUXER) += apngenc.o OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o -OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o \ +OBJS-$(CONFIG_ASF_DEMUXER) += asfdec_f.o asf.o asfcrypt.o \ + avlanguage.o +OBJS-$(CONFIG_ASF_O_DEMUXER) += asfdec_o.o asf.o asfcrypt.o \ avlanguage.o OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o subtitles.o @@ -200,6 +203,7 @@ OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2enc.o img2.o OBJS-$(CONFIG_IMAGE2_ALIAS_PIX_DEMUXER) += img2_alias_pix.o OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o OBJS-$(CONFIG_IMAGE_BMP_PIPE_DEMUXER) += img2dec.o img2.o +OBJS-$(CONFIG_IMAGE_DDS_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_DPX_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_EXR_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o @@ -468,7 +472,7 @@ OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o -OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec.o asf.o asfcrypt.o \ +OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec_f.o asf.o asfcrypt.o \ avlanguage.o mpegts.o isom.o OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o \ mpegtsenc.o asf.o @@ -493,6 +497,7 @@ OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o # protocols I/O +OBJS-$(CONFIG_ASYNC_PROTOCOL) += async.o OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o @@ -542,7 +547,8 @@ SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h -TESTPROGS = seek \ +TESTPROGS = async \ + seek \ srtp \ url \ diff --git a/chromium/third_party/ffmpeg/libavformat/aadec.c b/chromium/third_party/ffmpeg/libavformat/aadec.c new file mode 100644 index 00000000000..266a8e85acd --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/aadec.c @@ -0,0 +1,314 @@ +/* + * Audible AA demuxer + * Copyright (c) 2015 Vesselin Bontchev + * + * Header parsing is borrowed from https://github.com/jteeuwen/audible project. + * Copyright (c) 2001-2014, Jim Teeuwen + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "avformat.h" +#include "internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/tea.h" +#include "libavutil/opt.h" + +#define AA_MAGIC 1469084982 /* this identifies an audible .aa file */ +#define MAX_CODEC_SECOND_SIZE 3982 +#define MAX_TOC_ENTRIES 16 +#define MAX_DICTIONARY_ENTRIES 128 +#define TEA_BLOCK_SIZE 8 + +typedef struct AADemuxContext { + AVClass *class; + uint8_t *aa_fixed_key; + int aa_fixed_key_len; + int codec_second_size; + int current_codec_second_size; + int chapter_idx; + struct AVTEA *tea_ctx; + uint8_t file_key[16]; + int64_t current_chapter_size; +} AADemuxContext; + +static int get_second_size(char *codec_name) +{ + int result = -1; + + if (!strcmp(codec_name, "mp332")) { + result = 3982; + } else if (!strcmp(codec_name, "acelp16")) { + result = 2000; + } else if (!strcmp(codec_name, "acelp85")) { + result = 1045; + } + + return result; +} + +static int aa_read_header(AVFormatContext *s) +{ + int i, j, idx, largest_idx = -1; + uint32_t nkey, nval, toc_size, npairs, header_seed = 0, start; + char key[128], val[128], codec_name[64] = {0}; + uint8_t output[24], dst[8], src[8]; + int64_t largest_size = -1, current_size = -1; + struct toc_entry { + uint32_t offset; + uint32_t size; + } TOC[MAX_TOC_ENTRIES]; + uint32_t header_key_part[4]; + uint8_t header_key[16] = {0}; + AADemuxContext *c = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st; + + /* parse .aa header */ + avio_skip(pb, 4); // file size + avio_skip(pb, 4); // magic string + toc_size = avio_rb32(pb); // TOC size + avio_skip(pb, 4); // unidentified integer + if (toc_size > MAX_TOC_ENTRIES) + return AVERROR_INVALIDDATA; + for (i = 0; i < toc_size; i++) { // read TOC + avio_skip(pb, 4); // TOC entry index + TOC[i].offset = avio_rb32(pb); // block offset + TOC[i].size = avio_rb32(pb); // block size + } + avio_skip(pb, 24); // header termination block (ignored) + npairs = avio_rb32(pb); // read dictionary entries + if (npairs > MAX_DICTIONARY_ENTRIES) + return AVERROR_INVALIDDATA; + for (i = 0; i < npairs; i++) { + memset(val, 0, sizeof(val)); + memset(key, 0, sizeof(key)); + avio_skip(pb, 1); // unidentified integer + nkey = avio_rb32(pb); // key string length + nval = avio_rb32(pb); // value string length + if (nkey > sizeof(key)) { + avio_skip(pb, nkey); + } else { + avio_read(pb, key, nkey); // key string + } + if (nval > sizeof(val)) { + avio_skip(pb, nval); + } else { + avio_read(pb, val, nval); // value string + } + if (!strcmp(key, "codec")) { + av_log(s, AV_LOG_DEBUG, "Codec is <%s>\n", val); + strncpy(codec_name, val, sizeof(codec_name) - 1); + } + if (!strcmp(key, "HeaderSeed")) { + av_log(s, AV_LOG_DEBUG, "HeaderSeed is <%s>\n", val); + header_seed = atoi(val); + } + if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890" + av_log(s, AV_LOG_DEBUG, "HeaderKey is <%s>\n", val); + sscanf(val, "%u%u%u%u", &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]); + for (idx = 0; idx < 4; idx++) { + AV_WB32(&header_key[idx * 4], header_key_part[idx]); // convert each part to BE! + } + av_log(s, AV_LOG_DEBUG, "Processed HeaderKey is "); + for (i = 0; i < 16; i++) + av_log(s, AV_LOG_DEBUG, "%02x", header_key[i]); + av_log(s, AV_LOG_DEBUG, "\n"); + } + } + + /* verify fixed key */ + if (c->aa_fixed_key_len != 16) { + av_log(s, AV_LOG_ERROR, "aa_fixed_key value needs to be 16 bytes!\n"); + return AVERROR(EINVAL); + } + + /* verify codec */ + if ((c->codec_second_size = get_second_size(codec_name)) == -1) { + av_log(s, AV_LOG_ERROR, "unknown codec <%s>!\n", codec_name); + return AVERROR(EINVAL); + } + + /* decryption key derivation */ + c->tea_ctx = av_tea_alloc(); + if (!c->tea_ctx) + return AVERROR(ENOMEM); + av_tea_init(c->tea_ctx, c->aa_fixed_key, 16); + output[0] = output[1] = 0; // purely for padding purposes + memcpy(output + 2, header_key, 16); + idx = 0; + for (i = 0; i < 3; i++) { // TEA CBC with weird mixed endianness + AV_WB32(src, header_seed); + AV_WB32(src + 4, header_seed + 1); + header_seed += 2; + av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 0); // TEA ECB encrypt + for (j = 0; j < TEA_BLOCK_SIZE && idx < 18; j+=1, idx+=1) { + output[idx] = output[idx] ^ dst[j]; + } + } + memcpy(c->file_key, output + 2, 16); // skip first 2 bytes of output + av_log(s, AV_LOG_DEBUG, "File key is "); + for (i = 0; i < 16; i++) + av_log(s, AV_LOG_DEBUG, "%02x", c->file_key[i]); + av_log(s, AV_LOG_DEBUG, "\n"); + + /* decoder setup */ + st = avformat_new_stream(s, NULL); + if (!st) { + av_freep(&c->tea_ctx); + return AVERROR(ENOMEM); + } + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + if (!strcmp(codec_name, "mp332")) { + st->codec->codec_id = AV_CODEC_ID_MP3; + st->codec->sample_rate = 22050; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + st->start_time = 0; + } else if (!strcmp(codec_name, "acelp85")) { + st->codec->codec_id = AV_CODEC_ID_SIPR; + st->codec->block_align = 19; + st->codec->channels = 1; + st->codec->sample_rate = 8500; + } else if (!strcmp(codec_name, "acelp16")) { + st->codec->codec_id = AV_CODEC_ID_SIPR; + st->codec->block_align = 20; + st->codec->channels = 1; + st->codec->sample_rate = 16000; + } + + /* determine, and jump to audio start offset */ + for (i = 1; i < toc_size; i++) { // skip the first entry! + current_size = TOC[i].size; + if (current_size > largest_size) { + largest_idx = i; + largest_size = current_size; + } + } + start = TOC[largest_idx].offset; + avio_seek(pb, start, SEEK_SET); + c->current_chapter_size = 0; + + return 0; +} + +static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + uint8_t dst[TEA_BLOCK_SIZE]; + uint8_t src[TEA_BLOCK_SIZE]; + int i; + int trailing_bytes; + int blocks; + uint8_t buf[MAX_CODEC_SECOND_SIZE * 2]; + int written = 0; + int ret; + AADemuxContext *c = s->priv_data; + + // are we at the start of a chapter? + if (c->current_chapter_size == 0) { + c->current_chapter_size = avio_rb32(s->pb); + if (c->current_chapter_size == 0) { + return AVERROR_EOF; + } + av_log(s, AV_LOG_DEBUG, "Chapter %d (%" PRId64 " bytes)\n", c->chapter_idx, c->current_chapter_size); + c->chapter_idx = c->chapter_idx + 1; + avio_skip(s->pb, 4); // data start offset + c->current_codec_second_size = c->codec_second_size; + } + + // is this the last block in this chapter? + if (c->current_chapter_size / c->current_codec_second_size == 0) { + c->current_codec_second_size = c->current_chapter_size % c->current_codec_second_size; + } + + // decrypt c->current_codec_second_size bytes + blocks = c->current_codec_second_size / TEA_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + avio_read(s->pb, src, TEA_BLOCK_SIZE); + av_tea_init(c->tea_ctx, c->file_key, 16); + av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 1); + memcpy(buf + written, dst, TEA_BLOCK_SIZE); + written = written + TEA_BLOCK_SIZE; + } + trailing_bytes = c->current_codec_second_size % TEA_BLOCK_SIZE; + if (trailing_bytes != 0) { // trailing bytes are left unencrypted! + avio_read(s->pb, src, trailing_bytes); + memcpy(buf + written, src, trailing_bytes); + written = written + trailing_bytes; + } + + // update state + c->current_chapter_size = c->current_chapter_size - c->current_codec_second_size; + if (c->current_chapter_size <= 0) + c->current_chapter_size = 0; + + ret = av_new_packet(pkt, written); + if (ret < 0) + return ret; + memcpy(pkt->data, buf, written); + + return 0; +} + +static int aa_probe(AVProbeData *p) +{ + uint8_t *buf = p->buf; + + // first 4 bytes are file size, next 4 bytes are the magic + if (AV_RB32(buf+4) != AA_MAGIC) + return 0; + + return AVPROBE_SCORE_MAX / 2; +} + +static int aa_read_close(AVFormatContext *s) +{ + AADemuxContext *c = s->priv_data; + + av_freep(&c->tea_ctx); + + return 0; +} + +#define OFFSET(x) offsetof(AADemuxContext, x) +static const AVOption aa_options[] = { + { "aa_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files! + "Fixed key used for handling Audible AA files", OFFSET(aa_fixed_key), + AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd2a51d673"}, + .flags = AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass aa_class = { + .class_name = "aa", + .item_name = av_default_item_name, + .option = aa_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_aa_demuxer = { + .name = "aa", + .long_name = NULL_IF_CONFIG_SMALL("Audible AA format files"), + .priv_class = &aa_class, + .priv_data_size = sizeof(AADemuxContext), + .extensions = "aa", + .read_probe = aa_probe, + .read_header = aa_read_header, + .read_packet = aa_read_packet, + .read_close = aa_read_close, + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/ac3dec.c b/chromium/third_party/ffmpeg/libavformat/ac3dec.c index 58ef44d45a7..bef55cb6586 100644 --- a/chromium/third_party/ffmpeg/libavformat/ac3dec.c +++ b/chromium/third_party/ffmpeg/libavformat/ac3dec.c @@ -80,7 +80,7 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! - if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1; + if (first_frames>=7) return AVPROBE_SCORE_EXTENSION + 1; else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION/2; else if(max_frames>=1) return 1; diff --git a/chromium/third_party/ffmpeg/libavformat/act.c b/chromium/third_party/ffmpeg/libavformat/act.c index 7b6b8406fc0..35aacbc4595 100644 --- a/chromium/third_party/ffmpeg/libavformat/act.c +++ b/chromium/third_party/ffmpeg/libavformat/act.c @@ -75,7 +75,7 @@ static int read_header(AVFormatContext *s) avio_skip(pb, 16); size=avio_rl32(pb); - ff_get_wav_header(pb, st->codec, size, 0); + ff_get_wav_header(s, pb, st->codec, size, 0); /* 8000Hz (Fine-rec) file format has 10 bytes long diff --git a/chromium/third_party/ffmpeg/libavformat/aiffenc.c b/chromium/third_party/ffmpeg/libavformat/aiffenc.c index e2828e7508b..3abd2840f25 100644 --- a/chromium/third_party/ffmpeg/libavformat/aiffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/aiffenc.c @@ -112,7 +112,7 @@ static int aiff_write_header(AVFormatContext *s) if (aiff->audio_stream_idx < 0 && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { aiff->audio_stream_idx = i; } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) { - av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in AIFF.\n"); + av_log(s, AV_LOG_ERROR, "AIFF allows only one audio stream and a picture.\n"); return AVERROR(EINVAL); } } diff --git a/chromium/third_party/ffmpeg/libavformat/allformats.c b/chromium/third_party/ffmpeg/libavformat/allformats.c index 306e0c9876d..0a24ac718b2 100644 --- a/chromium/third_party/ffmpeg/libavformat/allformats.c +++ b/chromium/third_party/ffmpeg/libavformat/allformats.c @@ -60,6 +60,7 @@ void av_register_all(void) /* (de)muxers */ REGISTER_MUXER (A64, a64); + REGISTER_DEMUXER (AA, aa); REGISTER_DEMUXER (AAC, aac); REGISTER_MUXDEMUX(AC3, ac3); REGISTER_DEMUXER (ACT, act); @@ -77,6 +78,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(APNG, apng); REGISTER_DEMUXER (AQTITLE, aqtitle); REGISTER_MUXDEMUX(ASF, asf); + REGISTER_DEMUXER (ASF_O, asf_o); REGISTER_MUXDEMUX(ASS, ass); REGISTER_MUXDEMUX(AST, ast); REGISTER_MUXER (ASF_STREAM, asf_stream); @@ -334,6 +336,7 @@ void av_register_all(void) /* image demuxers */ REGISTER_DEMUXER (IMAGE_BMP_PIPE, image_bmp_pipe); + REGISTER_DEMUXER (IMAGE_DDS_PIPE, image_dds_pipe); REGISTER_DEMUXER (IMAGE_DPX_PIPE, image_dpx_pipe); REGISTER_DEMUXER (IMAGE_EXR_PIPE, image_exr_pipe); REGISTER_DEMUXER (IMAGE_J2K_PIPE, image_j2k_pipe); @@ -349,6 +352,7 @@ void av_register_all(void) /* protocols */ + REGISTER_PROTOCOL(ASYNC, async); REGISTER_PROTOCOL(BLURAY, bluray); REGISTER_PROTOCOL(CACHE, cache); REGISTER_PROTOCOL(CONCAT, concat); diff --git a/chromium/third_party/ffmpeg/libavformat/anm.c b/chromium/third_party/ffmpeg/libavformat/anm.c index f7187973109..23200474bd2 100644 --- a/chromium/third_party/ffmpeg/libavformat/anm.c +++ b/chromium/third_party/ffmpeg/libavformat/anm.c @@ -133,7 +133,7 @@ static int read_header(AVFormatContext *s) /* color cycling and palette data */ st->codec->extradata_size = 16*8 + 4*256; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_mallocz(st->codec->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) { return AVERROR(ENOMEM); } diff --git a/chromium/third_party/ffmpeg/libavformat/apetag.c b/chromium/third_party/ffmpeg/libavformat/apetag.c index 26359205f83..2ee277f8642 100644 --- a/chromium/third_party/ffmpeg/libavformat/apetag.c +++ b/chromium/third_party/ffmpeg/libavformat/apetag.c @@ -55,7 +55,7 @@ static int ape_tag_read_field(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); return -1; } - if (size > INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) { + if (size > INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { av_log(s, AV_LOG_ERROR, "APE tag size too large.\n"); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/apngdec.c b/chromium/third_party/ffmpeg/libavformat/apngdec.c index 6deff3b66ba..84298aecfdd 100644 --- a/chromium/third_party/ffmpeg/libavformat/apngdec.c +++ b/chromium/third_party/ffmpeg/libavformat/apngdec.c @@ -132,7 +132,7 @@ static int append_extradata(AVCodecContext *s, AVIOContext *pb, int len) return AVERROR_INVALIDDATA; new_size = previous_size + len; - new_extradata = av_realloc(s->extradata, new_size + FF_INPUT_BUFFER_PADDING_SIZE); + new_extradata = av_realloc(s->extradata, new_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_extradata) return AVERROR(ENOMEM); s->extradata = new_extradata; @@ -178,7 +178,7 @@ static int apng_read_header(AVFormatContext *s) return ret; /* extradata will contain every chunk up to the first fcTL (excluded) */ - st->codec->extradata = av_malloc(len + 12 + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_malloc(len + 12 + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); st->codec->extradata_size = len + 12; diff --git a/chromium/third_party/ffmpeg/libavformat/apngenc.c b/chromium/third_party/ffmpeg/libavformat/apngenc.c index dcf6b906e18..9b2c634b954 100644 --- a/chromium/third_party/ffmpeg/libavformat/apngenc.c +++ b/chromium/third_party/ffmpeg/libavformat/apngenc.c @@ -173,7 +173,7 @@ static void flush_packet(AVFormatContext *format_context, AVPacket *packet) "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n"); apng->framerate_warned = 1; } - } else if (apng->last_delay.den > 0) { + } else if (apng->last_delay.num > 0) { delay = apng->last_delay; } else { delay = apng->prev_delay; diff --git a/chromium/third_party/ffmpeg/libavformat/aqtitledec.c b/chromium/third_party/ffmpeg/libavformat/aqtitledec.c index 95087665aa1..7c864c8e10f 100644 --- a/chromium/third_party/ffmpeg/libavformat/aqtitledec.c +++ b/chromium/third_party/ffmpeg/libavformat/aqtitledec.c @@ -95,7 +95,7 @@ static int aqt_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&aqt->q); + ff_subtitles_queue_finalize(s, &aqt->q); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/asf.h b/chromium/third_party/ffmpeg/libavformat/asf.h index 0c9598a8d8f..f98fc46edcb 100644 --- a/chromium/third_party/ffmpeg/libavformat/asf.h +++ b/chromium/third_party/ffmpeg/libavformat/asf.h @@ -28,37 +28,15 @@ #define PACKET_SIZE 3200 -typedef struct ASFPayload { - uint8_t type; - uint16_t size; -} ASFPayload; - -typedef struct ASFStream { - int num; - unsigned char seq; - /* use for reading */ - AVPacket pkt; - int frag_offset; - int packet_obj_size; - int timestamp; - int64_t duration; - int skip_to_key; - int pkt_clean; - - int ds_span; /* descrambling */ - int ds_packet_size; - int ds_chunk_size; - - int64_t packet_pos; - - uint16_t stream_language_index; - - int palette_changed; - uint32_t palette[256]; - - int payload_ext_ct; - ASFPayload payload[8]; -} ASFStream; +typedef enum ASFDataType { + ASF_UNICODE = 0, + ASF_BYTE_ARRAY = 1, + ASF_BOOL = 2, + ASF_DWORD = 3, + ASF_QWORD = 4, + ASF_WORD = 5, + ASF_GUID = 6, +}ASFDataType; typedef struct ASFMainHeader { ff_asf_guid guid; ///< generated by client computer diff --git a/chromium/third_party/ffmpeg/libavformat/asfdec.c b/chromium/third_party/ffmpeg/libavformat/asfdec_f.c index 92784348cba..7c31cfaee47 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/asfdec_f.c @@ -39,6 +39,38 @@ #include "asf.h" #include "asfcrypt.h" +typedef struct ASFPayload { + uint8_t type; + uint16_t size; +} ASFPayload; + +typedef struct ASFStream { + int num; + unsigned char seq; + /* use for reading */ + AVPacket pkt; + int frag_offset; + int packet_obj_size; + int timestamp; + int64_t duration; + int skip_to_key; + int pkt_clean; + + int ds_span; /* descrambling */ + int ds_packet_size; + int ds_chunk_size; + + int64_t packet_pos; + + uint16_t stream_language_index; + + int palette_changed; + uint32_t palette[256]; + + int payload_ext_ct; + ASFPayload payload[8]; +} ASFStream; + typedef struct ASFContext { const AVClass *class; int asfid2avid[128]; ///< conversion table from asf ID 2 AVStream ID @@ -81,6 +113,8 @@ typedef struct ASFContext { int no_resync_search; int export_xmp; + + int uses_std_ecc; } ASFContext; static const AVOption options[] = { @@ -100,8 +134,9 @@ static const AVClass asf_class = { #include <assert.h> #define ASF_MAX_STREAMS 127 -#define FRAME_HEADER_SIZE 16 -// Fix Me! FRAME_HEADER_SIZE may be different. (17 is known to be too large) +#define FRAME_HEADER_SIZE 6 +// Fix Me! FRAME_HEADER_SIZE may be different. +// (7 is known to be too large for GipsyGuitar.wmv) #ifdef DEBUG static const ff_asf_guid stream_bitrate_guid = { /* (http://get.to/sdp) */ @@ -294,12 +329,15 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int if (!value) goto finish; - if (type == 0) { // UTF16-LE + switch (type) { + case ASF_UNICODE: avio_get_str16le(s->pb, len, value, 2 * len + 1); - } else if (type == -1) { // ASCII + break; + case -1: // ASCI avio_read(s->pb, value, len); value[len]=0; - } else if (type == 1) { // byte array + break; + case ASF_BYTE_ARRAY: if (!strcmp(key, "WM/Picture")) { // handle cover art asf_read_picture(s, len); } else if (!strcmp(key, "ID3")) { // handle ID3 tag @@ -308,13 +346,18 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int av_log(s, AV_LOG_VERBOSE, "Unsupported byte array in tag %s.\n", key); } goto finish; - } else if (type > 1 && type <= 5) { // boolean or DWORD or QWORD or WORD + case ASF_BOOL: + case ASF_DWORD: + case ASF_QWORD: + case ASF_WORD: { uint64_t num = get_value(s->pb, type, type2_size); snprintf(value, LEN, "%"PRIu64, num); - } else if (type == 6) { // (don't) handle GUID + break; + } + case ASF_GUID: av_log(s, AV_LOG_DEBUG, "Unsupported GUID value in tag %s.\n", key); goto finish; - } else { + default: av_log(s, AV_LOG_DEBUG, "Unsupported value type %d in tag %s.\n", type, key); goto finish; @@ -429,7 +472,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) st->codec->codec_type = type; if (type == AVMEDIA_TYPE_AUDIO) { - int ret = ff_get_wav_header(pb, st->codec, type_specific_size, 0); + int ret = ff_get_wav_header(s, pb, st->codec, type_specific_size, 0); if (ret < 0) return ret; if (is_dvr_ms_audio) { @@ -474,7 +517,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) if (sizeX > 40) { st->codec->extradata_size = ffio_limit(pb, sizeX - 40); st->codec->extradata = av_mallocz(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); avio_read(pb, st->codec->extradata, st->codec->extradata_size); @@ -653,24 +696,29 @@ static int asf_read_metadata(AVFormatContext *s, int64_t size) { AVIOContext *pb = s->pb; ASFContext *asf = s->priv_data; - int n, stream_num, name_len, value_len; + int n, stream_num, name_len_utf16, name_len_utf8, value_len; int ret, i; n = avio_rl16(pb); for (i = 0; i < n; i++) { - char name[1024]; + uint8_t *name; int value_type; avio_rl16(pb); // lang_list_index stream_num = avio_rl16(pb); - name_len = avio_rl16(pb); + name_len_utf16 = avio_rl16(pb); value_type = avio_rl16(pb); /* value_type */ value_len = avio_rl32(pb); - if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len) - avio_skip(pb, name_len - ret); + name_len_utf8 = 2*name_len_utf16 + 1; + name = av_malloc(name_len_utf8); + if (!name) + return AVERROR(ENOMEM); + + if ((ret = avio_get_str16le(pb, name_len_utf16, name, name_len_utf8)) < name_len_utf16) + avio_skip(pb, name_len_utf16 - ret); av_log(s, AV_LOG_TRACE, "%d stream %d name_len %2d type %d len %4d <%s>\n", - i, stream_num, name_len, value_type, value_len, name); + i, stream_num, name_len_utf16, value_type, value_len, name); if (!strcmp(name, "AspectRatioX")){ int aspect_x = get_value(s->pb, value_type, 16); @@ -683,6 +731,7 @@ static int asf_read_metadata(AVFormatContext *s, int64_t size) } else { get_tag(s, name, value_type, value_len, 16); } + av_freep(&name); } return 0; @@ -746,6 +795,7 @@ static int asf_read_header(AVFormatContext *s) for (;;) { uint64_t gpos = avio_tell(pb); + int ret = 0; ff_get_guid(pb, &g); gsize = avio_rl64(pb); print_guid(&g); @@ -762,13 +812,9 @@ static int asf_read_header(AVFormatContext *s) if (gsize < 24) return AVERROR_INVALIDDATA; if (!ff_guidcmp(&g, &ff_asf_file_header)) { - int ret = asf_read_file_properties(s, gsize); - if (ret < 0) - return ret; + ret = asf_read_file_properties(s, gsize); } else if (!ff_guidcmp(&g, &ff_asf_stream_header)) { - int ret = asf_read_stream_properties(s, gsize); - if (ret < 0) - return ret; + ret = asf_read_stream_properties(s, gsize); } else if (!ff_guidcmp(&g, &ff_asf_comment_header)) { asf_read_content_desc(s, gsize); } else if (!ff_guidcmp(&g, &ff_asf_language_guid)) { @@ -797,7 +843,6 @@ static int asf_read_header(AVFormatContext *s) if (!s->keylen) { if (!ff_guidcmp(&g, &ff_asf_content_encryption)) { unsigned int len; - int ret; AVPacket pkt; av_log(s, AV_LOG_WARNING, "DRM protected stream detected, decoding will likely fail!\n"); @@ -823,6 +868,9 @@ static int asf_read_header(AVFormatContext *s) } } } + if (ret < 0) + return ret; + if (avio_tell(pb) != gpos + gsize) av_log(s, AV_LOG_DEBUG, "gpos mismatch our pos=%"PRIu64", end=%"PRId64"\n", @@ -910,44 +958,67 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb) int rsize = 8; int c, d, e, off; - // if we do not know packet size, allow skipping up to 32 kB - off = 32768; - if (asf->no_resync_search) - off = 3; - else if (s->packet_size > 0) - off = (avio_tell(pb) - s->internal->data_offset) % s->packet_size + 3; - - c = d = e = -1; - while (off-- > 0) { - c = d; - d = e; - e = avio_r8(pb); - if (c == 0x82 && !d && !e) - break; - } + if (asf->uses_std_ecc > 0) { + // if we do not know packet size, allow skipping up to 32 kB + off = 32768; + if (asf->no_resync_search) + off = 3; +// else if (s->packet_size > 0 && !asf->uses_std_ecc) +// off = (avio_tell(pb) - s->internal->data_offset) % s->packet_size + 3; + + c = d = e = -1; + while (off-- > 0) { + c = d; + d = e; + e = avio_r8(pb); + if (c == 0x82 && !d && !e) + break; + } - if (c != 0x82) { - /* This code allows handling of -EAGAIN at packet boundaries (i.e. - * if the packet sync code above triggers -EAGAIN). This does not - * imply complete -EAGAIN handling support at random positions in - * the stream. */ - if (pb->error == AVERROR(EAGAIN)) - return AVERROR(EAGAIN); - if (!avio_feof(pb)) - av_log(s, AV_LOG_ERROR, - "ff asf bad header %x at:%"PRId64"\n", c, avio_tell(pb)); - } - if ((c & 0x8f) == 0x82) { - if (d || e) { + if (c != 0x82) { + /* This code allows handling of -EAGAIN at packet boundaries (i.e. + * if the packet sync code above triggers -EAGAIN). This does not + * imply complete -EAGAIN handling support at random positions in + * the stream. */ + if (pb->error == AVERROR(EAGAIN)) + return AVERROR(EAGAIN); if (!avio_feof(pb)) - av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n"); - return AVERROR_INVALIDDATA; + av_log(s, AV_LOG_ERROR, + "ff asf bad header %x at:%"PRId64"\n", c, avio_tell(pb)); + } + if ((c & 0x8f) == 0x82) { + if (d || e) { + if (!avio_feof(pb)) + av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n"); + return AVERROR_INVALIDDATA; + } + c = avio_r8(pb); + d = avio_r8(pb); + rsize += 3; + } else if(!avio_feof(pb)) { + avio_seek(pb, -1, SEEK_CUR); // FIXME } - c = avio_r8(pb); - d = avio_r8(pb); - rsize += 3; - } else if(!avio_feof(pb)) { - avio_seek(pb, -1, SEEK_CUR); // FIXME + } else { + c = avio_r8(pb); + if (c & 0x80) { + rsize ++; + if (!(c & 0x60)) { + d = avio_r8(pb); + e = avio_r8(pb); + avio_seek(pb, (c & 0xF) - 2, SEEK_CUR); + rsize += c & 0xF; + } + + if (c != 0x82) + avpriv_request_sample(s, "Invalid ECC byte\n"); + + if (!asf->uses_std_ecc) + asf->uses_std_ecc = (c == 0x82 && !d && !e) ? 1 : -1; + + c = avio_r8(pb); + } else + asf->uses_std_ecc = -1; + d = avio_r8(pb); } asf->packet_flags = c; @@ -1019,9 +1090,9 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb) DO_2BITS(asf->packet_property >> 4, asf->packet_seq, 0); DO_2BITS(asf->packet_property >> 2, asf->packet_frag_offset, 0); DO_2BITS(asf->packet_property, asf->packet_replic_size, 0); - av_log(asf, AV_LOG_TRACE, "key:%d stream:%d seq:%d offset:%d replic_size:%d\n", + av_log(asf, AV_LOG_TRACE, "key:%d stream:%d seq:%d offset:%d replic_size:%d num:%X packet_property %X\n", asf->packet_key_frame, asf->stream_index, asf->packet_seq, - asf->packet_frag_offset, asf->packet_replic_size); + asf->packet_frag_offset, asf->packet_replic_size, num, asf->packet_property); if (rsize+(int64_t)asf->packet_replic_size > asf->packet_size_left) { av_log(s, AV_LOG_ERROR, "packet_replic_size %d is invalid\n", asf->packet_replic_size); return AVERROR_INVALIDDATA; @@ -1030,8 +1101,8 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb) int64_t end = avio_tell(pb) + asf->packet_replic_size; AVRational aspect; asfst->packet_obj_size = avio_rl32(pb); - if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size <= 0) { - av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n"); + if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size < 0) { + av_log(s, AV_LOG_ERROR, "packet_obj_size %d invalid\n", asfst->packet_obj_size); asfst->packet_obj_size = 0; return AVERROR_INVALIDDATA; } @@ -1100,8 +1171,8 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb) return AVERROR_INVALIDDATA; } else if (asf->packet_frag_size > asf->packet_size_left - rsize) { if (asf->packet_frag_size > asf->packet_size_left - rsize + asf->packet_padsize) { - av_log(s, AV_LOG_ERROR, "packet_frag_size is invalid (%d-%d)\n", - asf->packet_size_left, rsize); + av_log(s, AV_LOG_ERROR, "packet_frag_size is invalid (%d>%d-%d+%d)\n", + asf->packet_frag_size, asf->packet_size_left, rsize, asf->packet_padsize); return AVERROR_INVALIDDATA; } else { int diff = asf->packet_frag_size - (asf->packet_size_left - rsize); @@ -1143,6 +1214,9 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) asf->packet_segments < 1 && asf->packet_time_start == 0) { int ret = asf->packet_size_left + asf->packet_padsize; + if (asf->packet_size_left && asf->packet_size_left < FRAME_HEADER_SIZE) + av_log(s, AV_LOG_WARNING, "Skip due to FRAME_HEADER_SIZE\n"); + assert(ret >= 0); /* fail safe */ avio_skip(pb, ret); @@ -1172,7 +1246,8 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) continue; } asf->asf_st = &asf->streams[s->streams[asf->stream_index]->id]; - asf->asf_st->skip_to_key = 0; + if (!asf->packet_frag_offset) + asf->asf_st->skip_to_key = 0; } asf_st = asf->asf_st; av_assert0(asf_st); @@ -1319,12 +1394,12 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) } else { /* packet descrambling */ AVBufferRef *buf = av_buffer_alloc(asf_st->pkt.size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (buf) { uint8_t *newdata = buf->data; int offset = 0; memset(newdata + asf_st->pkt.size, 0, - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); while (offset < asf_st->pkt.size) { int off = offset / asf_st->ds_chunk_size; int row = off / asf_st->ds_span; @@ -1345,11 +1420,6 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) } asf_st->frag_offset = 0; *pkt = asf_st->pkt; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - asf_st->pkt.destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif asf_st->pkt.buf = 0; asf_st->pkt.size = 0; asf_st->pkt.data = 0; @@ -1476,6 +1546,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, // assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0); pos = asf_st->packet_pos; + av_assert1(pkt->pos == asf_st->packet_pos); av_add_index_entry(s->streams[i], pos, pts, pkt->size, pos - start_pos[i] + 1, AVINDEX_KEYFRAME); diff --git a/chromium/third_party/ffmpeg/libavformat/asfdec_o.c b/chromium/third_party/ffmpeg/libavformat/asfdec_o.c new file mode 100644 index 00000000000..cf2a01e6dbf --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/asfdec_o.c @@ -0,0 +1,1755 @@ +/* + * Microsoft Advanced Streaming Format demuxer + * Copyright (c) 2014 Alexandra HĂ¡jkovĂ¡ + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/bswap.h" +#include "libavutil/common.h" +#include "libavutil/dict.h" +#include "libavutil/internal.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include "libavutil/time_internal.h" + +#include "avformat.h" +#include "avio_internal.h" +#include "avlanguage.h" +#include "id3v2.h" +#include "internal.h" +#include "riff.h" +#include "asf.h" +#include "asfcrypt.h" + +#define ASF_BOOL 0x2 +#define ASF_WORD 0x5 +#define ASF_GUID 0x6 +#define ASF_DWORD 0x3 +#define ASF_QWORD 0x4 +#define ASF_UNICODE 0x0 +#define ASF_FLAG_BROADCAST 0x1 +#define ASF_BYTE_ARRAY 0x1 +#define ASF_TYPE_AUDIO 0x2 +#define ASF_TYPE_VIDEO 0x1 +#define ASF_STREAM_NUM 0x7F +#define ASF_MAX_STREAMS 128 +#define BMP_HEADER_SIZE 40 +#define ASF_NUM_OF_PAYLOADS 0x3F +#define ASF_ERROR_CORRECTION_LENGTH_TYPE 0x60 +#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 + +typedef struct GUIDParseTable { + const char *name; + ff_asf_guid guid; + int (*read_object)(AVFormatContext *, const struct GUIDParseTable *); + int is_subobject; +} GUIDParseTable; + +typedef struct ASFPacket { + AVPacket avpkt; + int64_t dts; + uint32_t frame_num; // ASF payloads with the same number are parts of the same frame + int flags; + int data_size; + int duration; + int size_left; + uint8_t stream_index; +} ASFPacket; + +typedef struct ASFStream { + uint8_t stream_index; // from packet header + int index; // stream index in AVFormatContext, set in asf_read_stream_properties + int type; + int indexed; // added index entries from the Simple Index Object or not + int8_t span; // for deinterleaving + uint16_t virtual_pkt_len; + uint16_t virtual_chunk_len; + int16_t lang_idx; + ASFPacket pkt; +} ASFStream; + +typedef struct ASFStreamData{ + char langs[32]; + AVDictionary *asf_met; // for storing per-stream metadata + AVRational aspect_ratio; +} ASFStreamData; + +typedef struct ASFContext { + int data_reached; + int is_simple_index; // is simple index present or not 1/0 + int is_header; + + uint64_t preroll; + uint64_t nb_packets; // ASF packets + uint32_t packet_size; + int64_t send_time; + int duration; + + uint32_t b_flags; // flags with broadcast flag + uint32_t prop_flags; // file properties object flags + + uint64_t data_size; // data object size + uint64_t unknown_size; // size of the unknown object + + int64_t offset; // offset of the current object + + int64_t data_offset; + int64_t first_packet_offset; // packet offset + int64_t unknown_offset; // for top level header objects or subobjects without specified behavior + + // ASF file must not contain more than 128 streams according to the specification + ASFStream *asf_st[ASF_MAX_STREAMS]; + ASFStreamData asf_sd[ASF_MAX_STREAMS]; + int nb_streams; + + int stream_index; // from packet header, for the subpayload case + + // packet parameteres + uint64_t sub_header_offset; // offset of subplayload header + int64_t sub_dts; + uint8_t dts_delta; // for subpayloads + uint32_t packet_size_internal; // packet size stored inside ASFPacket, can be 0 + int64_t packet_offset; // offset of the current packet inside Data Object + uint32_t pad_len; // padding after payload + uint32_t rep_data_len; + + // packet state + uint64_t sub_left; // subpayloads left or not + unsigned int nb_sub; // number of subpayloads read so far from the current ASF packet + uint16_t mult_sub_len; // total length of subpayloads array inside multiple payload + uint64_t nb_mult_left; // multiple payloads left + int return_subpayload; + enum { + PARSE_PACKET_HEADER, + READ_SINGLE, + READ_MULTI, + READ_MULTI_SUB + } state; +} ASFContext; + +static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size); +static const GUIDParseTable *find_guid(ff_asf_guid guid); + +static int asf_probe(AVProbeData *pd) +{ + /* check file header */ + if (!ff_guidcmp(pd->buf, &ff_asf_header)) + return AVPROBE_SCORE_MAX/2; + else + return 0; +} + +static void swap_guid(ff_asf_guid guid) +{ + FFSWAP(unsigned char, guid[0], guid[3]); + FFSWAP(unsigned char, guid[1], guid[2]); + FFSWAP(unsigned char, guid[4], guid[5]); + FFSWAP(unsigned char, guid[6], guid[7]); +} + +static void align_position(AVIOContext *pb, int64_t offset, uint64_t size) +{ + if (avio_tell(pb) != offset + size) + avio_seek(pb, offset + size, SEEK_SET); +} + +static int asf_read_unknown(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size = avio_rl64(pb); + int ret; + + if (asf->is_header) + asf->unknown_size = size; + asf->is_header = 0; + if (!g->is_subobject) { + if (!(ret = strcmp(g->name, "Header Extension"))) + avio_skip(pb, 22); // skip reserved fields and Data Size + if ((ret = detect_unknown_subobject(s, asf->unknown_offset, + asf->unknown_size)) < 0) + return ret; + } else + avio_skip(pb, size - 24); + + return 0; +} + +static int get_asf_string(AVIOContext *pb, int maxlen, char *buf, int buflen) +{ + char *q = buf; + int ret = 0; + if (buflen <= 0) + return AVERROR(EINVAL); + while (ret + 1 < maxlen) { + uint8_t tmp; + uint32_t ch; + GET_UTF16(ch, (ret += 2) <= maxlen ? avio_rl16(pb) : 0, break;); + PUT_UTF8(ch, tmp, if (q - buf < buflen - 1) *q++ = tmp;) + } + *q = 0; + + return ret; +} + +static int asf_read_marker(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size = avio_rl64(pb); + int i, nb_markers, ret; + size_t len; + char name[1024]; + + avio_skip(pb, 8); + avio_skip(pb, 8); // skip reserved GUID + nb_markers = avio_rl32(pb); + avio_skip(pb, 2); // skip reserved field + len = avio_rl16(pb); + for (i = 0; i < len; i++) + avio_skip(pb, 1); + + for (i = 0; i < nb_markers; i++) { + int64_t pts; + + avio_skip(pb, 8); + pts = avio_rl64(pb); + pts -= asf->preroll * 10000; + avio_skip(pb, 2); // entry length + avio_skip(pb, 4); // send time + avio_skip(pb, 4); // flags + len = avio_rl32(pb); + + if ((ret = avio_get_str16le(pb, len, name, + sizeof(name))) < len) + avio_skip(pb, len - ret); + avpriv_new_chapter(s, i, (AVRational) { 1, 10000000 }, pts, + AV_NOPTS_VALUE, name); + } + align_position(pb, asf->offset, size); + + return 0; +} + +static int asf_read_metadata(AVFormatContext *s, const char *title, uint16_t len, + unsigned char *ch, uint16_t buflen) +{ + AVIOContext *pb = s->pb; + + avio_get_str16le(pb, len, ch, buflen); + if (ch[0]) { + if (av_dict_set(&s->metadata, title, ch, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } + + return 0; +} + +static int asf_read_value(AVFormatContext *s, const uint8_t *name, uint16_t name_len, + uint16_t val_len, int type, AVDictionary **met) +{ + int ret; + uint8_t *value; + uint16_t buflen = 2 * val_len + 1; + AVIOContext *pb = s->pb; + + value = av_malloc(buflen); + if (!value) + return AVERROR(ENOMEM); + if (type == ASF_UNICODE) { + // get_asf_string reads UTF-16 and converts it to UTF-8 which needs longer buffer + if ((ret = get_asf_string(pb, val_len, value, buflen)) < 0) + goto failed; + if (av_dict_set(met, name, value, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } else { + char buf[256]; + if (val_len > sizeof(buf)) { + ret = AVERROR_INVALIDDATA; + goto failed; + } + if ((ret = avio_read(pb, value, val_len)) < 0) + goto failed; + if (ret < 2 * val_len) + value[ret] = '\0'; + else + value[2 * val_len - 1] = '\0'; + snprintf(buf, sizeof(buf), "%s", value); + if (av_dict_set(met, name, buf, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } + av_freep(&value); + + return 0; + +failed: + av_freep(&value); + return ret; +} +static int asf_read_generic_value(AVIOContext *pb, int type, uint64_t *value) +{ + + switch (type) { + case ASF_BOOL: + *value = avio_rl16(pb); + break; + case ASF_DWORD: + *value = avio_rl32(pb); + break; + case ASF_QWORD: + *value = avio_rl64(pb); + break; + case ASF_WORD: + *value = avio_rl16(pb); + break; + default: + return AVERROR_INVALIDDATA; + } + + return 0; +} + +static int asf_set_metadata(AVFormatContext *s, const uint8_t *name, + uint16_t name_len, int type, AVDictionary **met) +{ + AVIOContext *pb = s->pb; + uint64_t value; + char buf[32]; + int ret; + + ret = asf_read_generic_value(pb, type, &value); + if (ret < 0) + return ret; + + snprintf(buf, sizeof(buf), "%"PRIu64, value); + if (av_dict_set(met, name, buf, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + + return 0; +} + +/* MSDN claims that this should be "compatible with the ID3 frame, APIC", + * but in reality this is only loosely similar */ +static int asf_read_picture(AVFormatContext *s, int len) +{ + ASFContext *asf = s->priv_data; + AVPacket pkt = { 0 }; + const CodecMime *mime = ff_id3v2_mime_tags; + enum AVCodecID id = AV_CODEC_ID_NONE; + char mimetype[64]; + uint8_t *desc = NULL; + AVStream *st = NULL; + int ret, type, picsize, desc_len; + ASFStream *asf_st; + + /* type + picsize + mime + desc */ + if (len < 1 + 4 + 2 + 2) { + av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len); + return AVERROR_INVALIDDATA; + } + + /* picture type */ + type = avio_r8(s->pb); + len--; + if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) { + av_log(s, AV_LOG_WARNING, "Unknown attached picture type: %d.\n", type); + type = 0; + } + + /* picture data size */ + picsize = avio_rl32(s->pb); + len -= 4; + + /* picture MIME type */ + len -= avio_get_str16le(s->pb, len, mimetype, sizeof(mimetype)); + while (mime->id != AV_CODEC_ID_NONE) { + if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { + id = mime->id; + break; + } + mime++; + } + if (id == AV_CODEC_ID_NONE) { + av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n", + mimetype); + return 0; + } + + if (picsize >= len) { + av_log(s, AV_LOG_ERROR, "Invalid attached picture data size: %d >= %d.\n", + picsize, len); + return AVERROR_INVALIDDATA; + } + + /* picture description */ + desc_len = (len - picsize) * 2 + 1; + desc = av_malloc(desc_len); + if (!desc) + return AVERROR(ENOMEM); + len -= avio_get_str16le(s->pb, len - picsize, desc, desc_len); + + ret = av_get_packet(s->pb, &pkt, picsize); + if (ret < 0) + goto fail; + + st = avformat_new_stream(s, NULL); + if (!st) { + ret = AVERROR(ENOMEM); + goto fail; + } + asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st)); + asf_st = asf->asf_st[asf->nb_streams]; + if (!asf_st) { + ret = AVERROR(ENOMEM); + goto fail; + } + + st->disposition |= AV_DISPOSITION_ATTACHED_PIC; + st->codec->codec_type = asf_st->type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = id; + st->attached_pic = pkt; + st->attached_pic.stream_index = asf_st->index = st->index; + st->attached_pic.flags |= AV_PKT_FLAG_KEY; + + asf->nb_streams++; + + if (*desc) { + if (av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } else + av_freep(&desc); + + if (av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + + return 0; + +fail: + av_freep(&desc); + av_free_packet(&pkt); + return ret; +} + +static void get_id3_tag(AVFormatContext *s, int len) +{ + ID3v2ExtraMeta *id3v2_extra_meta = NULL; + + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len); + if (id3v2_extra_meta) + ff_id3v2_parse_apic(s, &id3v2_extra_meta); + ff_id3v2_free_extra_meta(&id3v2_extra_meta); +} + +static int process_metadata(AVFormatContext *s, const uint8_t *name, uint16_t name_len, + uint16_t val_len, uint16_t type, AVDictionary **met) +{ + int ret; + ff_asf_guid guid; + + if (val_len) { + switch (type) { + case ASF_UNICODE: + asf_read_value(s, name, name_len, val_len, type, met); + break; + case ASF_BYTE_ARRAY: + if (!strcmp(name, "WM/Picture")) // handle cover art + asf_read_picture(s, val_len); + else if (!strcmp(name, "ID3")) // handle ID3 tag + get_id3_tag(s, val_len); + else + asf_read_value(s, name, name_len, val_len, type, met); + break; + case ASF_GUID: + ff_get_guid(s->pb, &guid); + break; + default: + if ((ret = asf_set_metadata(s, name, name_len, type, met)) < 0) + return ret; + break; + } + } + + return 0; +} + +static int asf_read_ext_content(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size = avio_rl64(pb); + uint16_t nb_desc = avio_rl16(pb); + int i, ret; + + for (i = 0; i < nb_desc; i++) { + uint16_t name_len, type, val_len; + uint8_t *name = NULL; + + name_len = avio_rl16(pb); + if (!name_len) + return AVERROR_INVALIDDATA; + name = av_malloc(name_len); + if (!name) + return AVERROR(ENOMEM); + avio_get_str16le(pb, name_len, name, + name_len); + type = avio_rl16(pb); + // BOOL values are 16 bits long in the Metadata Object + // but 32 bits long in the Extended Content Description Object + if (type == ASF_BOOL) + type = ASF_DWORD; + val_len = avio_rl16(pb); + + ret = process_metadata(s, name, name_len, val_len, type, &s->metadata); + av_freep(&name); + if (ret < 0) + return ret; + } + + align_position(pb, asf->offset, size); + return 0; +} + +static AVStream *find_stream(AVFormatContext *s, uint16_t st_num) +{ + AVStream *st = NULL; + ASFContext *asf = s->priv_data; + int i; + + for (i = 0; i < asf->nb_streams; i++) { + if (asf->asf_st[i]->stream_index == st_num) { + st = s->streams[asf->asf_st[i]->index]; + break; + } + } + + return st; +} + +static int asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t *name, int type) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t value = 0; + int ret; + + ret = asf_read_generic_value(pb, type, &value); + if (ret < 0) + return ret; + + if (st_num < ASF_MAX_STREAMS) { + if (!strcmp(name, "AspectRatioX")) + asf->asf_sd[st_num].aspect_ratio.num = value; + else + asf->asf_sd[st_num].aspect_ratio.den = value; + } + return 0; +} + +static int asf_read_metadata_obj(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size = avio_rl64(pb); + uint16_t nb_recs = avio_rl16(pb); // number of records in the Description Records list + int i, ret; + + for (i = 0; i < nb_recs; i++) { + uint16_t name_len, buflen, type, val_len, st_num; + uint8_t *name = NULL; + + avio_skip(pb, 2); // skip reserved field + st_num = avio_rl16(pb); + name_len = avio_rl16(pb); + buflen = 2 * name_len + 1; + if (!name_len) + break; + type = avio_rl16(pb); + val_len = avio_rl32(pb); + name = av_malloc(buflen); + if (!name) + return AVERROR(ENOMEM); + avio_get_str16le(pb, name_len, name, + buflen); + if (!strcmp(name, "AspectRatioX") || !strcmp(name, "AspectRatioY")) { + ret = asf_store_aspect_ratio(s, st_num, name, type); + if (ret < 0) { + av_freep(&name); + break; + } + } else { + if (st_num < ASF_MAX_STREAMS) { + if ((ret = process_metadata(s, name, name_len, val_len, type, + &asf->asf_sd[st_num].asf_met)) < 0) { + av_freep(&name); + break; + } + } + } + av_freep(&name); + } + + align_position(pb, asf->offset, size); + return 0; +} + +static int asf_read_content_desc(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int i; + static const char *const titles[] = + { "Title", "Author", "Copyright", "Description", "Rate" }; + uint16_t len[5], buflen[5] = { 0 }; + uint8_t *ch; + uint64_t size = avio_rl64(pb); + + for (i = 0; i < 5; i++) { + len[i] = avio_rl16(pb); + // utf8 string should be <= 2 * utf16 string, extra byte for the terminator + buflen[i] = 2 * len[i] + 1; + } + + for (i = 0; i < 5; i++) { + ch = av_malloc(buflen[i]); + if (!ch) + return(AVERROR(ENOMEM)); + asf_read_metadata(s, titles[i], len[i], ch, buflen[i]); + av_freep(&ch); + } + align_position(pb, asf->offset, size); + + return 0; +} + +static int asf_read_properties(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + time_t creation_time; + + avio_rl64(pb); // read object size + avio_skip(pb, 16); // skip File ID + avio_skip(pb, 8); // skip File size + creation_time = avio_rl64(pb); + if (!(asf->b_flags & ASF_FLAG_BROADCAST)) { + struct tm tmbuf; + struct tm *tm; + char buf[64]; + + // creation date is in 100 ns units from 1 Jan 1601, conversion to s + creation_time /= 10000000; + // there are 11644473600 seconds between 1 Jan 1601 and 1 Jan 1970 + creation_time -= 11644473600; + tm = gmtime_r(&creation_time, &tmbuf); + if (tm) { + if (!strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)) + buf[0] = '\0'; + } else + buf[0] = '\0'; + if (buf[0]) { + if (av_dict_set(&s->metadata, "creation_time", buf, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } + } + asf->nb_packets = avio_rl64(pb); + asf->duration = avio_rl64(pb) / 10000; // stream duration + avio_skip(pb, 8); // skip send duration + asf->preroll = avio_rl64(pb); + asf->duration -= asf->preroll; + asf->b_flags = avio_rl32(pb); + avio_skip(pb, 4); // skip minimal packet size + asf->packet_size = avio_rl32(pb); + avio_skip(pb, 4); // skip max_bitrate + + return 0; +} + +static int parse_video_info(AVIOContext *pb, AVStream *st) +{ + uint16_t size; + unsigned int tag; + + st->codec->width = avio_rl32(pb); + st->codec->height = avio_rl32(pb); + avio_skip(pb, 1); // skip reserved flags + size = avio_rl16(pb); // size of the Format Data + tag = ff_get_bmp_header(pb, st, NULL); + st->codec->codec_tag = tag; + st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); + + if (size > BMP_HEADER_SIZE) { + int ret; + st->codec->extradata_size = size - BMP_HEADER_SIZE; + if (!(st->codec->extradata = av_malloc(st->codec->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE))) { + st->codec->extradata_size = 0; + return AVERROR(ENOMEM); + } + memset(st->codec->extradata + st->codec->extradata_size , 0, + AV_INPUT_BUFFER_PADDING_SIZE); + if ((ret = avio_read(pb, st->codec->extradata, + st->codec->extradata_size)) < 0) + return ret; + } + return 0; +} + +static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size; + uint32_t err_data_len, ts_data_len; // type specific data length + uint16_t flags; + ff_asf_guid stream_type; + enum AVMediaType type; + int i, ret; + uint8_t stream_index; + AVStream *st; + ASFStream *asf_st; + + // ASF file must not contain more than 128 streams according to the specification + if (asf->nb_streams >= ASF_MAX_STREAMS) + return AVERROR_INVALIDDATA; + + size = avio_rl64(pb); + ff_get_guid(pb, &stream_type); + if (!ff_guidcmp(&stream_type, &ff_asf_audio_stream)) + type = AVMEDIA_TYPE_AUDIO; + else if (!ff_guidcmp(&stream_type, &ff_asf_video_stream)) + type = AVMEDIA_TYPE_VIDEO; + else if (!ff_guidcmp(&stream_type, &ff_asf_jfif_media)) + type = AVMEDIA_TYPE_VIDEO; + else if (!ff_guidcmp(&stream_type, &ff_asf_command_stream)) + type = AVMEDIA_TYPE_DATA; + else if (!ff_guidcmp(&stream_type, + &ff_asf_ext_stream_embed_stream_header)) + type = AVMEDIA_TYPE_UNKNOWN; + else + return AVERROR_INVALIDDATA; + + ff_get_guid(pb, &stream_type); // error correction type + avio_skip(pb, 8); // skip the time offset + ts_data_len = avio_rl32(pb); + err_data_len = avio_rl32(pb); + flags = avio_rl16(pb); // bit 15 - Encrypted Content + + stream_index = flags & ASF_STREAM_NUM; + for (i = 0; i < asf->nb_streams; i++) + if (stream_index == asf->asf_st[i]->stream_index) { + av_log(s, AV_LOG_WARNING, + "Duplicate stream found, this stream will be ignored.\n"); + align_position(pb, asf->offset, size); + return 0; + } + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 32, 1, 1000); // pts should be dword, in milliseconds + st->codec->codec_type = type; + asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st)); + if (!asf->asf_st[asf->nb_streams]) + return AVERROR(ENOMEM); + asf_st = asf->asf_st[asf->nb_streams]; + asf->nb_streams++; + asf_st->stream_index = stream_index; + asf_st->index = st->index; + asf_st->indexed = 0; + st->id = flags & ASF_STREAM_NUM; + av_init_packet(&asf_st->pkt.avpkt); + asf_st->pkt.data_size = 0; + avio_skip(pb, 4); // skip reserved field + + switch (type) { + case AVMEDIA_TYPE_AUDIO: + asf_st->type = AVMEDIA_TYPE_AUDIO; + if ((ret = ff_get_wav_header(s, pb, st->codec, ts_data_len, 0)) < 0) + return ret; + break; + case AVMEDIA_TYPE_VIDEO: + asf_st->type = AVMEDIA_TYPE_VIDEO; + if ((ret = parse_video_info(pb, st)) < 0) + return ret; + break; + default: + avio_skip(pb, ts_data_len); + break; + } + + if (err_data_len) { + if (type == AVMEDIA_TYPE_AUDIO) { + uint8_t span = avio_r8(pb); + if (span > 1) { + asf_st->span = span; + asf_st->virtual_pkt_len = avio_rl16(pb); + asf_st->virtual_chunk_len = avio_rl16(pb); + if (!asf_st->virtual_chunk_len || !asf_st->virtual_pkt_len) + return AVERROR_INVALIDDATA; + avio_skip(pb, err_data_len - 5); + } else + avio_skip(pb, err_data_len - 1); + } else + avio_skip(pb, err_data_len); + } + + align_position(pb, asf->offset, size); + + return 0; +} + +static void set_language(AVFormatContext *s, const char *rfc1766, AVDictionary **met) +{ + // language abbr should contain at least 2 chars + if (rfc1766 && strlen(rfc1766) > 1) { + const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any + const char *iso6392 = av_convert_lang_to(primary_tag, + AV_LANG_ISO639_2_BIBL); + if (iso6392) + if (av_dict_set(met, "language", iso6392, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } +} + +static int asf_read_ext_stream_properties(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st = NULL; + ff_asf_guid guid; + uint16_t nb_st_name, nb_pay_exts, st_num, lang_idx; + int i, ret; + uint32_t bitrate; + uint64_t start_time, end_time, time_per_frame; + uint64_t size = avio_rl64(pb); + + start_time = avio_rl64(pb); + end_time = avio_rl64(pb); + bitrate = avio_rl32(pb); + avio_skip(pb, 28); // skip some unused values + st_num = avio_rl16(pb); + st_num &= ASF_STREAM_NUM; + lang_idx = avio_rl16(pb); // Stream Language ID Index + for (i = 0; i < asf->nb_streams; i++) { + if (st_num == asf->asf_st[i]->stream_index) { + st = s->streams[asf->asf_st[i]->index]; + asf->asf_st[i]->lang_idx = lang_idx; + break; + } + } + time_per_frame = avio_rl64(pb); // average time per frame + if (st) { + st->start_time = start_time; + st->duration = end_time - start_time; + st->codec->bit_rate = bitrate; + st->avg_frame_rate.num = 10000000; + st->avg_frame_rate.den = time_per_frame; + } + nb_st_name = avio_rl16(pb); + nb_pay_exts = avio_rl16(pb); + for (i = 0; i < nb_st_name; i++) { + uint16_t len; + + avio_rl16(pb); // Language ID Index + len = avio_rl16(pb); + avio_skip(pb, len); + } + + for (i = 0; i < nb_pay_exts; i++) { + uint32_t len; + avio_skip(pb, 16); // Extension System ID + avio_skip(pb, 2); // Extension Data Size + len = avio_rl32(pb); + avio_skip(pb, len); + } + + if ((ret = ff_get_guid(pb, &guid)) < 0) { + align_position(pb, asf->offset, size); + + return 0; + } + + g = find_guid(guid); + if (g && !(strcmp(g->name, "Stream Properties"))) { + if ((ret = g->read_object(s, g)) < 0) + return ret; + } + + align_position(pb, asf->offset, size); + return 0; +} + +static int asf_read_language_list(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int i, ret; + uint64_t size = avio_rl64(pb); + uint16_t nb_langs = avio_rl16(pb); + + if (nb_langs < ASF_MAX_STREAMS) { + for (i = 0; i < nb_langs; i++) { + size_t len; + len = avio_r8(pb); + if (!len) + len = 6; + if ((ret = get_asf_string(pb, len, asf->asf_sd[i].langs, + sizeof(asf->asf_sd[i].langs))) < 0) { + return ret; + } + } + } + + align_position(pb, asf->offset, size); + return 0; +} + +// returns data object offset when reading this object for the first time +static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size = asf->data_size = avio_rl64(pb); + int i; + + if (!asf->data_reached) { + asf->data_reached = 1; + asf->data_offset = asf->offset; + } + + for (i = 0; i < asf->nb_streams; i++) { + if (!(asf->b_flags & ASF_FLAG_BROADCAST)) + s->streams[i]->duration = asf->duration; + } + asf->nb_mult_left = 0; + asf->sub_left = 0; + asf->state = PARSE_PACKET_HEADER; + asf->return_subpayload = 0; + asf->packet_size_internal = 0; + avio_skip(pb, 16); // skip File ID + size = avio_rl64(pb); // Total Data Packets + if (size != asf->nb_packets) + av_log(s, AV_LOG_WARNING, + "Number of Packets from File Properties Object is not equal to Total" + "Datapackets value! num of packets %"PRIu64" total num %"PRIu64".\n", + size, asf->nb_packets); + avio_skip(pb, 2); // skip reserved field + asf->first_packet_offset = avio_tell(pb); + if (pb->seekable && !(asf->b_flags & ASF_FLAG_BROADCAST)) + align_position(pb, asf->offset, asf->data_size); + + return 0; +} + +static int asf_read_simple_index(AVFormatContext *s, const GUIDParseTable *g) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st = NULL; + uint64_t interval; // index entry time interval in 100 ns units, usually it's 1s + uint32_t pkt_num, nb_entries; + int32_t prev_pkt_num = -1; + int i; + uint64_t size = avio_rl64(pb); + + // simple index objects should be ordered by stream number, this loop tries to find + // the first not indexed video stream + for (i = 0; i < asf->nb_streams; i++) { + if ((asf->asf_st[i]->type == AVMEDIA_TYPE_VIDEO) && !asf->asf_st[i]->indexed) { + asf->asf_st[i]->indexed = 1; + st = s->streams[asf->asf_st[i]->index]; + break; + } + } + if (!st) { + avio_skip(pb, size - 24); // if there's no video stream, skip index object + return 0; + } + avio_skip(pb, 16); // skip File ID + interval = avio_rl64(pb); + avio_skip(pb, 4); + nb_entries = avio_rl32(pb); + for (i = 0; i < nb_entries; i++) { + pkt_num = avio_rl32(pb); + avio_skip(pb, 2); + if (prev_pkt_num != pkt_num) { + av_add_index_entry(st, asf->first_packet_offset + asf->packet_size * + pkt_num, av_rescale(interval, i, 10000), + asf->packet_size, 0, AVINDEX_KEYFRAME); + prev_pkt_num = pkt_num; + } + } + asf->is_simple_index = 1; + align_position(pb, asf->offset, size); + + return 0; +} + +static const GUIDParseTable gdef[] = { + { "Data", { 0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_data, 1 }, + { "Simple Index", { 0x33, 0x00, 0x08, 0x90, 0xE5, 0xB1, 0x11, 0xCF, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }, asf_read_simple_index, 1 }, + { "Content Description", { 0x75, 0xB2, 0x26, 0x33, 0x66 ,0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_content_desc, 1 }, + { "Extended Content Description", { 0xD2, 0xD0, 0xA4, 0x40, 0xE3, 0x07, 0x11, 0xD2, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5e, 0xA8, 0x50 }, asf_read_ext_content, 1 }, + { "Stream Bitrate Properties", { 0x7B, 0xF8, 0x75, 0xCE, 0x46, 0x8D, 0x11, 0xD1, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }, asf_read_unknown, 1 }, + { "File Properties", { 0x8C, 0xAB, 0xDC, 0xA1, 0xA9, 0x47, 0x11, 0xCF, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_properties, 1 }, + { "Header Extension", { 0x5F, 0xBF, 0x03, 0xB5, 0xA9, 0x2E, 0x11, 0xCF, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_unknown, 0 }, + { "Stream Properties", { 0xB7, 0xDC, 0x07, 0x91, 0xA9, 0xB7, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_stream_properties, 1 }, + { "Codec List", { 0x86, 0xD1, 0x52, 0x40, 0x31, 0x1D, 0x11, 0xD0, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 }, + { "Marker", { 0xF4, 0x87, 0xCD, 0x01, 0xA9, 0x51, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_marker, 1 }, + { "Script Command", { 0x1E, 0xFB, 0x1A, 0x30, 0x0B, 0x62, 0x11, 0xD0, 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 }, + { "Language List", { 0x7C, 0x43, 0x46, 0xa9, 0xef, 0xe0, 0x4B, 0xFC, 0xB2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 }, asf_read_language_list, 1}, + { "Padding", { 0x18, 0x06, 0xD4, 0x74, 0xCA, 0xDF, 0x45, 0x09, 0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8 }, asf_read_unknown, 1 }, + { "DRMv1 Header", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, + { "DRMv2 Header", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9c }, asf_read_unknown, 1 }, + { "Index", { 0xD6, 0xE2, 0x29, 0xD3, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Media Object Index", { 0xFE, 0xB1, 0x03, 0xF8, 0x12, 0xAD, 0x4C, 0x64, 0x84, 0x0F, 0x2A, 0x1D, 0x2F, 0x7A, 0xD4, 0x8C }, asf_read_unknown, 1 }, + { "Timecode Index", { 0x3C, 0xB7, 0x3F, 0xD0, 0x0C, 0x4A, 0x48, 0x03, 0x95, 0x3D, 0xED, 0xF7, 0xB6, 0x22, 0x8F, 0x0C }, asf_read_unknown, 0 }, + { "Bitrate_Mutual_Exclusion", { 0xD6, 0xE2, 0x29, 0xDC, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Error Correction", { 0x75, 0xB2, 0x26, 0x35, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_unknown, 1 }, + { "Content Branding", { 0x22, 0x11, 0xB3, 0xFA, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, + { "Content Encryption", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, + { "Extended Content Encryption", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C }, asf_read_unknown, 1 }, + { "Digital Signature", { 0x22, 0x11, 0xB3, 0xFC, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, + { "Extended Stream Properties", { 0x14, 0xE6, 0xA5, 0xCB, 0xC6, 0x72, 0x43, 0x32, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A }, asf_read_ext_stream_properties, 1 }, + { "Advanced Mutual Exclusion", { 0xA0, 0x86, 0x49, 0xCF, 0x47, 0x75, 0x46, 0x70, 0x8A, 0x16, 0x6E, 0x35, 0x35, 0x75, 0x66, 0xCD }, asf_read_unknown, 1 }, + { "Group Mutual Exclusion", { 0xD1, 0x46, 0x5A, 0x40, 0x5A, 0x79, 0x43, 0x38, 0xB7, 0x1B, 0xE3, 0x6B, 0x8F, 0xD6, 0xC2, 0x49 }, asf_read_unknown, 1}, + { "Stream Prioritization", { 0xD4, 0xFE, 0xD1, 0x5B, 0x88, 0xD3, 0x45, 0x4F, 0x81, 0xF0, 0xED, 0x5C, 0x45, 0x99, 0x9E, 0x24 }, asf_read_unknown, 1 }, + { "Bandwidth Sharing Object", { 0xA6, 0x96, 0x09, 0xE6, 0x51, 0x7B, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, + { "Metadata", { 0xC5, 0xF8, 0xCB, 0xEA, 0x5B, 0xAF, 0x48, 0x77, 0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA }, asf_read_metadata_obj, 1 }, + { "Metadata Library", { 0x44, 0x23, 0x1C, 0x94, 0x94, 0x98, 0x49, 0xD1, 0xA1, 0x41, 0x1D, 0x13, 0x4E, 0x45, 0x70, 0x54 }, asf_read_metadata_obj, 1 }, + { "Audio Spread", { 0xBF, 0xC3, 0xCD, 0x50, 0x61, 0x8F, 0x11, 0xCF, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20 }, asf_read_unknown, 1 }, + { "Index Parameters", { 0xD6, 0xE2, 0x29, 0xDF, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Content Encryption System Windows Media DRM Network Devices", + { 0x7A, 0x07, 0x9B, 0xB6, 0xDA, 0XA4, 0x4e, 0x12, 0xA5, 0xCA, 0x91, 0xD3, 0x8D, 0xC1, 0x1A, 0x8D }, asf_read_unknown, 1 }, + { "Mutex Language", { 0xD6, 0xE2, 0x2A, 0x00, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Mutex Bitrate", { 0xD6, 0xE2, 0x2A, 0x01, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Mutex Unknown", { 0xD6, 0xE2, 0x2A, 0x02, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, + { "Bandwith Sharing Exclusive", { 0xAF, 0x60, 0x60, 0xAA, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, + { "Bandwith Sharing Partial", { 0xAF, 0x60, 0x60, 0xAB, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, + { "Payload Extension System Timecode", { 0x39, 0x95, 0x95, 0xEC, 0x86, 0x67, 0x4E, 0x2D, 0x8F, 0xDB, 0x98, 0x81, 0x4C, 0xE7, 0x6C, 0x1E }, asf_read_unknown, 1 }, + { "Payload Extension System File Name", { 0xE1, 0x65, 0xEC, 0x0E, 0x19, 0xED, 0x45, 0xD7, 0xB4, 0xA7, 0x25, 0xCB, 0xD1, 0xE2, 0x8E, 0x9B }, asf_read_unknown, 1 }, + { "Payload Extension System Content Type", { 0xD5, 0x90, 0xDC, 0x20, 0x07, 0xBC, 0x43, 0x6C, 0x9C, 0xF7, 0xF3, 0xBB, 0xFB, 0xF1, 0xA4, 0xDC }, asf_read_unknown, 1 }, + { "Payload Extension System Pixel Aspect Ratio", { 0x1, 0x1E, 0xE5, 0x54, 0xF9, 0xEA, 0x4B, 0xC8, 0x82, 0x1A, 0x37, 0x6B, 0x74, 0xE4, 0xC4, 0xB8 }, asf_read_unknown, 1 }, + { "Payload Extension System Sample Duration", { 0xC6, 0xBD, 0x94, 0x50, 0x86, 0x7F, 0x49, 0x07, 0x83, 0xA3, 0xC7, 0x79, 0x21, 0xB7, 0x33, 0xAD }, asf_read_unknown, 1 }, + { "Payload Extension System Encryption Sample ID", { 0x66, 0x98, 0xB8, 0x4E, 0x0A, 0xFA, 0x43, 0x30, 0xAE, 0xB2, 0x1C, 0x0A, 0x98, 0xD7, 0xA4, 0x4D }, asf_read_unknown, 1 }, + { "Payload Extension System Degradable JPEG", { 0x00, 0xE1, 0xAF, 0x06, 0x7B, 0xEC, 0x11, 0xD1, 0xA5, 0x82, 0x00, 0xC0, 0x4F, 0xC2, 0x9C, 0xFB }, asf_read_unknown, 1 }, +}; + +#define READ_LEN(flag, name, len) \ + do { \ + if ((flag) == name ## IS_BYTE) \ + len = avio_r8(pb); \ + else if ((flag) == name ## IS_WORD) \ + len = avio_rl16(pb); \ + else if ((flag) == name ## IS_DWORD) \ + len = avio_rl32(pb); \ + else \ + len = 0; \ + } while(0) + +static int asf_read_subpayload(AVFormatContext *s, AVPacket *pkt, int is_header) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint8_t sub_len; + int ret, i; + + if (is_header) { + asf->dts_delta = avio_r8(pb); + if (asf->nb_mult_left) { + asf->mult_sub_len = avio_rl16(pb); // total + } + asf->sub_header_offset = avio_tell(pb); + asf->nb_sub = 0; + asf->sub_left = 1; + } + sub_len = avio_r8(pb); + if ((ret = av_get_packet(pb, pkt, sub_len)) < 0) // each subpayload is entire frame + return ret; + for (i = 0; i < asf->nb_streams; i++) { + if (asf->stream_index == asf->asf_st[i]->stream_index) { + pkt->stream_index = asf->asf_st[i]->index; + break; + } + } + asf->return_subpayload = 1; + if (!sub_len) + asf->return_subpayload = 0; + + if (sub_len) + asf->nb_sub++; + pkt->dts = asf->sub_dts + (asf->nb_sub - 1) * asf->dts_delta - asf->preroll; + if (asf->nb_mult_left && (avio_tell(pb) >= + (asf->sub_header_offset + asf->mult_sub_len))) { + asf->sub_left = 0; + asf->nb_mult_left--; + } + if (avio_tell(pb) >= asf->packet_offset + asf->packet_size - asf->pad_len) { + asf->sub_left = 0; + if (!asf->nb_mult_left) { + avio_skip(pb, asf->pad_len); + if (avio_tell(pb) != asf->packet_offset + asf->packet_size) { + if (!asf->packet_size) + return AVERROR_INVALIDDATA; + av_log(s, AV_LOG_WARNING, + "Position %"PRId64" wrong, should be %"PRId64"\n", + avio_tell(pb), asf->packet_offset + asf->packet_size); + avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); + } + } + } + + return 0; +} + +static void reset_packet(ASFPacket *asf_pkt) +{ + asf_pkt->size_left = 0; + asf_pkt->data_size = 0; + asf_pkt->duration = 0; + asf_pkt->flags = 0; + asf_pkt->dts = 0; + asf_pkt->duration = 0; + av_free_packet(&asf_pkt->avpkt); + av_init_packet(&asf_pkt->avpkt); +} + +static int asf_read_replicated_data(AVFormatContext *s, ASFPacket *asf_pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int ret; + + if (!asf_pkt->data_size) { + asf_pkt->data_size = asf_pkt->size_left = avio_rl32(pb); // read media object size + if (asf_pkt->data_size <= 0) + return AVERROR_INVALIDDATA; + if ((ret = av_new_packet(&asf_pkt->avpkt, asf_pkt->data_size)) < 0) + return ret; + } else + avio_skip(pb, 4); // reading of media object size is already done + asf_pkt->dts = avio_rl32(pb); // read presentation time + if (asf->rep_data_len && (asf->rep_data_len >= 8)) + avio_skip(pb, asf->rep_data_len - 8); // skip replicated data + + return 0; +} + +static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, + ASFPacket *asf_pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint16_t pay_len; + unsigned char *p; + int ret; + int skip = 0; + + // if replicated lenght is 1, subpayloads are present + if (asf->rep_data_len == 1) { + asf->sub_left = 1; + asf->state = READ_MULTI_SUB; + pkt->flags = asf_pkt->flags; + if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) + return ret; + } else { + if (asf->rep_data_len) + if ((ret = asf_read_replicated_data(s, asf_pkt)) < 0) + return ret; + pay_len = avio_rl16(pb); // payload length should be WORD + if (pay_len > asf->packet_size) { + av_log(s, AV_LOG_ERROR, + "Error: invalid data packet size, pay_len %"PRIu16", " + "asf->packet_size %"PRIu32", offset %"PRId64".\n", + pay_len, asf->packet_size, avio_tell(pb)); + return AVERROR_INVALIDDATA; + } + p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left; + if (pay_len > asf_pkt->size_left) { + av_log(s, AV_LOG_ERROR, + "Error: invalid buffer size, pay_len %d, data size left %d.\n", + pay_len, asf_pkt->size_left); + skip = pay_len - asf_pkt->size_left; + pay_len = asf_pkt->size_left; + } + if (asf_pkt->size_left <= 0) + return AVERROR_INVALIDDATA; + if ((ret = avio_read(pb, p, pay_len)) < 0) + return ret; + if (s->key && s->keylen == 20) + ff_asfcrypt_dec(s->key, p, ret); + avio_skip(pb, skip); + asf_pkt->size_left -= pay_len; + asf->nb_mult_left--; + } + + return 0; +} + +static int asf_read_single_payload(AVFormatContext *s, AVPacket *pkt, + ASFPacket *asf_pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int64_t offset; + uint64_t size; + unsigned char *p; + int ret; + + if (!asf_pkt->data_size) { + asf_pkt->data_size = asf_pkt->size_left = avio_rl32(pb); // read media object size + if (asf_pkt->data_size <= 0) + return AVERROR_EOF; + if ((ret = av_new_packet(&asf_pkt->avpkt, asf_pkt->data_size)) < 0) + return ret; + } else + avio_skip(pb, 4); // skip media object size + asf_pkt->dts = avio_rl32(pb); // read presentation time + if (asf->rep_data_len >= 8) + avio_skip(pb, asf->rep_data_len - 8); // skip replicated data + offset = avio_tell(pb); + + // size of the payload - size of the packet without header and padding + if (asf->packet_size_internal) + size = asf->packet_size_internal - offset + asf->packet_offset - asf->pad_len; + else + size = asf->packet_size - offset + asf->packet_offset - asf->pad_len; + if (size > asf->packet_size) { + av_log(s, AV_LOG_ERROR, + "Error: invalid data packet size, offset %"PRId64".\n", + avio_tell(pb)); + return AVERROR_INVALIDDATA; + } + p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left; + if (size > asf_pkt->size_left || asf_pkt->size_left <= 0) + return AVERROR_INVALIDDATA; + if (asf_pkt->size_left > size) + asf_pkt->size_left -= size; + else + asf_pkt->size_left = 0; + if ((ret = avio_read(pb, p, size)) < 0) + return ret; + if (s->key && s->keylen == 20) + ff_asfcrypt_dec(s->key, p, ret); + if (asf->packet_size_internal) + avio_skip(pb, asf->packet_size - asf->packet_size_internal); + avio_skip(pb, asf->pad_len); // skip padding + + return 0; +} + +static int asf_read_payload(AVFormatContext *s, AVPacket *pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int ret, i; + ASFPacket *asf_pkt = NULL; + + if (!asf->sub_left) { + uint32_t off_len, media_len; + uint8_t stream_num; + + stream_num = avio_r8(pb); + asf->stream_index = stream_num & ASF_STREAM_NUM; + for (i = 0; i < asf->nb_streams; i++) { + if (asf->stream_index == asf->asf_st[i]->stream_index) { + asf_pkt = &asf->asf_st[i]->pkt; + asf_pkt->stream_index = asf->asf_st[i]->index; + break; + } + } + if (!asf_pkt) + return AVERROR_INVALIDDATA; + if (stream_num >> 7) + asf_pkt->flags |= AV_PKT_FLAG_KEY; + READ_LEN(asf->prop_flags & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE, + ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_, media_len); + READ_LEN(asf->prop_flags & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE, + ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_, off_len); + READ_LEN(asf->prop_flags & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE, + ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_, asf->rep_data_len); + if (asf_pkt->size_left && (asf_pkt->frame_num != media_len)) { + av_log(s, AV_LOG_WARNING, "Unfinished frame will be ignored\n"); + reset_packet(asf_pkt); + } + asf_pkt->frame_num = media_len; + asf->sub_dts = off_len; + if (asf->nb_mult_left) { + if ((ret = asf_read_multiple_payload(s, pkt, asf_pkt)) < 0) + return ret; + } else if (asf->rep_data_len == 1) { + asf->sub_left = 1; + asf->state = READ_SINGLE; + pkt->flags = asf_pkt->flags; + if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) + return ret; + } else { + if ((ret = asf_read_single_payload(s, pkt, asf_pkt)) < 0) + return ret; + } + } else { + for (i = 0; i <= asf->nb_streams; i++) { + if (asf->stream_index == asf->asf_st[i]->stream_index) { + asf_pkt = &asf->asf_st[i]->pkt; + break; + } + } + if (!asf_pkt) + return AVERROR_INVALIDDATA; + pkt->flags = asf_pkt->flags; + pkt->dts = asf_pkt->dts; + pkt->stream_index = asf->asf_st[i]->index; + if ((ret = asf_read_subpayload(s, pkt, 0)) < 0) // read subpayload without its header + return ret; + } + + return 0; +} + +static int asf_read_packet_header(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + uint64_t size; + uint32_t av_unused seq; + unsigned char error_flags, len_flags, pay_flags; + + asf->packet_offset = avio_tell(pb); + error_flags = avio_r8(pb); // read Error Correction Flags + if (error_flags & ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT) { + if (!(error_flags & ASF_ERROR_CORRECTION_LENGTH_TYPE)) { + size = error_flags & ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; + avio_skip(pb, size); + } + len_flags = avio_r8(pb); + } else + len_flags = error_flags; + asf->prop_flags = avio_r8(pb); + READ_LEN(len_flags & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE, + ASF_PPI_FLAG_PACKET_LENGTH_FIELD_, asf->packet_size_internal); + READ_LEN(len_flags & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE, + ASF_PPI_FLAG_SEQUENCE_FIELD_, seq); + READ_LEN(len_flags & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE, + ASF_PPI_FLAG_PADDING_LENGTH_FIELD_, asf->pad_len ); + asf->send_time = avio_rl32(pb); // send time + avio_skip(pb, 2); // skip duration + if (len_flags & ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT) { // Multiple Payloads present + pay_flags = avio_r8(pb); + asf->nb_mult_left = (pay_flags & ASF_NUM_OF_PAYLOADS); + } + + return 0; +} + +static int asf_deinterleave(AVFormatContext *s, ASFPacket *asf_pkt, int st_num) +{ + ASFContext *asf = s->priv_data; + ASFStream *asf_st = asf->asf_st[st_num]; + unsigned char *p = asf_pkt->avpkt.data; + uint16_t pkt_len = asf->asf_st[st_num]->virtual_pkt_len; + uint16_t chunk_len = asf->asf_st[st_num]->virtual_chunk_len; + int nchunks = pkt_len / chunk_len; + AVPacket pkt; + int pos = 0, j, l, ret; + + + if ((ret = av_new_packet(&pkt, asf_pkt->data_size)) < 0) + return ret; + + while (asf_pkt->data_size >= asf_st->span * pkt_len + pos) { + if (pos >= asf_pkt->data_size) { + break; + } + for (l = 0; l < pkt_len; l++) { + if (pos >= asf_pkt->data_size) { + break; + } + for (j = 0; j < asf_st->span; j++) { + if ((pos + chunk_len) >= asf_pkt->data_size) + break; + memcpy(pkt.data + pos, + p + (j * nchunks + l) * chunk_len, + chunk_len); + pos += chunk_len; + } + } + p += asf_st->span * pkt_len; + if (p > asf_pkt->avpkt.data + asf_pkt->data_size) + break; + } + av_free_packet(&asf_pkt->avpkt); + asf_pkt->avpkt = pkt; + + return 0; +} + +static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int ret, i; + + if ((avio_tell(pb) >= asf->data_offset + asf->data_size) && + !(asf->b_flags & ASF_FLAG_BROADCAST)) + return AVERROR_EOF; + while (!pb->eof_reached) { + if (asf->state == PARSE_PACKET_HEADER) { + asf_read_packet_header(s); + if (!asf->nb_mult_left) + asf->state = READ_SINGLE; + else + asf->state = READ_MULTI; + } + if ((ret = asf_read_payload(s, pkt)) < 0) + return ret; + switch (asf->state) { + case READ_SINGLE: + if (!asf->sub_left) + asf->state = PARSE_PACKET_HEADER; + break; + case READ_MULTI_SUB: + if (!asf->sub_left && !asf->nb_mult_left) { + asf->state = PARSE_PACKET_HEADER; + if (!asf->return_subpayload) + avio_skip(pb, asf->pad_len); // skip padding + if (asf->packet_offset + asf->packet_size > avio_tell(pb)) + avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); + } else if (!asf->sub_left) + asf->state = READ_MULTI; + break; + case READ_MULTI: + if (!asf->nb_mult_left) { + asf->state = PARSE_PACKET_HEADER; + if (!asf->return_subpayload) { + avio_skip(pb, asf->pad_len); // skip padding + } + if (asf->packet_offset + asf->packet_size > avio_tell(pb)) + avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); + } + break; + } + if (asf->return_subpayload) { + asf->return_subpayload = 0; + return 0; + } + for (i = 0; i < s->nb_streams; i++) { + ASFPacket *asf_pkt = &asf->asf_st[i]->pkt; + if (asf_pkt && !asf_pkt->size_left && asf_pkt->data_size) { + if (asf->asf_st[i]->span > 1 && + asf->asf_st[i]->type == AVMEDIA_TYPE_AUDIO) + if ((ret = asf_deinterleave(s, asf_pkt, i)) < 0) + return ret; + av_packet_move_ref(pkt, &asf_pkt->avpkt); + pkt->stream_index = asf->asf_st[i]->index; + pkt->flags = asf_pkt->flags; + pkt->dts = asf_pkt->dts - asf->preroll; + asf_pkt->data_size = 0; + asf_pkt->frame_num = 0; + return 0; + } + } + } + + if (pb->eof_reached) + return AVERROR_EOF; + + return 0; +} + +static int asf_read_close(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + int i; + + for (i = 0; i < ASF_MAX_STREAMS; i++) { + av_dict_free(&asf->asf_sd[i].asf_met); + if (i < asf->nb_streams) { + av_free_packet(&asf->asf_st[i]->pkt.avpkt); + av_freep(&asf->asf_st[i]); + } + } + + asf->nb_streams = 0; + return 0; +} + +static void reset_packet_state(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + int i; + + asf->state = PARSE_PACKET_HEADER; + asf->offset = 0; + asf->return_subpayload = 0; + asf->sub_left = 0; + asf->sub_header_offset = 0; + asf->packet_offset = asf->first_packet_offset; + asf->pad_len = 0; + asf->rep_data_len = 0; + asf->dts_delta = 0; + asf->mult_sub_len = 0; + asf->nb_mult_left = 0; + asf->nb_sub = 0; + asf->prop_flags = 0; + asf->sub_dts = 0; + for (i = 0; i < asf->nb_streams; i++) { + ASFPacket *pkt = &asf->asf_st[i]->pkt; + pkt->size_left = 0; + pkt->data_size = 0; + pkt->duration = 0; + pkt->flags = 0; + pkt->dts = 0; + pkt->duration = 0; + av_free_packet(&pkt->avpkt); + av_init_packet(&pkt->avpkt); + } +} + +/* + * Find a timestamp for the requested position within the payload + * where the pos (position) is the offset inside the Data Object. + * When position is not on the packet boundary, asf_read_timestamp tries + * to find the closest packet offset after this position. If this packet + * is a key frame, this packet timestamp is read and an index entry is created + * for the packet. If this packet belongs to the requested stream, + * asf_read_timestamp upgrades pos to the packet beginning offset and + * returns this packet's dts. So returned dts is the dts of the first key frame with + * matching stream number after given position. + */ +static int64_t asf_read_timestamp(AVFormatContext *s, int stream_index, + int64_t *pos, int64_t pos_limit) +{ + ASFContext *asf = s->priv_data; + int64_t pkt_pos = *pos, pkt_offset, dts = AV_NOPTS_VALUE, data_end; + AVPacket pkt; + int n; + + data_end = asf->data_offset + asf->data_size; + + n = (pkt_pos - asf->first_packet_offset + asf->packet_size - 1) / + asf->packet_size; + n = av_clip(n, 0, ((data_end - asf->first_packet_offset) / asf->packet_size - 1)); + pkt_pos = asf->first_packet_offset + n * asf->packet_size; + + avio_seek(s->pb, pkt_pos, SEEK_SET); + pkt_offset = pkt_pos; + + reset_packet_state(s); + while (avio_tell(s->pb) < data_end) { + + int i, ret, st_found; + + av_init_packet(&pkt); + pkt_offset = avio_tell(s->pb); + if ((ret = asf_read_packet(s, &pkt)) < 0) { + dts = AV_NOPTS_VALUE; + return ret; + } + // ASFPacket may contain fragments of packets belonging to different streams, + // pkt_offset is the offset of the first fragment within it. + if ((pkt_offset >= (pkt_pos + asf->packet_size))) + pkt_pos += asf->packet_size; + for (i = 0; i < asf->nb_streams; i++) { + ASFStream *st = asf->asf_st[i]; + + st_found = 0; + if (pkt.flags & AV_PKT_FLAG_KEY) { + dts = pkt.dts; + if (dts) { + av_add_index_entry(s->streams[pkt.stream_index], pkt_pos, + dts, pkt.size, 0, AVINDEX_KEYFRAME); + if (stream_index == st->index) { + st_found = 1; + break; + } + } + } + } + if (st_found) + break; + av_free_packet(&pkt); + } + *pos = pkt_pos; + + av_free_packet(&pkt); + return dts; +} + +static int asf_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) +{ + ASFContext *asf = s->priv_data; + int idx, ret; + + if (s->streams[stream_index]->nb_index_entries && asf->is_simple_index) { + idx = av_index_search_timestamp(s->streams[stream_index], timestamp, flags); + if (idx < 0 || idx >= s->streams[stream_index]->nb_index_entries) + return AVERROR_INVALIDDATA; + avio_seek(s->pb, s->streams[stream_index]->index_entries[idx].pos, SEEK_SET); + } else { + if ((ret = ff_seek_frame_binary(s, stream_index, timestamp, flags)) < 0) + return ret; + } + + reset_packet_state(s); + + return 0; +} + +static const GUIDParseTable *find_guid(ff_asf_guid guid) +{ + int j, ret; + const GUIDParseTable *g; + + swap_guid(guid); + g = gdef; + for (j = 0; j < FF_ARRAY_ELEMS(gdef); j++) { + if (!(ret = memcmp(guid, g->guid, sizeof(g->guid)))) + return g; + g++; + } + + return NULL; +} + +static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + const GUIDParseTable *g = NULL; + ff_asf_guid guid; + int ret; + + while (avio_tell(pb) <= offset + size) { + if (avio_tell(pb) == asf->offset) + break; + asf->offset = avio_tell(pb); + if ((ret = ff_get_guid(pb, &guid)) < 0) + return ret; + g = find_guid(guid); + if (g) { + if ((ret = g->read_object(s, g)) < 0) + return ret; + } else { + GUIDParseTable g2; + + g2.name = "Unknown"; + g2.is_subobject = 1; + asf_read_unknown(s, &g2); + } + } + + return 0; +} + +static int asf_read_header(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + const GUIDParseTable *g = NULL; + ff_asf_guid guid; + int i, ret; + uint64_t size; + + asf->preroll = 0; + asf->is_simple_index = 0; + ff_get_guid(pb, &guid); + if (ff_guidcmp(&guid, &ff_asf_header)) + return AVERROR_INVALIDDATA; + avio_skip(pb, 8); // skip header object size + avio_skip(pb, 6); // skip number of header objects and 2 reserved bytes + asf->data_reached = 0; + + /* 1 is here instead of pb->eof_reached because (when not streaming), Data are skipped + * for the first time, + * Index object is processed and got eof and then seeking back to the Data is performed. + */ + while (1) { + // for the cases when object size is invalid + if (avio_tell(pb) == asf->offset) + break; + asf->offset = avio_tell(pb); + if ((ret = ff_get_guid(pb, &guid)) < 0) { + if (ret == AVERROR_EOF && asf->data_reached) + break; + else + goto failed; + } + g = find_guid(guid); + if (g) { + asf->unknown_offset = asf->offset; + asf->is_header = 1; + if ((ret = g->read_object(s, g)) < 0) + goto failed; + } else { + size = avio_rl64(pb); + align_position(pb, asf->offset, size); + } + if (asf->data_reached && (!pb->seekable || (asf->b_flags & ASF_FLAG_BROADCAST))) + break; + } + + if (!asf->data_reached) { + av_log(s, AV_LOG_ERROR, "Data Object was not found.\n"); + ret = AVERROR_INVALIDDATA; + goto failed; + } + if (pb->seekable) + avio_seek(pb, asf->first_packet_offset, SEEK_SET); + + for (i = 0; i < asf->nb_streams; i++) { + const char *rfc1766 = asf->asf_sd[asf->asf_st[i]->lang_idx].langs; + AVStream *st = s->streams[asf->asf_st[i]->index]; + set_language(s, rfc1766, &st->metadata); + } + + for (i = 0; i < ASF_MAX_STREAMS; i++) { + AVStream *st = NULL; + + st = find_stream(s, i); + if (st) { + av_dict_copy(&st->metadata, asf->asf_sd[i].asf_met, AV_DICT_IGNORE_SUFFIX); + if (asf->asf_sd[i].aspect_ratio.num > 0 && asf->asf_sd[i].aspect_ratio.den > 0) { + st->sample_aspect_ratio.num = asf->asf_sd[i].aspect_ratio.num; + st->sample_aspect_ratio.den = asf->asf_sd[i].aspect_ratio.den; + } + } + } + + return 0; + +failed: + asf_read_close(s); + return ret; +} + +AVInputFormat ff_asf_o_demuxer = { + .name = "asf_o", + .long_name = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"), + .priv_data_size = sizeof(ASFContext), + .read_probe = asf_probe, + .read_header = asf_read_header, + .read_packet = asf_read_packet, + .read_close = asf_read_close, + .read_timestamp = asf_read_timestamp, + .read_seek = asf_read_seek, + .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/asfenc.c b/chromium/third_party/ffmpeg/libavformat/asfenc.c index 015c731cec8..32b726bb293 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/asfenc.c @@ -183,6 +183,38 @@ #define DATA_HEADER_SIZE 50 +typedef struct ASFPayload { + uint8_t type; + uint16_t size; +} ASFPayload; + +typedef struct ASFStream { + int num; + unsigned char seq; + /* use for reading */ + AVPacket pkt; + int frag_offset; + int packet_obj_size; + int timestamp; + int64_t duration; + int skip_to_key; + int pkt_clean; + + int ds_span; /* descrambling */ + int ds_packet_size; + int ds_chunk_size; + + int64_t packet_pos; + + uint16_t stream_language_index; + + int palette_changed; + uint32_t palette[256]; + + int payload_ext_ct; + ASFPayload payload[8]; +} ASFStream; + typedef struct ASFContext { uint32_t seqno; int is_streamed; diff --git a/chromium/third_party/ffmpeg/libavformat/assdec.c b/chromium/third_party/ffmpeg/libavformat/assdec.c index c62e76f0ddb..5423c03f146 100644 --- a/chromium/third_party/ffmpeg/libavformat/assdec.c +++ b/chromium/third_party/ffmpeg/libavformat/assdec.c @@ -152,7 +152,7 @@ static int ass_read_header(AVFormatContext *s) if (res < 0) goto end; - ff_subtitles_queue_finalize(&ass->q); + ff_subtitles_queue_finalize(s, &ass->q); end: av_bprint_finalize(&header, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/async.c b/chromium/third_party/ffmpeg/libavformat/async.c new file mode 100644 index 00000000000..003212d5b6c --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/async.c @@ -0,0 +1,560 @@ +/* + * Input async protocol. + * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Based on libavformat/cache.c by Michael Niedermayer + */ + + /** + * @TODO + * support timeout + * support backward short seek + * support work with concatdec, hls + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/error.h" +#include "libavutil/fifo.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "url.h" +#include <stdint.h> +#include <pthread.h> + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#define BUFFER_CAPACITY (4 * 1024 * 1024) +#define SHORT_SEEK_THRESHOLD (256 * 1024) + +typedef struct Context { + AVClass *class; + URLContext *inner; + + int seek_request; + int64_t seek_pos; + int seek_whence; + int seek_completed; + int64_t seek_ret; + + int io_error; + int io_eof_reached; + + int64_t logical_pos; + int64_t logical_size; + AVFifoBuffer *fifo; + + pthread_cond_t cond_wakeup_main; + pthread_cond_t cond_wakeup_background; + pthread_mutex_t mutex; + pthread_t async_buffer_thread; + + int abort_request; + AVIOInterruptCB interrupt_callback; +} Context; + +static int async_check_interrupt(void *arg) +{ + URLContext *h = arg; + Context *c = h->priv_data; + + if (c->abort_request) + return 1; + + if (ff_check_interrupt(&c->interrupt_callback)) + c->abort_request = 1; + + return c->abort_request; +} + +static void *async_buffer_task(void *arg) +{ + URLContext *h = arg; + Context *c = h->priv_data; + AVFifoBuffer *fifo = c->fifo; + int ret = 0; + int64_t seek_ret; + + while (1) { + int fifo_space, to_copy; + + pthread_mutex_lock(&c->mutex); + if (async_check_interrupt(h)) { + c->io_eof_reached = 1; + c->io_error = AVERROR_EXIT; + pthread_cond_signal(&c->cond_wakeup_main); + pthread_mutex_unlock(&c->mutex); + break; + } + + if (c->seek_request) { + seek_ret = ffurl_seek(c->inner, c->seek_pos, c->seek_whence); + if (seek_ret < 0) { + c->io_eof_reached = 1; + c->io_error = (int)seek_ret; + } else { + c->io_eof_reached = 0; + c->io_error = 0; + } + + c->seek_completed = 1; + c->seek_ret = seek_ret; + c->seek_request = 0; + + av_fifo_reset(fifo); + + pthread_cond_signal(&c->cond_wakeup_main); + pthread_mutex_unlock(&c->mutex); + continue; + } + + fifo_space = av_fifo_space(fifo); + if (c->io_eof_reached || fifo_space <= 0) { + pthread_cond_signal(&c->cond_wakeup_main); + pthread_cond_wait(&c->cond_wakeup_background, &c->mutex); + pthread_mutex_unlock(&c->mutex); + continue; + } + pthread_mutex_unlock(&c->mutex); + + to_copy = FFMIN(4096, fifo_space); + ret = av_fifo_generic_write(fifo, c->inner, to_copy, (void *)ffurl_read); + + pthread_mutex_lock(&c->mutex); + if (ret <= 0) { + c->io_eof_reached = 1; + if (ret < 0) { + c->io_error = ret; + } + } + + pthread_cond_signal(&c->cond_wakeup_main); + pthread_mutex_unlock(&c->mutex); + } + + return NULL; +} + +static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options) +{ + Context *c = h->priv_data; + int ret; + AVIOInterruptCB interrupt_callback = {.callback = async_check_interrupt, .opaque = h}; + + av_strstart(arg, "async:", &arg); + + c->fifo = av_fifo_alloc(BUFFER_CAPACITY); + if (!c->fifo) { + ret = AVERROR(ENOMEM); + goto fifo_fail; + } + + /* wrap interrupt callback */ + c->interrupt_callback = h->interrupt_callback; + ret = ffurl_open(&c->inner, arg, flags, &interrupt_callback, options); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "ffurl_open failed : %s, %s\n", av_err2str(ret), arg); + goto url_fail; + } + + c->logical_size = ffurl_size(c->inner); + h->is_streamed = c->inner->is_streamed; + + ret = pthread_mutex_init(&c->mutex, NULL); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret)); + goto mutex_fail; + } + + ret = pthread_cond_init(&c->cond_wakeup_main, NULL); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); + goto cond_wakeup_main_fail; + } + + ret = pthread_cond_init(&c->cond_wakeup_background, NULL); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); + goto cond_wakeup_background_fail; + } + + ret = pthread_create(&c->async_buffer_thread, NULL, async_buffer_task, h); + if (ret) { + av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", av_err2str(ret)); + goto thread_fail; + } + + return 0; + +thread_fail: + pthread_cond_destroy(&c->cond_wakeup_background); +cond_wakeup_background_fail: + pthread_cond_destroy(&c->cond_wakeup_main); +cond_wakeup_main_fail: + pthread_mutex_destroy(&c->mutex); +mutex_fail: + ffurl_close(c->inner); +url_fail: + av_fifo_freep(&c->fifo); +fifo_fail: + return ret; +} + +static int async_close(URLContext *h) +{ + Context *c = h->priv_data; + int ret; + + pthread_mutex_lock(&c->mutex); + c->abort_request = 1; + pthread_cond_signal(&c->cond_wakeup_background); + pthread_mutex_unlock(&c->mutex); + + ret = pthread_join(c->async_buffer_thread, NULL); + if (ret != 0) + av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", av_err2str(ret)); + + pthread_cond_destroy(&c->cond_wakeup_background); + pthread_cond_destroy(&c->cond_wakeup_main); + pthread_mutex_destroy(&c->mutex); + ffurl_close(c->inner); + av_fifo_freep(&c->fifo); + + return 0; +} + +static int async_read_internal(URLContext *h, void *dest, int size, int read_complete, + void (*func)(void*, void*, int)) +{ + Context *c = h->priv_data; + AVFifoBuffer *fifo = c->fifo; + int to_read = size; + int ret = 0; + + pthread_mutex_lock(&c->mutex); + + while (to_read > 0) { + int fifo_size, to_copy; + if (async_check_interrupt(h)) { + ret = AVERROR_EXIT; + break; + } + fifo_size = av_fifo_size(fifo); + to_copy = FFMIN(to_read, fifo_size); + if (to_copy > 0) { + av_fifo_generic_read(fifo, dest, to_copy, func); + if (!func) + dest = (uint8_t *)dest + to_copy; + c->logical_pos += to_copy; + to_read -= to_copy; + ret = size - to_read; + + if (to_read <= 0 || !read_complete) + break; + } else if (c->io_eof_reached) { + if (ret <= 0) + ret = AVERROR_EOF; + break; + } + pthread_cond_signal(&c->cond_wakeup_background); + pthread_cond_wait(&c->cond_wakeup_main, &c->mutex); + } + + pthread_cond_signal(&c->cond_wakeup_background); + pthread_mutex_unlock(&c->mutex); + + return ret; +} + +static int async_read(URLContext *h, unsigned char *buf, int size) +{ + return async_read_internal(h, buf, size, 0, NULL); +} + +static void fifo_do_not_copy_func(void* dest, void* src, int size) { + // do not copy +} + +static int64_t async_seek(URLContext *h, int64_t pos, int whence) +{ + Context *c = h->priv_data; + AVFifoBuffer *fifo = c->fifo; + int64_t ret; + int64_t new_logical_pos; + int fifo_size; + + if (whence == AVSEEK_SIZE) { + av_log(h, AV_LOG_TRACE, "async_seek: AVSEEK_SIZE: %"PRId64"\n", (int64_t)c->logical_size); + return c->logical_size; + } else if (whence == SEEK_CUR) { + av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos); + new_logical_pos = pos + c->logical_pos; + } else if (whence == SEEK_SET){ + av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos); + new_logical_pos = pos; + } else { + return AVERROR(EINVAL); + } + if (new_logical_pos < 0) + return AVERROR(EINVAL); + + fifo_size = av_fifo_size(fifo); + if (new_logical_pos == c->logical_pos) { + /* current position */ + return c->logical_pos; + } else if ((new_logical_pos > c->logical_pos) && + (new_logical_pos < (c->logical_pos + fifo_size + SHORT_SEEK_THRESHOLD))) { + /* fast seek */ + av_log(h, AV_LOG_TRACE, "async_seek: fask_seek %"PRId64" from %d dist:%d/%d\n", + new_logical_pos, (int)c->logical_pos, + (int)(new_logical_pos - c->logical_pos), fifo_size); + async_read_internal(h, NULL, (int)(new_logical_pos - c->logical_pos), 1, fifo_do_not_copy_func); + return c->logical_pos; + } else if (c->logical_size <= 0) { + /* can not seek */ + return AVERROR(EINVAL); + } else if (new_logical_pos > c->logical_size) { + /* beyond end */ + return AVERROR(EINVAL); + } + + pthread_mutex_lock(&c->mutex); + + c->seek_request = 1; + c->seek_pos = new_logical_pos; + c->seek_whence = SEEK_SET; + c->seek_completed = 0; + c->seek_ret = 0; + + while (1) { + if (async_check_interrupt(h)) { + ret = AVERROR_EXIT; + break; + } + if (c->seek_completed) { + if (c->seek_ret >= 0) + c->logical_pos = c->seek_ret; + ret = c->seek_ret; + break; + } + pthread_cond_signal(&c->cond_wakeup_background); + pthread_cond_wait(&c->cond_wakeup_main, &c->mutex); + } + + pthread_mutex_unlock(&c->mutex); + + return ret; +} + +#define OFFSET(x) offsetof(Context, x) +#define D AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { + {NULL}, +}; + +static const AVClass async_context_class = { + .class_name = "Async", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +URLProtocol ff_async_protocol = { + .name = "async", + .url_open2 = async_open, + .url_read = async_read, + .url_seek = async_seek, + .url_close = async_close, + .priv_data_size = sizeof(Context), + .priv_data_class = &async_context_class, +}; + +#ifdef TEST + +#define TEST_SEEK_POS (1536) +#define TEST_STREAM_SIZE (2048) + +typedef struct TestContext { + AVClass *class; + int64_t logical_pos; + int64_t logical_size; +} TestContext; + +static int async_test_open(URLContext *h, const char *arg, int flags, AVDictionary **options) +{ + TestContext *c = h->priv_data; + c->logical_pos = 0; + c->logical_size = TEST_STREAM_SIZE; + return 0; +} + +static int async_test_close(URLContext *h) +{ + return 0; +} + +static int async_test_read(URLContext *h, unsigned char *buf, int size) +{ + TestContext *c = h->priv_data; + int i; + int read_len = 0; + + if (c->logical_pos >= c->logical_size) + return AVERROR_EOF; + + for (i = 0; i < size; ++i) { + buf[i] = c->logical_pos & 0xFF; + + c->logical_pos++; + read_len++; + + if (c->logical_pos >= c->logical_size) + break; + } + + return read_len; +} + +static int64_t async_test_seek(URLContext *h, int64_t pos, int whence) +{ + TestContext *c = h->priv_data; + int64_t new_logical_pos; + + if (whence == AVSEEK_SIZE) { + return c->logical_size; + } else if (whence == SEEK_CUR) { + new_logical_pos = pos + c->logical_pos; + } else if (whence == SEEK_SET){ + new_logical_pos = pos; + } else { + return AVERROR(EINVAL); + } + if (new_logical_pos < 0) + return AVERROR(EINVAL); + + c->logical_pos = new_logical_pos; + return new_logical_pos; +} + +static const AVClass async_test_context_class = { + .class_name = "Async-Test", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +URLProtocol ff_async_test_protocol = { + .name = "async-test", + .url_open2 = async_test_open, + .url_read = async_test_read, + .url_seek = async_test_seek, + .url_close = async_test_close, + .priv_data_size = sizeof(TestContext), + .priv_data_class = &async_test_context_class, +}; + +int main(void) +{ + URLContext *h = NULL; + int i; + int ret; + int64_t size; + int64_t pos; + int64_t read_len; + unsigned char buf[4096]; + + ffurl_register_protocol(&ff_async_protocol); + ffurl_register_protocol(&ff_async_test_protocol); + + ret = ffurl_open(&h, "async:async-test:", AVIO_FLAG_READ, NULL, NULL); + printf("open: %d\n", ret); + + size = ffurl_size(h); + printf("size: %"PRId64"\n", size); + + pos = ffurl_seek(h, 0, SEEK_CUR); + read_len = 0; + while (1) { + ret = ffurl_read(h, buf, sizeof(buf)); + if (ret == AVERROR_EOF) { + printf("read-error: AVERROR_EOF at %"PRId64"\n", ffurl_seek(h, 0, SEEK_CUR)); + break; + } + else if (ret == 0) + break; + else if (ret < 0) { + printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR)); + goto fail; + } else { + for (i = 0; i < ret; ++i) { + if (buf[i] != (pos & 0xFF)) { + printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n", + (int)buf[i], (int)(pos & 0xFF), pos); + break; + } + pos++; + } + } + + read_len += ret; + } + printf("read: %"PRId64"\n", read_len); + + ret = ffurl_read(h, buf, 1); + printf("read: %d\n", ret); + + pos = ffurl_seek(h, TEST_SEEK_POS, SEEK_SET); + printf("seek: %"PRId64"\n", pos); + + read_len = 0; + while (1) { + ret = ffurl_read(h, buf, sizeof(buf)); + if (ret == AVERROR_EOF) + break; + else if (ret == 0) + break; + else if (ret < 0) { + printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR)); + goto fail; + } else { + for (i = 0; i < ret; ++i) { + if (buf[i] != (pos & 0xFF)) { + printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n", + (int)buf[i], (int)(pos & 0xFF), pos); + break; + } + pos++; + } + } + + read_len += ret; + } + printf("read: %"PRId64"\n", read_len); + + ret = ffurl_read(h, buf, 1); + printf("read: %d\n", ret); + +fail: + ffurl_close(h); + return 0; +} + +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_flacdec.c b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_flacdec.c index 4207fd2bf6c..4c1f9435810 100644 --- a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_flacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_flacdec.c @@ -58,7 +58,7 @@ static int flac_read_header(AVFormatContext *s) case FLAC_METADATA_TYPE_CUESHEET: case FLAC_METADATA_TYPE_PICTURE: case FLAC_METADATA_TYPE_VORBIS_COMMENT: - buffer = av_mallocz(metadata_size + FF_INPUT_BUFFER_PADDING_SIZE); + buffer = av_mallocz(metadata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!buffer) { return AVERROR(ENOMEM); } diff --git a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_options.c b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_options.c index d238dd5ab70..9918349703a 100644 --- a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_options.c +++ b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_options.c @@ -20,6 +20,8 @@ #include "avformat.h" #include "avio_internal.h" #include "internal.h" + +#include "libavutil/internal.h" #include "libavutil/opt.h" /** @@ -27,7 +29,9 @@ * Options definition for AVFormatContext. */ +FF_DISABLE_DEPRECATION_WARNINGS #include "options_table.h" +FF_ENABLE_DEPRECATION_WARNINGS static const char* format_to_name(void* ptr) { diff --git a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_utils.c b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_utils.c index caa15abbaed..24eacf39675 100644 --- a/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_utils.c +++ b/chromium/third_party/ffmpeg/libavformat/autorename_libavformat_utils.c @@ -116,7 +116,10 @@ MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb) int64_t av_stream_get_end_pts(const AVStream *st) { - return st->pts.val; + if (st->priv_pts) { + return st->priv_pts->val; + } else + return AV_NOPTS_VALUE; } struct AVCodecParserContext *av_stream_get_parser(const AVStream *st) @@ -1262,12 +1265,6 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) { out_pkt.buf = pkt->buf; pkt->buf = NULL; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - out_pkt.destruct = pkt->destruct; - pkt->destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if ((ret = av_dup_packet(&out_pkt)) < 0) goto fail; @@ -1585,26 +1582,26 @@ int av_find_default_stream_index(AVFormatContext *s) int i; AVStream *st; int best_stream = 0; - int best_score = -1; + int best_score = INT_MIN; if (s->nb_streams <= 0) return -1; for (i = 0; i < s->nb_streams; i++) { int score = 0; st = s->streams[i]; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && - !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { - if (!st->codec->width && !st->codec->height && !st->codec_info_nb_frames) - score += 25; - else - score += 100; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + score -= 400; + if (st->codec->width && st->codec->height) + score += 50; + score+= 25; } if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if (!st->codec->sample_rate && !st->codec_info_nb_frames) - score += 12; - else + if (st->codec->sample_rate) score += 50; } + if (st->codec_info_nb_frames) + score += 12; if (st->discard != AVDISCARD_ALL) score += 200; @@ -1781,6 +1778,63 @@ int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, return m; } +void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance) +{ + int ist1, ist2; + int64_t pos_delta = 0; + int64_t skip = 0; + //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable + const char *proto = avio_find_protocol_name(s->filename); + + if (!proto) { + av_log(s, AV_LOG_INFO, + "Protocol name not provided, cannot determine if input is local or " + "a network protocol, buffers and access patterns cannot be configured " + "optimally without knowing the protocol\n"); + } + + if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache"))) + return; + + for (ist1 = 0; ist1 < s->nb_streams; ist1++) { + AVStream *st1 = s->streams[ist1]; + for (ist2 = 0; ist2 < s->nb_streams; ist2++) { + AVStream *st2 = s->streams[ist2]; + int i1, i2; + + if (ist1 == ist2) + continue; + + for (i1 = i2 = 0; i1 < st1->nb_index_entries; i1++) { + AVIndexEntry *e1 = &st1->index_entries[i1]; + int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q); + + skip = FFMAX(skip, e1->size); + for (; i2 < st2->nb_index_entries; i2++) { + AVIndexEntry *e2 = &st2->index_entries[i2]; + int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q); + if (e2_pts - e1_pts < time_tolerance) + continue; + pos_delta = FFMAX(pos_delta, e1->pos - e2->pos); + break; + } + } + } + } + + pos_delta *= 2; + /* XXX This could be adjusted depending on protocol*/ + if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) { + av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta); + ffio_set_buf_size(s->pb, pos_delta); + s->pb->short_seek_threshold = FFMAX(s->pb->short_seek_threshold, pos_delta/2); + } + + if (skip < (1<<23)) { + s->pb->short_seek_threshold = FFMAX(s->pb->short_seek_threshold, skip); + } +} + int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) { return ff_index_search_timestamp(st->index_entries, st->nb_index_entries, @@ -2665,7 +2719,7 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, ret >= 0 && (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) || (!st->codec_info_nb_frames && - st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { + (st->codec->codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)))) { got_picture = 0; switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: @@ -2865,14 +2919,14 @@ int ff_alloc_extradata(AVCodecContext *avctx, int size) { int ret; - if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) { + if (size < 0 || size >= INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { avctx->extradata = NULL; avctx->extradata_size = 0; return AVERROR(EINVAL); } - avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); if (avctx->extradata) { - memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(avctx->extradata + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); avctx->extradata_size = size; ret = 0; } else { @@ -3031,9 +3085,18 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) // new streams might appear, no options for those int orig_nb_streams = ic->nb_streams; int flush_codecs; +#if FF_API_PROBESIZE_32 int64_t max_analyze_duration = ic->max_analyze_duration2; +#else + int64_t max_analyze_duration = ic->max_analyze_duration; +#endif int64_t max_stream_analyze_duration; + int64_t max_subtitle_analyze_duration; +#if FF_API_PROBESIZE_32 int64_t probesize = ic->probesize2; +#else + int64_t probesize = ic->probesize; +#endif if (!max_analyze_duration) max_analyze_duration = ic->max_analyze_duration; @@ -3044,11 +3107,13 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN); max_stream_analyze_duration = max_analyze_duration; + max_subtitle_analyze_duration = max_analyze_duration; if (!max_analyze_duration) { max_stream_analyze_duration = max_analyze_duration = 5*AV_TIME_BASE; + max_subtitle_analyze_duration = 30*AV_TIME_BASE; if (!strcmp(ic->iformat->name, "flv")) - max_stream_analyze_duration = 30*AV_TIME_BASE; + max_stream_analyze_duration = 90*AV_TIME_BASE; } if (ic->pb) @@ -3264,6 +3329,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } if (st->codec_info_nb_frames>1) { int64_t t = 0; + int64_t limit; if (st->time_base.den > 0) t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q); @@ -3276,10 +3342,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) && st->info->fps_last_dts != AV_NOPTS_VALUE) t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q)); - if (t >= (analyzed_all_streams ? max_analyze_duration : max_stream_analyze_duration)) { - av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds\n", - max_analyze_duration, - t); + if (analyzed_all_streams) limit = max_analyze_duration; + else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) limit = max_subtitle_analyze_duration; + else limit = max_stream_analyze_duration; + + if (t >= limit) { + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds st:%d\n", + limit, + t, pkt->stream_index); if (ic->flags & AVFMT_FLAG_NOBUFFER) av_packet_unref(pkt); break; @@ -3308,7 +3378,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) * it takes longer and uses more memory. For MPEG-4, we need to * decompress for QuickTime. * - * If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at + * If AV_CODEC_CAP_CHANNEL_CONF is set this will force decoding of at * least one frame of codec data, this makes sure the codec initializes * the channel configuration and does not only trust the values from * the container. */ @@ -3603,6 +3673,7 @@ void ff_free_stream(AVFormatContext *s, AVStream *st) { av_freep(&st->info->duration_error); av_freep(&st->info); av_freep(&st->recommended_encoder_configuration); + av_freep(&st->priv_pts); av_freep(&s->streams[ --s->nb_streams ]); } @@ -4235,8 +4306,9 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, if (*spec <= '9' && *spec >= '0') /* opt:index */ return strtol(spec, NULL, 0) == st->index; else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || - *spec == 't') { /* opt:[vasdt] */ + *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ enum AVMediaType type; + int nopic = 0; switch (*spec++) { case 'v': type = AVMEDIA_TYPE_VIDEO; break; @@ -4244,15 +4316,20 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, case 's': type = AVMEDIA_TYPE_SUBTITLE; break; case 'd': type = AVMEDIA_TYPE_DATA; break; case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; + case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; default: av_assert0(0); } if (type != st->codec->codec_type) return 0; + if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + return 0; if (*spec++ == ':') { /* possibly followed by :index */ int i, index = strtol(spec, NULL, 0); for (i = 0; i < s->nb_streams; i++) - if (s->streams[i]->codec->codec_type == type && index-- == 0) - return i == st->index; + if (s->streams[i]->codec->codec_type == type && + !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && + index-- == 0) + return i == st->index; return 0; } return 1; diff --git a/chromium/third_party/ffmpeg/libavformat/avc.c b/chromium/third_party/ffmpeg/libavformat/avc.c index 9d843e0ca4b..f7b8f38a00a 100644 --- a/chromium/third_party/ffmpeg/libavformat/avc.c +++ b/chromium/third_party/ffmpeg/libavformat/avc.c @@ -180,7 +180,7 @@ int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size) if (11 + sps_size + pps_size > *size) return AVERROR_INVALIDDATA; out_size = 8 + sps_size + pps_size; - out = av_mallocz(out_size + FF_INPUT_BUFFER_PADDING_SIZE); + out = av_mallocz(out_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!out) return AVERROR(ENOMEM); AV_WB32(&out[0], 0x00000001); diff --git a/chromium/third_party/ffmpeg/libavformat/avformat.h b/chromium/third_party/ffmpeg/libavformat/avformat.h index fb69852f458..b7f18c16143 100644 --- a/chromium/third_party/ffmpeg/libavformat/avformat.h +++ b/chromium/third_party/ffmpeg/libavformat/avformat.h @@ -478,12 +478,7 @@ typedef struct AVProbeData { #define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */ #define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */ #define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */ -#if LIBAVFORMAT_VERSION_MAJOR <= 54 -#define AVFMT_TS_NONSTRICT 0x8020000 //we try to be compatible to the ABIs of ffmpeg and major forks -#else -#define AVFMT_TS_NONSTRICT 0x20000 -#endif - /**< Format does not require strictly +#define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly increasing timestamps, but they must still be monotonic */ #define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative @@ -1015,7 +1010,6 @@ typedef struct AVStream { /** * Number of packets to buffer for codec probing */ -#define MAX_PROBE_PACKETS 2500 int probe_packets; /** @@ -1171,6 +1165,8 @@ typedef struct AVStream { * - decoding: Set by libavformat to calculate sample_aspect_ratio internally */ AVRational display_aspect_ratio; + + struct FFFrac *priv_pts; } AVStream; AVRational av_stream_get_r_frame_rate(const AVStream *s); @@ -1395,6 +1391,7 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. #define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats +#if FF_API_PROBESIZE_32 /** * @deprecated deprecated in favor of probesize2 */ @@ -1405,6 +1402,7 @@ typedef struct AVFormatContext { */ attribute_deprecated int max_analyze_duration; +#endif const uint8_t *key; int keylen; @@ -1757,7 +1755,11 @@ typedef struct AVFormatContext { * via AVOptions (NO direct access). * Can be set to 0 to let avformat choose using a heuristic. */ +#if FF_API_PROBESIZE_32 int64_t max_analyze_duration2; +#else + int64_t max_analyze_duration; +#endif /** * Maximum size of the data read from input for determining @@ -1765,7 +1767,11 @@ typedef struct AVFormatContext { * Demuxing only, set by the caller before avformat_open_input() * via AVOptions (NO direct access). */ +#if FF_API_PROBESIZE_32 int64_t probesize2; +#else + int64_t probesize; +#endif /** * dump format separator. diff --git a/chromium/third_party/ffmpeg/libavformat/avidec.c b/chromium/third_party/ffmpeg/libavformat/avidec.c index 5348b44b741..30b949770e6 100644 --- a/chromium/third_party/ffmpeg/libavformat/avidec.c +++ b/chromium/third_party/ffmpeg/libavformat/avidec.c @@ -823,7 +823,7 @@ static int avi_read_header(AVFormatContext *s) st->codec->extradata_size += 9; if ((ret = av_reallocp(&st->codec->extradata, st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { st->codec->extradata_size = 0; return ret; } else @@ -835,7 +835,7 @@ static int avi_read_header(AVFormatContext *s) // avio_skip(pb, size - 5 * 4); break; case AVMEDIA_TYPE_AUDIO: - ret = ff_get_wav_header(pb, st->codec, size, 0); + ret = ff_get_wav_header(s, pb, st->codec, size, 0); if (ret < 0) return ret; ast->dshow_block_align = st->codec->block_align; @@ -861,6 +861,9 @@ static int avi_read_header(AVFormatContext *s) if (st->codec->codec_id == AV_CODEC_ID_AAC && st->codec->extradata_size) st->need_parsing = AVSTREAM_PARSE_NONE; + // The flac parser does not work with AVSTREAM_PARSE_TIMESTAMPS + if (st->codec->codec_id == AV_CODEC_ID_FLAC) + st->need_parsing = AVSTREAM_PARSE_NONE; /* AVI files with Xan DPCM audio (wrongly) declare PCM * audio in the header but have Axan as stream_code_tag. */ if (ast->handler == AV_RL32("Axan")) { @@ -872,8 +875,9 @@ static int avi_read_header(AVFormatContext *s) st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV; ast->dshow_block_align = 0; } - if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align || - st->codec->codec_id == AV_CODEC_ID_MP2 && ast->dshow_block_align <= 4 && ast->dshow_block_align) { + if ((st->codec->codec_id == AV_CODEC_ID_AAC || + st->codec->codec_id == AV_CODEC_ID_FLAC || + st->codec->codec_id == AV_CODEC_ID_MP2 ) && ast->dshow_block_align <= 4 && ast->dshow_block_align) { av_log(s, AV_LOG_DEBUG, "overriding invalid dshow_block_align of %d\n", ast->dshow_block_align); ast->dshow_block_align = 0; } @@ -1304,9 +1308,6 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; int err; -#if FF_API_DESTRUCT_PACKET - void *dstr; -#endif if (CONFIG_DV_DEMUXER && avi->dv_demux) { int size = avpriv_dv_get_packet(avi->dv_demux, pkt); @@ -1423,18 +1424,8 @@ resync: if (CONFIG_DV_DEMUXER && avi->dv_demux) { AVBufferRef *avbuf = pkt->buf; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - dstr = pkt->destruct; -FF_ENABLE_DEPRECATION_WARNINGS -#endif size = avpriv_dv_produce_packet(avi->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = dstr; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pkt->buf = avbuf; pkt->flags |= AV_PKT_FLAG_KEY; if (size < 0) @@ -1681,9 +1672,13 @@ static int guess_ni_flag(AVFormatContext *s) if (n >= 2) { int64_t pos = st->index_entries[0].pos; - avio_seek(s->pb, pos + 4, SEEK_SET); + unsigned tag[2]; + avio_seek(s->pb, pos, SEEK_SET); + tag[0] = avio_r8(s->pb); + tag[1] = avio_r8(s->pb); + avio_rl16(s->pb); size = avio_rl32(s->pb); - if (pos + size > st->index_entries[1].pos) + if (get_stream_idx(tag) == i && pos + size > st->index_entries[1].pos) last_start = INT64_MAX; } diff --git a/chromium/third_party/ffmpeg/libavformat/avienc.c b/chromium/third_party/ffmpeg/libavformat/avienc.c index e5609d998c3..649961d11cf 100644 --- a/chromium/third_party/ffmpeg/libavformat/avienc.c +++ b/chromium/third_party/ffmpeg/libavformat/avienc.c @@ -29,10 +29,12 @@ #include "mpegts.h" #include "libavformat/avlanguage.h" #include "libavutil/avstring.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" #include "libavutil/timestamp.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavcodec/raw.h" @@ -57,9 +59,11 @@ typedef struct AVIIndex { } AVIIndex; typedef struct AVIContext { + const AVClass *class; int64_t riff_start, movi_list, odml_list; int64_t frames_hdr_all; int riff_id; + int write_channel_mask; } AVIContext; typedef struct AVIStream { @@ -338,7 +342,7 @@ static int avi_write_header(AVFormatContext *s) ff_end_tag(pb, strh); if (enc->codec_type != AVMEDIA_TYPE_DATA) { - int ret; + int ret, flags; enum AVPixelFormat pix_fmt; strf = ff_start_tag(pb, "strf"); @@ -366,7 +370,8 @@ static int avi_write_header(AVFormatContext *s) av_get_pix_fmt_name(enc->pix_fmt)); break; case AVMEDIA_TYPE_AUDIO: - if ((ret = ff_put_wav_header(pb, enc, 0)) < 0) + flags = (avi->write_channel_mask == 0) ? FF_PUT_WAV_HEADER_SKIP_CHANNELMASK : 0; + if ((ret = ff_put_wav_header(pb, enc, flags)) < 0) return ret; break; default: @@ -618,7 +623,7 @@ static int write_skip_frames(AVFormatContext *s, int stream_index, int64_t dts) AVIStream *avist = s->streams[stream_index]->priv_data; AVCodecContext *enc = s->streams[stream_index]->codec; - av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(dts), avist->packet_count, stream_index); + ff_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(dts), avist->packet_count, stream_index); while (enc->block_align == 0 && dts != AV_NOPTS_VALUE && dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) { AVPacket empty_packet; @@ -633,7 +638,7 @@ static int write_skip_frames(AVFormatContext *s, int stream_index, int64_t dts) empty_packet.data = NULL; empty_packet.stream_index = stream_index; avi_write_packet(s, &empty_packet); - av_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count); + ff_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count); } return 0; @@ -781,6 +786,20 @@ static int avi_write_trailer(AVFormatContext *s) return res; } +#define OFFSET(x) offsetof(AVIContext, x) +#define ENC AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "write_channel_mask", "write channel mask into wave format header", OFFSET(write_channel_mask), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC }, + { NULL }, +}; + +static const AVClass avi_muxer_class = { + .class_name = "AVI muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_avi_muxer = { .name = "avi", .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), @@ -795,4 +814,5 @@ AVOutputFormat ff_avi_muxer = { .codec_tag = (const AVCodecTag * const []) { ff_codec_bmp_tags, ff_codec_wav_tags, 0 }, + .priv_class = &avi_muxer_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/avio.c b/chromium/third_party/ffmpeg/libavformat/avio.c index deeb87f9ecb..21713d9d5e6 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.c +++ b/chromium/third_party/ffmpeg/libavformat/avio.c @@ -211,6 +211,26 @@ int ffurl_connect(URLContext *uc, AVDictionary **options) return 0; } +int ffurl_accept(URLContext *s, URLContext **c) +{ + av_assert0(!*c); + if (s->prot->url_accept) + return s->prot->url_accept(s, c); + return AVERROR(EBADF); +} + +int ffurl_handshake(URLContext *c) +{ + int ret; + if (c->prot->url_handshake) { + ret = c->prot->url_handshake(c); + if (ret) + return ret; + } + c->is_connected = 1; + return 0; +} + #define URL_SCHEME_CHARS \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ @@ -263,7 +283,7 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, *puc = NULL; if (av_strstart(filename, "https:", NULL)) - av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with " + av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with " "openssl, gnutls,\n" "or securetransport enabled.\n"); return AVERROR_PROTOCOL_NOT_FOUND; @@ -421,6 +441,44 @@ int avio_check(const char *url, int flags) return ret; } +int avpriv_io_move(const char *url_src, const char *url_dst) +{ + URLContext *h_src, *h_dst; + int ret = ffurl_alloc(&h_src, url_src, AVIO_FLAG_READ_WRITE, NULL); + if (ret < 0) + return ret; + ret = ffurl_alloc(&h_dst, url_dst, AVIO_FLAG_WRITE, NULL); + if (ret < 0) { + ffurl_close(h_src); + return ret; + } + + if (h_src->prot == h_dst->prot && h_src->prot->url_move) + ret = h_src->prot->url_move(h_src, h_dst); + else + ret = AVERROR(ENOSYS); + + ffurl_close(h_src); + ffurl_close(h_dst); + return ret; +} + +int avpriv_io_delete(const char *url) +{ + URLContext *h; + int ret = ffurl_alloc(&h, url, AVIO_FLAG_WRITE, NULL); + if (ret < 0) + return ret; + + if (h->prot->url_delete) + ret = h->prot->url_delete(h); + else + ret = AVERROR(ENOSYS); + + ffurl_close(h); + return ret; +} + int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options) { URLContext *h = NULL; @@ -447,6 +505,7 @@ int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options) if (ret < 0) goto fail; + h->is_connected = 1; ctx->url_context = h; *s = ctx; return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/avio.h b/chromium/third_party/ffmpeg/libavformat/avio.h index 9f3a992307e..06dd7f5ef8e 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.h +++ b/chromium/third_party/ffmpeg/libavformat/avio.h @@ -230,6 +230,25 @@ const char *avio_find_protocol_name(const char *url); int avio_check(const char *url, int flags); /** + * Move or rename a resource. + * + * @note url_src and url_dst should share the same protocol and authority. + * + * @param url_src url to resource to be moved + * @param url_dst new url to resource if the operation succeeded + * @return >=0 on success or negative on error. + */ +int avpriv_io_move(const char *url_src, const char *url_dst); + +/** + * Delete a resource. + * + * @param url resource to be deleted. + * @return >=0 on success or negative on error. + */ +int avpriv_io_delete(const char *url); + +/** * Open directory for reading. * * @param s directory read context. Pointer to a NULL pointer must be passed. @@ -566,7 +585,7 @@ int avio_open_dyn_buf(AVIOContext **s); /** * Return the written size and a pointer to the buffer. The buffer * must be freed with av_free(). - * Padding of FF_INPUT_BUFFER_PADDING_SIZE is added to the buffer. + * Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer. * * @param s IO context * @param pbuffer pointer to a byte buffer @@ -629,4 +648,33 @@ struct AVBPrint; */ int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size); +/** + * Accept and allocate a client context on a server context. + * @param s the server context + * @param c the client context, must be unallocated + * @return >= 0 on success or a negative value corresponding + * to an AVERROR on failure + */ +int avio_accept(AVIOContext *s, AVIOContext **c); + +/** + * Perform one step of the protocol handshake to accept a new client. + * This function must be called on a client returned by avio_accept() before + * using it as a read/write context. + * It is separate from avio_accept() because it may block. + * A step of the handshake is defined by places where the application may + * decide to change the proceedings. + * For example, on a protocol with a request header and a reply header, each + * one can constitute a step because the application may use the parameters + * from the request to change parameters in the reply; or each individual + * chunk of the request can constitute a step. + * If the handshake is already finished, avio_handshake() does nothing and + * returns 0 immediately. + * + * @param c the client context to perform the handshake on + * @return 0 on a complete and successful handshake + * > 0 if the handshake progressed, but is not complete + * < 0 for an AVERROR code + */ +int avio_handshake(AVIOContext *c); #endif /* AVFORMAT_AVIO_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/aviobuf.c b/chromium/third_party/ffmpeg/libavformat/aviobuf.c index ff850813e67..1b3d5f5b80c 100644 --- a/chromium/third_party/ffmpeg/libavformat/aviobuf.c +++ b/chromium/third_party/ffmpeg/libavformat/aviobuf.c @@ -1021,6 +1021,23 @@ int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size) return 0; } +int avio_accept(AVIOContext *s, AVIOContext **c) +{ + int ret; + URLContext *sc = s->opaque; + URLContext *cc = NULL; + ret = ffurl_accept(sc, &cc); + if (ret < 0) + return ret; + return ffio_fdopen(c, cc); +} + +int avio_handshake(AVIOContext *c) +{ + URLContext *cc = c->opaque; + return ffurl_handshake(cc); +} + /* output in a dynamic buffer */ typedef struct DynBuffer { @@ -1130,7 +1147,7 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { DynBuffer *d; int size; - static const char padbuf[FF_INPUT_BUFFER_PADDING_SIZE] = {0}; + static const char padbuf[AV_INPUT_BUFFER_PADDING_SIZE] = {0}; int padding = 0; if (!s) { @@ -1141,7 +1158,7 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) /* don't attempt to pad fixed-size packet buffers */ if (!s->max_packet_size) { avio_write(s, padbuf, sizeof(padbuf)); - padding = FF_INPUT_BUFFER_PADDING_SIZE; + padding = AV_INPUT_BUFFER_PADDING_SIZE; } avio_flush(s); diff --git a/chromium/third_party/ffmpeg/libavformat/avisynth.c b/chromium/third_party/ffmpeg/libavformat/avisynth.c index 7dc5ee7df62..45641c0fc1d 100644 --- a/chromium/third_party/ffmpeg/libavformat/avisynth.c +++ b/chromium/third_party/ffmpeg/libavformat/avisynth.c @@ -237,13 +237,12 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) st->codec->width = avs->vi->width; st->codec->height = avs->vi->height; - st->time_base = (AVRational) { avs->vi->fps_denominator, - avs->vi->fps_numerator }; st->avg_frame_rate = (AVRational) { avs->vi->fps_numerator, avs->vi->fps_denominator }; st->start_time = 0; st->duration = avs->vi->num_frames; st->nb_frames = avs->vi->num_frames; + avpriv_set_pts_info(st, 32, avs->vi->fps_denominator, avs->vi->fps_numerator); switch (avs->vi->pixel_type) { #ifdef USING_AVISYNTH @@ -311,9 +310,8 @@ static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = avs->vi->audio_samples_per_second; st->codec->channels = avs->vi->nchannels; - st->time_base = (AVRational) { 1, - avs->vi->audio_samples_per_second }; st->duration = avs->vi->num_audio_samples; + avpriv_set_pts_info(st, 64, 1, avs->vi->audio_samples_per_second); switch (avs->vi->sample_type) { case AVS_SAMPLE_INT8: diff --git a/chromium/third_party/ffmpeg/libavformat/brstm.c b/chromium/third_party/ffmpeg/libavformat/brstm.c index 1eba943e51c..f2bc0388402 100644 --- a/chromium/third_party/ffmpeg/libavformat/brstm.c +++ b/chromium/third_party/ffmpeg/libavformat/brstm.c @@ -30,9 +30,12 @@ typedef struct BRSTMDemuxContext { uint32_t current_block; uint32_t samples_per_block; uint32_t last_block_used_bytes; + uint32_t last_block_size; + uint32_t last_block_samples; + uint32_t data_start; uint8_t *table; uint8_t *adpc; - int bfstm; + int little_endian; } BRSTMDemuxContext; static int probe(AVProbeData *p) @@ -46,7 +49,8 @@ static int probe(AVProbeData *p) static int probe_bfstm(AVProbeData *p) { - if (AV_RL32(p->buf) == MKTAG('F','S','T','M') && + if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') || + AV_RL32(p->buf) == MKTAG('C','S','T','M')) && (AV_RL16(p->buf + 4) == 0xFFFE || AV_RL16(p->buf + 4) == 0xFEFF)) return AVPROBE_SCORE_MAX / 3 * 2; @@ -63,16 +67,34 @@ static int read_close(AVFormatContext *s) return 0; } +static av_always_inline unsigned int read16(AVFormatContext *s) +{ + BRSTMDemuxContext *b = s->priv_data; + if (b->little_endian) + return avio_rl16(s->pb); + else + return avio_rb16(s->pb); +} + +static av_always_inline unsigned int read32(AVFormatContext *s) +{ + BRSTMDemuxContext *b = s->priv_data; + if (b->little_endian) + return avio_rl32(s->pb); + else + return avio_rb32(s->pb); +} + static int read_header(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; int bom, major, minor, codec, chunk; - int64_t h1offset, pos, toffset, data_offset = 0; - uint32_t size, start, asize; + int64_t h1offset, pos, toffset; + uint32_t size, asize, start = 0; AVStream *st; int ret = AVERROR_EOF; - - b->bfstm = !strcmp("bfstm", s->iformat->name); + int loop = 0; + int bfstm = !strcmp("bfstm", s->iformat->name); st = avformat_new_stream(s, NULL); if (!st) @@ -86,16 +108,15 @@ static int read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "invalid byte order: %X\n", bom); return AVERROR_INVALIDDATA; } - if (bom == 0xFFFE) { - avpriv_request_sample(s, "little endian byte order"); - return AVERROR_PATCHWELCOME; - } - if (!b->bfstm) { + if (bom == 0xFFFE) + b->little_endian = 1; + + if (!bfstm) { major = avio_r8(s->pb); minor = avio_r8(s->pb); avio_skip(s->pb, 4); // size of file - size = avio_rb16(s->pb); + size = read16(s); if (size < 14) return AVERROR_INVALIDDATA; @@ -104,59 +125,58 @@ static int read_header(AVFormatContext *s) if (avio_rl32(s->pb) != MKTAG('H','E','A','D')) return AVERROR_INVALIDDATA; } else { - uint32_t info_offset = 0, info_size; + uint32_t info_offset = 0; uint16_t section_count, header_size, i; - header_size = avio_rb16(s->pb); // 6 + header_size = read16(s); // 6 avio_skip(s->pb, 4); // Unknown constant 0x00030000 avio_skip(s->pb, 4); // size of file - section_count = avio_rb16(s->pb); + section_count = read16(s); avio_skip(s->pb, 2); // padding for (i = 0; avio_tell(s->pb) < header_size - && !(data_offset && info_offset) + && !(start && info_offset) && i < section_count; i++) { - uint32_t flag = avio_rb32(s->pb); + uint16_t flag = read16(s); + avio_skip(s->pb, 2); switch (flag) { - case 0x40000000: - info_offset = avio_rb32(s->pb); - info_size = avio_rb32(s->pb); + case 0x4000: + info_offset = read32(s); + /*info_size =*/ read32(s); break; - case 0x40010000: + case 0x4001: avio_skip(s->pb, 4); // seek offset avio_skip(s->pb, 4); // seek size break; - case 0x40020000: - data_offset = avio_rb32(s->pb); - avio_skip(s->pb, 4); //data_size = avio_rb32(s->pb); + case 0x4002: + start = read32(s) + 8; + avio_skip(s->pb, 4); //data_size = read32(s); break; - case 0x40030000: + case 0x4003: avio_skip(s->pb, 4); // REGN offset avio_skip(s->pb, 4); // REGN size break; } } - if (!info_offset || !data_offset) + if (!info_offset || !start) return AVERROR_INVALIDDATA; - start = data_offset + 8; - avio_skip(s->pb, info_offset - avio_tell(s->pb)); pos = avio_tell(s->pb); if (avio_rl32(s->pb) != MKTAG('I','N','F','O')) return AVERROR_INVALIDDATA; } - size = avio_rb32(s->pb); + size = read32(s); if (size < 192) return AVERROR_INVALIDDATA; avio_skip(s->pb, 4); // unknown - h1offset = avio_rb32(s->pb); + h1offset = read32(s); if (h1offset > size) return AVERROR_INVALIDDATA; avio_skip(s->pb, 12); - toffset = avio_rb32(s->pb) + 16LL; + toffset = read32(s) + 16LL; if (toffset > size) return AVERROR_INVALIDDATA; @@ -165,65 +185,77 @@ static int read_header(AVFormatContext *s) switch (codec) { case 0: codec = AV_CODEC_ID_PCM_S8_PLANAR; break; - case 1: codec = AV_CODEC_ID_PCM_S16BE_PLANAR; break; - case 2: codec = AV_CODEC_ID_ADPCM_THP; break; + case 1: codec = b->little_endian ? + AV_CODEC_ID_PCM_S16LE_PLANAR : + AV_CODEC_ID_PCM_S16BE_PLANAR; break; + case 2: codec = b->little_endian ? + AV_CODEC_ID_ADPCM_THP_LE : + AV_CODEC_ID_ADPCM_THP; break; default: avpriv_request_sample(s, "codec %d", codec); return AVERROR_PATCHWELCOME; } - avio_skip(s->pb, 1); // loop flag + loop = avio_r8(s->pb); // loop flag st->codec->codec_id = codec; st->codec->channels = avio_r8(s->pb); if (!st->codec->channels) return AVERROR_INVALIDDATA; avio_skip(s->pb, 1); // padding - if (b->bfstm) - avio_skip(s->pb, 2); // padding - st->codec->sample_rate = avio_rb16(s->pb); + st->codec->sample_rate = bfstm ? read32(s) : read16(s); if (!st->codec->sample_rate) return AVERROR_INVALIDDATA; - if (!b->bfstm) + if (!bfstm) avio_skip(s->pb, 2); // padding - avio_skip(s->pb, 4); // loop start sample + + if (loop) { + if (av_dict_set_int(&s->metadata, "loop_start", + av_rescale(read32(s), AV_TIME_BASE, + st->codec->sample_rate), + 0) < 0) + return AVERROR(ENOMEM); + } else { + avio_skip(s->pb, 4); + } + st->start_time = 0; - st->duration = avio_rb32(s->pb); + st->duration = read32(s); avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - if (!b->bfstm) - start = avio_rb32(s->pb); + if (!bfstm) + start = read32(s); b->current_block = 0; - b->block_count = avio_rb32(s->pb); + b->block_count = read32(s); if (b->block_count > UINT16_MAX) { av_log(s, AV_LOG_WARNING, "too many blocks: %u\n", b->block_count); return AVERROR_INVALIDDATA; } - b->block_size = avio_rb32(s->pb); - if (b->block_size > UINT16_MAX / st->codec->channels) + b->block_size = read32(s); + if (b->block_size > UINT32_MAX / st->codec->channels) return AVERROR_INVALIDDATA; - b->block_size *= st->codec->channels; - b->samples_per_block = avio_rb32(s->pb); - b->last_block_used_bytes = avio_rb32(s->pb); - if (b->last_block_used_bytes > UINT16_MAX / st->codec->channels) + b->samples_per_block = read32(s); + b->last_block_used_bytes = read32(s); + b->last_block_samples = read32(s); + b->last_block_size = read32(s); + if (b->last_block_size > UINT32_MAX / st->codec->channels) + return AVERROR_INVALIDDATA; + if (b->last_block_used_bytes > b->last_block_size) return AVERROR_INVALIDDATA; - b->last_block_used_bytes *= st->codec->channels; - avio_skip(s->pb, 4); // last block samples - avio_skip(s->pb, 4); // last block size - if (codec == AV_CODEC_ID_ADPCM_THP) { + if (codec == AV_CODEC_ID_ADPCM_THP || codec == AV_CODEC_ID_ADPCM_THP_LE) { int ch; avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); - if (!b->bfstm) - toffset = avio_rb32(s->pb) + 16LL; + if (!bfstm) + toffset = read32(s) + 16LL; else - toffset = toffset + avio_rb32(s->pb) + st->codec->channels * 8 - 8; + toffset = toffset + read32(s) + st->codec->channels * 8 - 8; if (toffset > size) return AVERROR_INVALIDDATA; @@ -237,15 +269,7 @@ static int read_header(AVFormatContext *s) ret = AVERROR_INVALIDDATA; goto fail; } - avio_skip(s->pb, b->bfstm ? 14 : 24); - } - - if (b->bfstm) { - st->codec->extradata_size = 32 * st->codec->channels; - st->codec->extradata = av_malloc(st->codec->extradata_size); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - memcpy(st->codec->extradata, b->table, st->codec->extradata_size); + avio_skip(s->pb, bfstm ? 14 : 24); } } @@ -254,22 +278,21 @@ static int read_header(AVFormatContext *s) goto fail; } - if (!b->bfstm) - avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); - else - avio_skip(s->pb, data_offset - avio_tell(s->pb)); + avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); while (!avio_feof(s->pb)) { chunk = avio_rl32(s->pb); - size = avio_rb32(s->pb); + size = read32(s); if (size < 8) { ret = AVERROR_INVALIDDATA; goto fail; } size -= 8; switch (chunk) { + case MKTAG('S','E','E','K'): case MKTAG('A','D','P','C'): - if (codec != AV_CODEC_ID_ADPCM_THP) + if (codec != AV_CODEC_ID_ADPCM_THP && + codec != AV_CODEC_ID_ADPCM_THP_LE) goto skip; asize = b->block_count * st->codec->channels * 4; @@ -286,19 +309,36 @@ static int read_header(AVFormatContext *s) ret = AVERROR(ENOMEM); goto fail; } - avio_read(s->pb, b->adpc, asize); + if (bfstm && codec != AV_CODEC_ID_ADPCM_THP_LE) { + // Big-endian BFSTMs have little-endian SEEK tables + // for some strange reason. + int i; + for (i = 0; i < asize; i += 2) { + b->adpc[i+1] = avio_r8(s->pb); + b->adpc[i] = avio_r8(s->pb); + } + } else { + avio_read(s->pb, b->adpc, asize); + } avio_skip(s->pb, size - asize); } break; case MKTAG('D','A','T','A'): if ((start < avio_tell(s->pb)) || - (!b->adpc && codec == AV_CODEC_ID_ADPCM_THP && !b->bfstm)) { + (!b->adpc && (codec == AV_CODEC_ID_ADPCM_THP || + codec == AV_CODEC_ID_ADPCM_THP_LE))) { ret = AVERROR_INVALIDDATA; goto fail; } avio_skip(s->pb, start - avio_tell(s->pb)); - if ((major != 1 || minor) && !b->bfstm) + if (bfstm && (codec == AV_CODEC_ID_ADPCM_THP || + codec == AV_CODEC_ID_ADPCM_THP_LE)) + avio_skip(s->pb, 24); + + b->data_start = avio_tell(s->pb); + + if (!bfstm && (major != 1 || minor)) avpriv_request_sample(s, "Version %d.%d", major, minor); return 0; @@ -319,15 +359,25 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) { AVCodecContext *codec = s->streams[0]->codec; BRSTMDemuxContext *b = s->priv_data; - uint32_t samples, size; - int ret; + uint32_t samples, size, skip = 0; + int ret, i; if (avio_feof(s->pb)) return AVERROR_EOF; b->current_block++; if (b->current_block == b->block_count) { size = b->last_block_used_bytes; - samples = size / (8 * codec->channels) * 14; + samples = b->last_block_samples; + skip = b->last_block_size - b->last_block_used_bytes; + + if (samples < size * 14 / 8) { + uint32_t adjusted_size = samples / 14 * 8; + if (samples % 14) + adjusted_size += (samples % 14 + 1) / 2 + 1; + + skip += size - adjusted_size; + size = adjusted_size; + } } else if (b->current_block < b->block_count) { size = b->block_size; samples = b->samples_per_block; @@ -335,23 +385,36 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; } - if (codec->codec_id == AV_CODEC_ID_ADPCM_THP && !codec->extradata) { + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP || + codec->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { uint8_t *dst; - if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0) + if (av_new_packet(pkt, 8 + (32 + 4 + size) * codec->channels) < 0) return AVERROR(ENOMEM); dst = pkt->data; - bytestream_put_be32(&dst, size); - bytestream_put_be32(&dst, samples); + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { + bytestream_put_le32(&dst, size * codec->channels); + bytestream_put_le32(&dst, samples); + } else { + bytestream_put_be32(&dst, size * codec->channels); + bytestream_put_be32(&dst, samples); + } bytestream_put_buffer(&dst, b->table, 32 * codec->channels); bytestream_put_buffer(&dst, b->adpc + 4 * codec->channels * (b->current_block - 1), 4 * codec->channels); - ret = avio_read(s->pb, dst, size); - if (ret != size) - av_free_packet(pkt); + for (i = 0; i < codec->channels; i++) { + ret = avio_read(s->pb, dst, size); + dst += size; + avio_skip(s->pb, skip); + if (ret != size) { + av_free_packet(pkt); + break; + } + } pkt->duration = samples; } else { + size *= codec->channels; ret = av_get_packet(s->pb, pkt, size); } @@ -363,6 +426,24 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } +static int read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) +{ + AVStream *st = s->streams[stream_index]; + BRSTMDemuxContext *b = s->priv_data; + int64_t ret = 0; + + timestamp /= b->samples_per_block; + ret = avio_seek(s->pb, b->data_start + timestamp * b->block_size * + st->codec->channels, SEEK_SET); + if (ret < 0) + return ret; + + b->current_block = timestamp; + ff_update_cur_dts(s, st, timestamp * b->samples_per_block); + return 0; +} + AVInputFormat ff_brstm_demuxer = { .name = "brstm", .long_name = NULL_IF_CONFIG_SMALL("BRSTM (Binary Revolution Stream)"), @@ -371,6 +452,7 @@ AVInputFormat ff_brstm_demuxer = { .read_header = read_header, .read_packet = read_packet, .read_close = read_close, + .read_seek = read_seek, .extensions = "brstm", }; @@ -382,5 +464,6 @@ AVInputFormat ff_bfstm_demuxer = { .read_header = read_header, .read_packet = read_packet, .read_close = read_close, - .extensions = "bfstm", + .read_seek = read_seek, + .extensions = "bfstm,bcstm", }; diff --git a/chromium/third_party/ffmpeg/libavformat/caf.c b/chromium/third_party/ffmpeg/libavformat/caf.c index c1ecc94425e..00854615ca3 100644 --- a/chromium/third_party/ffmpeg/libavformat/caf.c +++ b/chromium/third_party/ffmpeg/libavformat/caf.c @@ -61,6 +61,18 @@ const AVCodecTag ff_codec_caf_tags[] = { /*{ MPEG4CELP MKTAG('c','e','l','p') },*/ /*{ MPEG4HVXC MKTAG('h','v','x','c') },*/ /*{ MPEG4TwinVQ MKTAG('t','w','v','q') },*/ + + { AV_CODEC_ID_PCM_S8, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S16LE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S16BE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S24LE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S24BE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S32LE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_S32BE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_F32LE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_F32BE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_F64LE, MKTAG('l','p','c','m') }, + { AV_CODEC_ID_PCM_F64BE, MKTAG('l','p','c','m') }, { AV_CODEC_ID_NONE, 0 }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/cafdec.c b/chromium/third_party/ffmpeg/libavformat/cafdec.c index cc6ed0ce9f6..bfbbb02627a 100644 --- a/chromium/third_party/ffmpeg/libavformat/cafdec.c +++ b/chromium/third_party/ffmpeg/libavformat/cafdec.c @@ -101,7 +101,7 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size) AVIOContext *pb = s->pb; AVStream *st = s->streams[0]; - if (size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) + if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) return -1; if (st->codec->codec_id == AV_CODEC_ID_AAC) { diff --git a/chromium/third_party/ffmpeg/libavformat/cafenc.c b/chromium/third_party/ffmpeg/libavformat/cafenc.c index 1708275e11f..544bc4a114f 100644 --- a/chromium/third_party/ffmpeg/libavformat/cafenc.c +++ b/chromium/third_party/ffmpeg/libavformat/cafenc.c @@ -120,21 +120,6 @@ static int caf_write_header(AVFormatContext *s) return AVERROR_PATCHWELCOME; } - switch (enc->codec_id) { - case AV_CODEC_ID_PCM_S8: - case AV_CODEC_ID_PCM_S16LE: - case AV_CODEC_ID_PCM_S16BE: - case AV_CODEC_ID_PCM_S24LE: - case AV_CODEC_ID_PCM_S24BE: - case AV_CODEC_ID_PCM_S32LE: - case AV_CODEC_ID_PCM_S32BE: - case AV_CODEC_ID_PCM_F32LE: - case AV_CODEC_ID_PCM_F32BE: - case AV_CODEC_ID_PCM_F64LE: - case AV_CODEC_ID_PCM_F64BE: - codec_tag = MKTAG('l','p','c','m'); - } - if (!codec_tag) { av_log(s, AV_LOG_ERROR, "unsupported codec\n"); return AVERROR_INVALIDDATA; diff --git a/chromium/third_party/ffmpeg/libavformat/concatdec.c b/chromium/third_party/ffmpeg/libavformat/concatdec.c index 07db9f96a39..88b6dbe6a44 100644 --- a/chromium/third_party/ffmpeg/libavformat/concatdec.c +++ b/chromium/third_party/ffmpeg/libavformat/concatdec.c @@ -41,8 +41,13 @@ typedef struct ConcatStream { typedef struct { char *url; int64_t start_time; + int64_t file_start_time; + int64_t file_inpoint; int64_t duration; ConcatStream *streams; + int64_t inpoint; + int64_t outpoint; + AVDictionary *metadata; int nb_streams; } ConcatFile; @@ -54,6 +59,7 @@ typedef struct { AVFormatContext *avf; int safe; int seekable; + int eof; ConcatMatchMode stream_match_mode; unsigned auto_convert; } ConcatContext; @@ -142,6 +148,8 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, file->url = url; file->start_time = AV_NOPTS_VALUE; file->duration = AV_NOPTS_VALUE; + file->inpoint = AV_NOPTS_VALUE; + file->outpoint = AV_NOPTS_VALUE; return 0; @@ -172,6 +180,8 @@ static int copy_stream_props(AVStream *st, AVStream *source_st) st->avg_frame_rate = source_st->avg_frame_rate; st->time_base = source_st->time_base; st->sample_aspect_ratio = source_st->sample_aspect_ratio; + + av_dict_copy(&st->metadata, source_st->metadata, 0); return 0; } @@ -304,8 +314,14 @@ static int open_file(AVFormatContext *avf, unsigned fileno) file->start_time = !fileno ? 0 : cat->files[fileno - 1].start_time + cat->files[fileno - 1].duration; + file->file_start_time = (avf->start_time == AV_NOPTS_VALUE) ? 0 : avf->start_time; + file->file_inpoint = (file->inpoint == AV_NOPTS_VALUE) ? file->file_start_time : file->inpoint; if ((ret = match_streams(avf)) < 0) return ret; + if (file->inpoint != AV_NOPTS_VALUE) { + if ((ret = avformat_seek_file(cat->avf, -1, INT64_MIN, file->inpoint, file->inpoint, 0)) < 0) + return ret; + } return 0; } @@ -319,6 +335,7 @@ static int concat_read_close(AVFormatContext *avf) for (i = 0; i < cat->nb_files; i++) { av_freep(&cat->files[i].url); av_freep(&cat->files[i].streams); + av_dict_free(&cat->files[i].metadata); } av_freep(&cat->files); return 0; @@ -351,20 +368,43 @@ static int concat_read_header(AVFormatContext *avf) } if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0) goto fail; - } else if (!strcmp(keyword, "duration")) { + } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "inpoint") || !strcmp(keyword, "outpoint")) { char *dur_str = get_keyword(&cursor); int64_t dur; if (!file) { - av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n", - line); + av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n", + line, keyword); FAIL(AVERROR_INVALIDDATA); } if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) { - av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n", - line, dur_str); + av_log(avf, AV_LOG_ERROR, "Line %d: invalid %s '%s'\n", + line, keyword, dur_str); goto fail; } - file->duration = dur; + if (!strcmp(keyword, "duration")) + file->duration = dur; + else if (!strcmp(keyword, "inpoint")) + file->inpoint = dur; + else if (!strcmp(keyword, "outpoint")) + file->outpoint = dur; + } else if (!strcmp(keyword, "file_packet_metadata")) { + char *metadata; + metadata = av_get_token((const char **)&cursor, SPACE_CHARS); + if (!metadata) { + av_log(avf, AV_LOG_ERROR, "Line %d: packet metadata required\n", line); + FAIL(AVERROR_INVALIDDATA); + } + if (!file) { + av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n", + line, keyword); + FAIL(AVERROR_INVALIDDATA); + } + if ((ret = av_dict_parse_string(&file->metadata, metadata, "=", "", 0)) < 0) { + av_log(avf, AV_LOG_ERROR, "Line %d: failed to parse metadata string\n", line); + av_freep(&metadata); + FAIL(AVERROR_INVALIDDATA); + } + av_freep(&metadata); } else if (!strcmp(keyword, "stream")) { if (!avformat_new_stream(avf, NULL)) FAIL(AVERROR(ENOMEM)); @@ -401,8 +441,11 @@ static int concat_read_header(AVFormatContext *avf) cat->files[i].start_time = time; else time = cat->files[i].start_time; - if (cat->files[i].duration == AV_NOPTS_VALUE) - break; + if (cat->files[i].duration == AV_NOPTS_VALUE) { + if (cat->files[i].inpoint == AV_NOPTS_VALUE || cat->files[i].outpoint == AV_NOPTS_VALUE) + break; + cat->files[i].duration = cat->files[i].outpoint - cat->files[i].inpoint; + } time += cat->files[i].duration; } if (i == cat->nb_files) { @@ -426,11 +469,18 @@ static int open_next_file(AVFormatContext *avf) ConcatContext *cat = avf->priv_data; unsigned fileno = cat->cur_file - cat->files; - if (cat->cur_file->duration == AV_NOPTS_VALUE) + if (cat->cur_file->duration == AV_NOPTS_VALUE) { cat->cur_file->duration = cat->avf->duration; + if (cat->cur_file->inpoint != AV_NOPTS_VALUE) + cat->cur_file->duration -= (cat->cur_file->inpoint - cat->cur_file->file_start_time); + if (cat->cur_file->outpoint != AV_NOPTS_VALUE) + cat->cur_file->duration -= cat->avf->duration - (cat->cur_file->outpoint - cat->cur_file->file_start_time); + } - if (++fileno >= cat->nb_files) + if (++fileno >= cat->nb_files) { + cat->eof = 1; return AVERROR_EOF; + } return open_file(avf, fileno); } @@ -474,20 +524,35 @@ static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt) return 0; } +/* Returns true if the packet dts is greater or equal to the specified outpoint. */ +static int packet_after_outpoint(ConcatContext *cat, AVPacket *pkt) +{ + if (cat->cur_file->outpoint != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE) { + return av_compare_ts(pkt->dts, cat->avf->streams[pkt->stream_index]->time_base, + cat->cur_file->outpoint, AV_TIME_BASE_Q) >= 0; + } + return 0; +} + static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) { ConcatContext *cat = avf->priv_data; int ret; - int64_t file_start_time, delta; + int64_t delta; ConcatStream *cs; AVStream *st; + if (cat->eof) + return AVERROR_EOF; + if (!cat->avf) return AVERROR(EIO); while (1) { ret = av_read_frame(cat->avf, pkt); - if (ret == AVERROR_EOF) { + if (ret == AVERROR_EOF || packet_after_outpoint(cat, pkt)) { + if (ret == 0) + av_packet_unref(pkt); if ((ret = open_next_file(avf)) < 0) return ret; continue; @@ -515,10 +580,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - file_start_time = cat->avf->start_time; - if (file_start_time == AV_NOPTS_VALUE) - file_start_time = 0; - delta = av_rescale_q(cat->cur_file->start_time - file_start_time, + delta = av_rescale_q(cat->cur_file->start_time - cat->cur_file->file_inpoint, AV_TIME_BASE_Q, cat->avf->streams[pkt->stream_index]->time_base); if (pkt->pts != AV_NOPTS_VALUE) @@ -528,6 +590,19 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) av_log(avf, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n", av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); + if (cat->cur_file->metadata) { + uint8_t* metadata; + int metadata_len; + char* packed_metadata = av_packet_pack_dictionary(cat->cur_file->metadata, &metadata_len); + if (!packed_metadata) + return AVERROR(ENOMEM); + if (!(metadata = av_packet_new_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, metadata_len))) { + av_freep(&packed_metadata); + return AVERROR(ENOMEM); + } + memcpy(metadata, packed_metadata, metadata_len); + av_freep(&packed_metadata); + } return ret; } @@ -545,7 +620,7 @@ static int try_seek(AVFormatContext *avf, int stream, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) { ConcatContext *cat = avf->priv_data; - int64_t t0 = cat->cur_file->start_time - cat->avf->start_time; + int64_t t0 = cat->cur_file->start_time - cat->cur_file->file_inpoint; ts -= t0; min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0; @@ -616,6 +691,7 @@ static int concat_seek(AVFormatContext *avf, int stream, cat->cur_file = cur_file_saved; } else { avformat_close_input(&cur_avf_saved); + cat->eof = 0; } return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/dnxhddec.c b/chromium/third_party/ffmpeg/libavformat/dnxhddec.c index 910e6b6684e..37e52d54c27 100644 --- a/chromium/third_party/ffmpeg/libavformat/dnxhddec.c +++ b/chromium/third_party/ffmpeg/libavformat/dnxhddec.c @@ -37,7 +37,7 @@ static int dnxhd_probe(AVProbeData *p) if (!w || !h) return 0; compression_id = AV_RB32(p->buf + 0x28); - if (compression_id < 1235 || compression_id > 1258) + if (compression_id < 1235 || compression_id > 1260) return 0; return AVPROBE_SCORE_MAX; } diff --git a/chromium/third_party/ffmpeg/libavformat/dtsdec.c b/chromium/third_party/ffmpeg/libavformat/dtsdec.c index da0fb61a60a..ef283916e79 100644 --- a/chromium/third_party/ffmpeg/libavformat/dtsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/dtsdec.c @@ -34,7 +34,7 @@ static int dts_probe(AVProbeData *p) int markers[4*16] = {0}; int sum, max, i; int64_t diff = 0; - uint8_t hdr[12 + FF_INPUT_BUFFER_PADDING_SIZE] = { 0 }; + uint8_t hdr[12 + AV_INPUT_BUFFER_PADDING_SIZE] = { 0 }; buf = p->buf + FFMIN(4096, p->buf_size); diff --git a/chromium/third_party/ffmpeg/libavformat/dump.c b/chromium/third_party/ffmpeg/libavformat/dump.c index 6355b99f416..705da821489 100644 --- a/chromium/third_party/ffmpeg/libavformat/dump.c +++ b/chromium/third_party/ffmpeg/libavformat/dump.c @@ -377,6 +377,9 @@ static void dump_sidedata(void *ctx, AVStream *st, const char *indent) av_log(ctx, AV_LOG_INFO, "audio service type: "); dump_audioservicetype(ctx, &sd); break; + case AV_PKT_DATA_QUALITY_STATS: + av_log(ctx, AV_LOG_INFO, "quality factor: %d, pict_type: %c", AV_RL32(sd.data), av_get_picture_type_char(sd.data[4])); + break; default: av_log(ctx, AV_LOG_WARNING, "unknown side data type %d (%d bytes)", sd.type, sd.size); @@ -420,8 +423,8 @@ static void dump_stream_format(AVFormatContext *ic, int i, av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) { AVRational display_aspect_ratio; av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, - st->codec->width * st->sample_aspect_ratio.num, - st->codec->height * st->sample_aspect_ratio.den, + st->codec->width * (int64_t)st->sample_aspect_ratio.num, + st->codec->height * (int64_t)st->sample_aspect_ratio.den, 1024 * 1024); av_log(NULL, AV_LOG_INFO, ", SAR %d:%d DAR %d:%d", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, @@ -509,7 +512,7 @@ void av_dump_format(AVFormatContext *ic, int index, int secs, us; av_log(NULL, AV_LOG_INFO, ", start: "); secs = ic->start_time / AV_TIME_BASE; - us = abs(ic->start_time % AV_TIME_BASE); + us = llabs(ic->start_time % AV_TIME_BASE); av_log(NULL, AV_LOG_INFO, "%d.%06d", secs, (int) av_rescale(us, 1000000, AV_TIME_BASE)); } diff --git a/chromium/third_party/ffmpeg/libavformat/dv.c b/chromium/third_party/ffmpeg/libavformat/dv.c index 85002289640..84c306114b6 100644 --- a/chromium/third_party/ffmpeg/libavformat/dv.c +++ b/chromium/third_party/ffmpeg/libavformat/dv.c @@ -553,12 +553,17 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) size = avpriv_dv_get_packet(c->dv_demux, pkt); if (size < 0) { + int ret; int64_t pos = avio_tell(s->pb); if (!c->dv_demux->sys) return AVERROR(EIO); size = c->dv_demux->sys->frame_size; - if (avio_read(s->pb, c->buf, size) <= 0) + ret = avio_read(s->pb, c->buf, size); + if (ret < 0) { + return ret; + } else if (ret == 0) { return AVERROR(EIO); + } size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size, pos); } diff --git a/chromium/third_party/ffmpeg/libavformat/dxa.c b/chromium/third_party/ffmpeg/libavformat/dxa.c index 44033563f8a..228e6fdca1a 100644 --- a/chromium/third_party/ffmpeg/libavformat/dxa.c +++ b/chromium/third_party/ffmpeg/libavformat/dxa.c @@ -106,7 +106,7 @@ static int dxa_read_header(AVFormatContext *s) ast = avformat_new_stream(s, NULL); if (!ast) return AVERROR(ENOMEM); - ret = ff_get_wav_header(pb, ast->codec, fsize, 0); + ret = ff_get_wav_header(s, pb, ast->codec, fsize, 0); if (ret < 0) return ret; if (ast->codec->sample_rate > 0) diff --git a/chromium/third_party/ffmpeg/libavformat/electronicarts.c b/chromium/third_party/ffmpeg/libavformat/electronicarts.c index d6a396b1ef5..5d21d49c455 100644 --- a/chromium/third_party/ffmpeg/libavformat/electronicarts.c +++ b/chromium/third_party/ffmpeg/libavformat/electronicarts.c @@ -59,17 +59,25 @@ #define MVhd_TAG MKTAG('M', 'V', 'h', 'd') #define MV0K_TAG MKTAG('M', 'V', '0', 'K') #define MV0F_TAG MKTAG('M', 'V', '0', 'F') +#define AVhd_TAG MKTAG('A', 'V', 'h', 'd') +#define AV0K_TAG MKTAG('A', 'V', '0', 'K') +#define AV0F_TAG MKTAG('A', 'V', '0', 'F') #define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */ #define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV I-frame */ +#define AVP6_TAG MKTAG('A', 'V', 'P', '6') -typedef struct EaDemuxContext { - int big_endian; - - enum AVCodecID video_codec; +typedef struct VideoProperties { + enum AVCodecID codec; AVRational time_base; int width, height; int nb_frames; - int video_stream_index; + int stream_index; +} VideoProperties; + +typedef struct EaDemuxContext { + int big_endian; + + VideoProperties video, alpha; enum AVCodecID audio_codec; int audio_stream_index; @@ -301,46 +309,43 @@ static void process_audio_header_sead(AVFormatContext *s) ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_SEAD; } -static void process_video_header_mdec(AVFormatContext *s) +static void process_video_header_mdec(AVFormatContext *s, VideoProperties *video) { - EaDemuxContext *ea = s->priv_data; AVIOContext *pb = s->pb; avio_skip(pb, 4); - ea->width = avio_rl16(pb); - ea->height = avio_rl16(pb); - ea->time_base = (AVRational) { 1, 15 }; - ea->video_codec = AV_CODEC_ID_MDEC; + video->width = avio_rl16(pb); + video->height = avio_rl16(pb); + video->time_base = (AVRational) { 1, 15 }; + video->codec = AV_CODEC_ID_MDEC; } -static int process_video_header_vp6(AVFormatContext *s) +static int process_video_header_vp6(AVFormatContext *s, VideoProperties *video) { - EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; avio_skip(pb, 8); - ea->nb_frames = avio_rl32(pb); + video->nb_frames = avio_rl32(pb); avio_skip(pb, 4); - ea->time_base.den = avio_rl32(pb); - ea->time_base.num = avio_rl32(pb); - if (ea->time_base.den <= 0 || ea->time_base.num <= 0) { + video->time_base.den = avio_rl32(pb); + video->time_base.num = avio_rl32(pb); + if (video->time_base.den <= 0 || video->time_base.num <= 0) { av_log(s, AV_LOG_ERROR, "Timebase is invalid\n"); return AVERROR_INVALIDDATA; } - ea->video_codec = AV_CODEC_ID_VP6; + video->codec = AV_CODEC_ID_VP6; return 1; } -static void process_video_header_cmv(AVFormatContext *s) +static void process_video_header_cmv(AVFormatContext *s, VideoProperties *video) { - EaDemuxContext *ea = s->priv_data; int fps; avio_skip(s->pb, 10); fps = avio_rl16(s->pb); if (fps) - ea->time_base = (AVRational) { 1, fps }; - ea->video_codec = AV_CODEC_ID_CMV; + video->time_base = (AVRational) { 1, fps }; + video->codec = AV_CODEC_ID_CMV; } /* Process EA file header. @@ -352,7 +357,7 @@ static int process_ea_header(AVFormatContext *s) AVIOContext *pb = s->pb; int i; - for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) { + for (i = 0; i < 5 && (!ea->audio_codec || !ea->video.codec); i++) { uint64_t startpos = avio_tell(pb); int err = 0; @@ -394,40 +399,44 @@ static int process_ea_header(AVFormatContext *s) break; case MVIh_TAG: - process_video_header_cmv(s); + process_video_header_cmv(s, &ea->video); break; case kVGT_TAG: - ea->video_codec = AV_CODEC_ID_TGV; + ea->video.codec = AV_CODEC_ID_TGV; break; case mTCD_TAG: - process_video_header_mdec(s); + process_video_header_mdec(s, &ea->video); break; case MPCh_TAG: - ea->video_codec = AV_CODEC_ID_MPEG2VIDEO; + ea->video.codec = AV_CODEC_ID_MPEG2VIDEO; break; case pQGT_TAG: case TGQs_TAG: - ea->video_codec = AV_CODEC_ID_TGQ; - ea->time_base = (AVRational) { 1, 15 }; + ea->video.codec = AV_CODEC_ID_TGQ; + ea->video.time_base = (AVRational) { 1, 15 }; break; case pIQT_TAG: - ea->video_codec = AV_CODEC_ID_TQI; - ea->time_base = (AVRational) { 1, 15 }; + ea->video.codec = AV_CODEC_ID_TQI; + ea->video.time_base = (AVRational) { 1, 15 }; break; case MADk_TAG: - ea->video_codec = AV_CODEC_ID_MAD; + ea->video.codec = AV_CODEC_ID_MAD; avio_skip(pb, 6); - ea->time_base = (AVRational) { avio_rl16(pb), 1000 }; + ea->video.time_base = (AVRational) { avio_rl16(pb), 1000 }; break; case MVhd_TAG: - err = process_video_header_vp6(s); + err = process_video_header_vp6(s, &ea->video); + break; + + case AVhd_TAG: + err = process_video_header_vp6(s, &ea->alpha); break; } @@ -458,6 +467,7 @@ static int ea_probe(AVProbeData *p) case MPCh_TAG: case MVhd_TAG: case MVIh_TAG: + case AVP6_TAG: break; default: return 0; @@ -472,6 +482,34 @@ static int ea_probe(AVProbeData *p) return AVPROBE_SCORE_MAX; } +static int init_video_stream(AVFormatContext *s, VideoProperties *video) +{ + AVStream *st; + + if (!video->codec) + return 0; + + /* initialize the video decoder stream */ + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + video->stream_index = st->index; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = video->codec; + // parsing is necessary to make FFmpeg generate correct timestamps + if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) + st->need_parsing = AVSTREAM_PARSE_HEADERS; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->width = video->width; + st->codec->height = video->height; + st->duration = st->nb_frames = video->nb_frames; + if (video->time_base.num) + avpriv_set_pts_info(st, 64, video->time_base.num, video->time_base.den); + st->r_frame_rate = + st->avg_frame_rate = av_inv_q(video->time_base); + return 0; +} + static int ea_read_header(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; @@ -480,26 +518,8 @@ static int ea_read_header(AVFormatContext *s) if (process_ea_header(s)<=0) return AVERROR(EIO); - if (ea->video_codec) { - /* initialize the video decoder stream */ - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - ea->video_stream_index = st->index; - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = ea->video_codec; - // parsing is necessary to make FFmpeg generate correct timestamps - if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) - st->need_parsing = AVSTREAM_PARSE_HEADERS; - st->codec->codec_tag = 0; /* no fourcc */ - st->codec->width = ea->width; - st->codec->height = ea->height; - st->duration = st->nb_frames = ea->nb_frames; - if (ea->time_base.num) - avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den); - st->r_frame_rate = - st->avg_frame_rate = av_inv_q(ea->time_base); - } + if (init_video_stream(s, &ea->video) || init_video_stream(s, &ea->alpha)) + return AVERROR(ENOMEM); if (ea->audio_codec) { if (ea->num_channels <= 0 || ea->num_channels > 2) { @@ -659,10 +679,12 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt) goto get_video_packet; case MV0K_TAG: + case AV0K_TAG: case MPCh_TAG: case pIQT_TAG: key = AV_PKT_FLAG_KEY; case MV0F_TAG: + case AV0F_TAG: get_video_packet: if (!chunk_size) continue; @@ -676,7 +698,10 @@ get_video_packet: break; } partial_packet = chunk_type == MVIh_TAG; - pkt->stream_index = ea->video_stream_index; + if (chunk_type == AV0K_TAG || chunk_type == AV0F_TAG) + pkt->stream_index = ea->alpha.stream_index; + else + pkt->stream_index = ea->video.stream_index; pkt->flags |= key; packet_read = 1; break; diff --git a/chromium/third_party/ffmpeg/libavformat/ffmdec.c b/chromium/third_party/ffmpeg/libavformat/ffmdec.c index 9b50c9f5a6f..110d31540f1 100644 --- a/chromium/third_party/ffmpeg/libavformat/ffmdec.c +++ b/chromium/third_party/ffmpeg/libavformat/ffmdec.c @@ -21,6 +21,7 @@ #include <stdint.h> +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/opt.h" @@ -160,7 +161,7 @@ static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); pos = FFMAX(pos, FFM_PACKET_SIZE); - av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); + ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); return avio_seek(pb, pos, SEEK_SET); } @@ -172,7 +173,7 @@ static int64_t get_dts(AVFormatContext *s, int64_t pos) ffm_seek1(s, pos); avio_skip(pb, 4); dts = avio_rb64(pb); - av_dlog(s, "dts=%0.6f\n", dts / 1000000.0); + ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0); return dts; } @@ -326,7 +327,7 @@ static int ffm2_read_header(AVFormatContext *s) codec->flags = avio_rb32(pb); codec->flags2 = avio_rb32(pb); codec->debug = avio_rb32(pb); - if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { + if (codec->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); } @@ -573,7 +574,7 @@ static int ffm_read_header(AVFormatContext *s) default: goto fail; } - if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { + if (codec->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); } @@ -608,7 +609,7 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0) return ret; - av_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", + ff_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size); if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != FRAME_HEADER_SIZE) @@ -666,7 +667,7 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in int64_t pts_min, pts_max, pts; double pos1; - av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); + ff_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); /* find the position using linear interpolation (better than dichotomy in typical cases) */ if (ffm->write_index && ffm->write_index < ffm->file_size) { diff --git a/chromium/third_party/ffmpeg/libavformat/ffmenc.c b/chromium/third_party/ffmpeg/libavformat/ffmenc.c index 3abbfdd08f4..f0b5743ea46 100644 --- a/chromium/third_party/ffmpeg/libavformat/ffmenc.c +++ b/chromium/third_party/ffmpeg/libavformat/ffmenc.c @@ -268,7 +268,7 @@ static int ffm_write_header(AVFormatContext *s) avio_wb32(pb, codec->flags); avio_wb32(pb, codec->flags2); avio_wb32(pb, codec->debug); - if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { + if (codec->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { avio_wb32(pb, codec->extradata_size); avio_write(pb, codec->extradata, codec->extradata_size); } diff --git a/chromium/third_party/ffmpeg/libavformat/file.c b/chromium/third_party/ffmpeg/libavformat/file.c index 6511328de7d..d59aa42b50b 100644 --- a/chromium/third_party/ffmpeg/libavformat/file.c +++ b/chromium/third_party/ffmpeg/libavformat/file.c @@ -23,6 +23,9 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "avformat.h" +#if HAVE_DIRENT_H +#include <dirent.h> +#endif #include <fcntl.h> #if HAVE_IO_H #include <io.h> @@ -44,6 +47,24 @@ # endif #endif +/* Not available in POSIX.1-1996 */ +#ifndef S_ISLNK +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK) +# else +# define S_ISLNK(m) 0 +# endif +#endif + +/* Not available in POSIX.1-1996 */ +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) 0 +# endif +#endif + /* standard file protocol */ typedef struct FileContext { @@ -51,6 +72,9 @@ typedef struct FileContext { int fd; int trunc; int blocksize; +#if HAVE_DIRENT_H + DIR *dir; +#endif } FileContext; static const AVOption file_options[] = { @@ -81,19 +105,19 @@ static const AVClass pipe_class = { static int file_read(URLContext *h, unsigned char *buf, int size) { FileContext *c = h->priv_data; - int r; + int ret; size = FFMIN(size, c->blocksize); - r = read(c->fd, buf, size); - return (-1 == r)?AVERROR(errno):r; + ret = read(c->fd, buf, size); + return (ret == -1) ? AVERROR(errno) : ret; } static int file_write(URLContext *h, const unsigned char *buf, int size) { FileContext *c = h->priv_data; - int r; + int ret; size = FFMIN(size, c->blocksize); - r = write(c->fd, buf, size); - return (-1 == r)?AVERROR(errno):r; + ret = write(c->fd, buf, size); + return (ret == -1) ? AVERROR(errno) : ret; } static int file_get_handle(URLContext *h) @@ -131,6 +155,42 @@ static int file_check(URLContext *h, int mask) return ret; } +static int file_delete(URLContext *h) +{ +#if HAVE_UNISTD_H + int ret; + const char *filename = h->filename; + av_strstart(filename, "file:", &filename); + + ret = rmdir(filename); + if (ret < 0 && errno == ENOTDIR) + ret = unlink(filename); + if (ret < 0) + return AVERROR(errno); + + return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_UNISTD_H */ +} + +static int file_move(URLContext *h_src, URLContext *h_dst) +{ +#if HAVE_UNISTD_H + const char *filename_src = h_src->filename; + const char *filename_dst = h_dst->filename; + av_strstart(filename_src, "file:", &filename_src); + av_strstart(filename_dst, "file:", &filename_dst); + + if (rename(filename_src, filename_dst) < 0) + return AVERROR(errno); + + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_UNISTD_H */ +} + #if CONFIG_FILE_PROTOCOL static int file_open(URLContext *h, const char *filename, int flags) @@ -189,6 +249,90 @@ static int file_close(URLContext *h) return close(c->fd); } +static int file_open_dir(URLContext *h) +{ +#if HAVE_LSTAT + FileContext *c = h->priv_data; + + c->dir = opendir(h->filename); + if (!c->dir) + return AVERROR(errno); + + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + +static int file_read_dir(URLContext *h, AVIODirEntry **next) +{ +#if HAVE_LSTAT + FileContext *c = h->priv_data; + struct dirent *dir; + char *fullpath = NULL; + + *next = ff_alloc_dir_entry(); + if (!*next) + return AVERROR(ENOMEM); + do { + errno = 0; + dir = readdir(c->dir); + if (!dir) { + av_freep(next); + return AVERROR(errno); + } + } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")); + + fullpath = av_append_path_component(h->filename, dir->d_name); + if (fullpath) { + struct stat st; + if (!lstat(fullpath, &st)) { + if (S_ISDIR(st.st_mode)) + (*next)->type = AVIO_ENTRY_DIRECTORY; + else if (S_ISFIFO(st.st_mode)) + (*next)->type = AVIO_ENTRY_NAMED_PIPE; + else if (S_ISCHR(st.st_mode)) + (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE; + else if (S_ISBLK(st.st_mode)) + (*next)->type = AVIO_ENTRY_BLOCK_DEVICE; + else if (S_ISLNK(st.st_mode)) + (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK; + else if (S_ISSOCK(st.st_mode)) + (*next)->type = AVIO_ENTRY_SOCKET; + else if (S_ISREG(st.st_mode)) + (*next)->type = AVIO_ENTRY_FILE; + else + (*next)->type = AVIO_ENTRY_UNKNOWN; + + (*next)->group_id = st.st_gid; + (*next)->user_id = st.st_uid; + (*next)->size = st.st_size; + (*next)->filemode = st.st_mode & 0777; + (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime; + (*next)->access_timestamp = INT64_C(1000000) * st.st_atime; + (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime; + } + av_free(fullpath); + } + + (*next)->name = av_strdup(dir->d_name); + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + +static int file_close_dir(URLContext *h) +{ +#if HAVE_LSTAT + FileContext *c = h->priv_data; + closedir(c->dir); + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + URLProtocol ff_file_protocol = { .name = "file", .url_open = file_open, @@ -198,8 +342,13 @@ URLProtocol ff_file_protocol = { .url_close = file_close, .url_get_file_handle = file_get_handle, .url_check = file_check, + .url_delete = file_delete, + .url_move = file_move, .priv_data_size = sizeof(FileContext), .priv_data_class = &file_class, + .url_open_dir = file_open_dir, + .url_read_dir = file_read_dir, + .url_close_dir = file_close_dir, }; #endif /* CONFIG_FILE_PROTOCOL */ diff --git a/chromium/third_party/ffmpeg/libavformat/flac_picture.c b/chromium/third_party/ffmpeg/libavformat/flac_picture.c index 669fd2e7825..7bd98258e4f 100644 --- a/chromium/third_party/ffmpeg/libavformat/flac_picture.c +++ b/chromium/third_party/ffmpeg/libavformat/flac_picture.c @@ -108,10 +108,10 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) ret = AVERROR_INVALIDDATA; goto fail; } - if (!(data = av_buffer_alloc(len + FF_INPUT_BUFFER_PADDING_SIZE))) { + if (!(data = av_buffer_alloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) { RETURN_ERROR(AVERROR(ENOMEM)); } - memset(data->data + len, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(data->data + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (avio_read(pb, data->data, len) != len) { av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n"); if (s->error_recognition & AV_EF_EXPLODE) diff --git a/chromium/third_party/ffmpeg/libavformat/flacdec.c b/chromium/third_party/ffmpeg/libavformat/flacdec.c index 4207fd2bf6c..4c1f9435810 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flacdec.c @@ -58,7 +58,7 @@ static int flac_read_header(AVFormatContext *s) case FLAC_METADATA_TYPE_CUESHEET: case FLAC_METADATA_TYPE_PICTURE: case FLAC_METADATA_TYPE_VORBIS_COMMENT: - buffer = av_mallocz(metadata_size + FF_INPUT_BUFFER_PADDING_SIZE); + buffer = av_mallocz(metadata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!buffer) { return AVERROR(ENOMEM); } diff --git a/chromium/third_party/ffmpeg/libavformat/flvdec.c b/chromium/third_party/ffmpeg/libavformat/flvdec.c index 345be1ea7d2..826e0d7ea20 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flvdec.c @@ -433,6 +433,8 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, case AMF_DATA_TYPE_UNSUPPORTED: break; // these take up no additional space case AMF_DATA_TYPE_MIXEDARRAY: + { + unsigned v; avio_skip(ioc, 4); // skip 32-bit max array index while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) @@ -441,11 +443,13 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, if (amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0) return -1; - if (avio_r8(ioc) != AMF_END_OF_OBJECT) { - av_log(s, AV_LOG_ERROR, "Missing AMF_END_OF_OBJECT in AMF_DATA_TYPE_MIXEDARRAY\n"); + v = avio_r8(ioc); + if (v != AMF_END_OF_OBJECT) { + av_log(s, AV_LOG_ERROR, "Missing AMF_END_OF_OBJECT in AMF_DATA_TYPE_MIXEDARRAY, found %d\n", v); return -1; } break; + } case AMF_DATA_TYPE_ARRAY: { unsigned int arraylen, i; @@ -654,7 +658,7 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream, { av_free(flv->new_extradata[stream]); flv->new_extradata[stream] = av_mallocz(size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!flv->new_extradata[stream]) return AVERROR(ENOMEM); flv->new_extradata_size[stream] = size; @@ -797,15 +801,16 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) int av_uninit(channels); int av_uninit(sample_rate); AVStream *st = NULL; + int last = -1; /* pkt size is repeated at end. skip it */ - for (;; avio_skip(s->pb, 4)) { + for (;; last = avio_rb32(s->pb)) { pos = avio_tell(s->pb); type = (avio_r8(s->pb) & 0x1F); size = avio_rb24(s->pb); dts = avio_rb24(s->pb); dts |= avio_r8(s->pb) << 24; - av_log(s, AV_LOG_TRACE, "type:%d, size:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, dts, avio_tell(s->pb)); + av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb)); if (avio_feof(s->pb)) return AVERROR_EOF; avio_skip(s->pb, 3); /* stream id, always 0 */ @@ -849,6 +854,13 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) meta_pos = avio_tell(s->pb); type = flv_read_metabody(s, next); if (type == 0 && dts == 0 || type < 0 || type == TYPE_UNKNOWN) { + if (type < 0 && flv->validate_count && + flv->validate_index[0].pos > next && + flv->validate_index[0].pos - 4 < next + ) { + av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n"); + next = flv->validate_index[0].pos - 4; + } goto skip; } else if (type == TYPE_ONTEXTDATA) { avpriv_request_sample(s, "OnTextData packet"); diff --git a/chromium/third_party/ffmpeg/libavformat/format.c b/chromium/third_party/ffmpeg/libavformat/format.c index 7df06b70fc0..fd81d7a132a 100644 --- a/chromium/third_party/ffmpeg/libavformat/format.c +++ b/chromium/third_party/ffmpeg/libavformat/format.c @@ -261,8 +261,13 @@ int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, if (pb->av_class) { uint8_t *mime_type_opt = NULL; + char *semi; av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt); pd.mime_type = (const char *)mime_type_opt; + semi = pd.mime_type ? strchr(pd.mime_type, ';') : NULL; + if (semi) { + *semi = '\0'; + } } #if 0 if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) { diff --git a/chromium/third_party/ffmpeg/libavformat/ftp.c b/chromium/third_party/ffmpeg/libavformat/ftp.c index 27a172e8ad7..dcb588dac29 100644 --- a/chromium/third_party/ffmpeg/libavformat/ftp.c +++ b/chromium/third_party/ffmpeg/libavformat/ftp.c @@ -19,6 +19,8 @@ */ #include "libavutil/avstring.h" +#include "libavutil/internal.h" +#include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" #include "url.h" @@ -26,15 +28,23 @@ #include "libavutil/bprint.h" #define CONTROL_BUFFER_SIZE 1024 +#define DIR_BUFFER_SIZE 4096 typedef enum { UNKNOWN, READY, DOWNLOADING, UPLOADING, + LISTING_DIR, DISCONNECTED } FTPState; +typedef enum { + UNKNOWN_METHOD, + NLST, + MLSD +} FTPListingMethod; + typedef struct { const AVClass *class; URLContext *conn_control; /**< Control connection */ @@ -53,6 +63,12 @@ typedef struct { const char *anonymous_password; /**< Password to be used for anonymous user. An email should be used. */ int write_seekable; /**< Control seekability, 0 = disable, 1 = enable. */ FTPState state; /**< State of data connection */ + FTPListingMethod listing_method; /**< Called listing method */ + char *features; /**< List of server's features represented as raw response */ + char *dir_buffer; + size_t dir_buffer_size; + size_t dir_buffer_offset; + int utf8; } FTPContext; #define OFFSET(x) offsetof(FTPContext, x) @@ -185,6 +201,8 @@ static int ftp_send_command(FTPContext *s, const char *command, { int err; + ff_dlog(s, "%s", command); + if (response) *response = NULL; @@ -266,7 +284,7 @@ static int ftp_passive_mode_epsv(FTPContext *s) end[-1] = '\0'; s->server_data_port = atoi(start); - av_dlog(s, "Server data port: %d\n", s->server_data_port); + ff_dlog(s, "Server data port: %d\n", s->server_data_port); av_free(res); return 0; @@ -312,7 +330,7 @@ static int ftp_passive_mode(FTPContext *s) start = av_strtok(end, ",", &end); if (!start) goto fail; s->server_data_port += atoi(start); - av_dlog(s, "Server data port: %d\n", s->server_data_port); + ff_dlog(s, "Server data port: %d\n", s->server_data_port); av_free(res); return 0; @@ -347,10 +365,7 @@ static int ftp_current_dir(FTPContext *s) if (!end) goto fail; - if (end > res && end[-1] == '/') { - end[-1] = '\0'; - } else - *end = '\0'; + *end = '\0'; s->path = av_strdup(start); av_free(res); @@ -434,19 +449,76 @@ static int ftp_restart(FTPContext *s, int64_t pos) return 0; } +static int ftp_set_dir(FTPContext *s) +{ + static const int cwd_codes[] = {250, 550, 0}; /* 550 is incorrect code */ + char command[MAX_URL_SIZE]; + + snprintf(command, sizeof(command), "CWD %s\r\n", s->path); + if (ftp_send_command(s, command, cwd_codes, NULL) != 250) + return AVERROR(EIO); + return 0; +} + +static int ftp_list_mlsd(FTPContext *s) +{ + static const char *command = "MLSD\r\n"; + static const int mlsd_codes[] = {150, 500, 0}; /* 500 is incorrect code */ + + if (ftp_send_command(s, command, mlsd_codes, NULL) != 150) + return AVERROR(ENOSYS); + s->listing_method = MLSD; + return 0; +} + +static int ftp_list_nlst(FTPContext *s) +{ + static const char *command = "NLST\r\n"; + static const int nlst_codes[] = {226, 425, 426, 451, 450, 550, 0}; + + if (ftp_send_command(s, command, nlst_codes, NULL) != 226) + return AVERROR(ENOSYS); + s->listing_method = NLST; + return 0; +} + +static int ftp_has_feature(FTPContext *s, const char *feature_name); + +static int ftp_list(FTPContext *s) +{ + int ret; + s->state = LISTING_DIR; + + if ((ret = ftp_list_mlsd(s)) < 0) + ret = ftp_list_nlst(s); + + return ret; +} + +static int ftp_has_feature(FTPContext *s, const char *feature_name) +{ + if (!s->features) + return 0; + + return av_stristr(s->features, feature_name) != NULL; +} + static int ftp_features(FTPContext *s) { static const char *feat_command = "FEAT\r\n"; static const char *enable_utf8_command = "OPTS UTF8 ON\r\n"; static const int feat_codes[] = {211, 0}; - static const int opts_codes[] = {200, 451}; - char *feat = NULL; + static const int opts_codes[] = {200, 451, 0}; - if (ftp_send_command(s, feat_command, feat_codes, &feat) == 211) { - if (av_stristr(feat, "UTF8")) - ftp_send_command(s, enable_utf8_command, opts_codes, NULL); + av_freep(&s->features); + if (ftp_send_command(s, feat_command, feat_codes, &s->features) != 211) { + av_freep(&s->features); + } + + if (ftp_has_feature(s, "UTF8")) { + if (ftp_send_command(s, enable_utf8_command, opts_codes, NULL) == 200) + s->utf8 = 1; } - av_freep(&feat); return 0; } @@ -570,20 +642,19 @@ static int ftp_abort(URLContext *h) return 0; } -static int ftp_open(URLContext *h, const char *url, int flags) +static int ftp_connect(URLContext *h, const char *url) { char proto[10], path[MAX_URL_SIZE], credencials[MAX_URL_SIZE], hostname[MAX_URL_SIZE]; const char *tok_user = NULL, *tok_pass = NULL; - char *end = NULL; + char *end = NULL, *newpath = NULL; int err; - size_t pathlen; FTPContext *s = h->priv_data; - av_dlog(h, "ftp protocol open\n"); - s->state = DISCONNECTED; + s->listing_method = UNKNOWN_METHOD; s->filesize = -1; s->position = 0; + s->features = NULL; av_url_split(proto, sizeof(proto), credencials, sizeof(credencials), @@ -602,22 +673,36 @@ static int ftp_open(URLContext *h, const char *url, int flags) s->password = av_strdup(tok_pass); s->hostname = av_strdup(hostname); if (!s->hostname || !s->user || (tok_pass && !s->password)) { - err = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } if (s->server_control_port < 0 || s->server_control_port > 65535) s->server_control_port = 21; if ((err = ftp_connect_control_connection(h)) < 0) - goto fail; + return err; if ((err = ftp_current_dir(s)) < 0) + return err; + + newpath = av_append_path_component(s->path, path); + if (!newpath) + return AVERROR(ENOMEM); + av_free(s->path); + s->path = newpath; + + return 0; +} + +static int ftp_open(URLContext *h, const char *url, int flags) +{ + FTPContext *s = h->priv_data; + int err; + + ff_dlog(h, "ftp protocol open\n"); + + if ((err = ftp_connect(h, url)) < 0) goto fail; - pathlen = strlen(s->path) + strlen(path) + 1; - if ((err = av_reallocp(&s->path, pathlen)) < 0) - goto fail; - av_strlcat(s->path + strlen(s->path), path, pathlen); if (ftp_restart(s, 0) < 0) { h->is_streamed = 1; @@ -642,7 +727,7 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence) int err; int64_t new_pos, fake_pos; - av_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence); + ff_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence); switch(whence) { case AVSEEK_SIZE: @@ -684,7 +769,7 @@ static int ftp_read(URLContext *h, unsigned char *buf, int size) FTPContext *s = h->priv_data; int read, err, retry_done = 0; - av_dlog(h, "ftp protocol read %d bytes\n", size); + ff_dlog(h, "ftp protocol read %d bytes\n", size); retry: if (s->state == DISCONNECTED) { /* optimization */ @@ -742,7 +827,7 @@ static int ftp_write(URLContext *h, const unsigned char *buf, int size) FTPContext *s = h->priv_data; int written; - av_dlog(h, "ftp protocol write %d bytes\n", size); + ff_dlog(h, "ftp protocol write %d bytes\n", size); if (s->state == DISCONNECTED) { if ((err = ftp_connect_data_connection(h)) < 0) @@ -769,13 +854,14 @@ static int ftp_close(URLContext *h) { FTPContext *s = h->priv_data; - av_dlog(h, "ftp protocol close\n"); + ff_dlog(h, "ftp protocol close\n"); ftp_close_both_connections(s); av_freep(&s->user); av_freep(&s->password); av_freep(&s->hostname); av_freep(&s->path); + av_freep(&s->features); return 0; } @@ -784,7 +870,7 @@ static int ftp_get_file_handle(URLContext *h) { FTPContext *s = h->priv_data; - av_dlog(h, "ftp protocol get_file_handle\n"); + ff_dlog(h, "ftp protocol get_file_handle\n"); if (s->conn_data) return ffurl_get_file_handle(s->conn_data); @@ -796,7 +882,7 @@ static int ftp_shutdown(URLContext *h, int flags) { FTPContext *s = h->priv_data; - av_dlog(h, "ftp protocol shutdown\n"); + ff_dlog(h, "ftp protocol shutdown\n"); if (s->conn_data) return ffurl_shutdown(s->conn_data, flags); @@ -804,6 +890,213 @@ static int ftp_shutdown(URLContext *h, int flags) return AVERROR(EIO); } +static int ftp_open_dir(URLContext *h) +{ + FTPContext *s = h->priv_data; + int ret; + + if ((ret = ftp_connect(h, h->filename)) < 0) + goto fail; + if ((ret = ftp_set_dir(s)) < 0) + goto fail; + if ((ret = ftp_connect_data_connection(h)) < 0) + goto fail; + if ((ret = ftp_list(s)) < 0) + goto fail; + s->dir_buffer = av_malloc(DIR_BUFFER_SIZE); + if (!s->dir_buffer) { + ret = AVERROR(ENOMEM); + goto fail; + } + s->dir_buffer[0] = 0; + if (s->conn_data && s->state == LISTING_DIR) + return 0; + fail: + ffurl_closep(&s->conn_control); + ffurl_closep(&s->conn_data); + return ret; +} + +static int64_t ftp_parse_date(const char *date) +{ + struct tm tv; + memset(&tv, 0, sizeof(struct tm)); + av_small_strptime(date, "%Y%m%d%H%M%S", &tv); + return INT64_C(1000000) * av_timegm(&tv); +} + +static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next) +{ + next->name = av_strdup(line); + return 0; +} + +static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next) +{ + char *fact, *value; + ff_dlog(NULL, "%s\n", mlsd); + while(fact = av_strtok(mlsd, ";", &mlsd)) { + if (fact[0] == ' ') { + next->name = av_strdup(&fact[1]); + continue; + } + fact = av_strtok(fact, "=", &value); + if (!av_strcasecmp(fact, "type")) { + if (!av_strcasecmp(value, "cdir") || !av_strcasecmp(value, "pdir")) + return 1; + if (!av_strcasecmp(value, "dir")) + next->type = AVIO_ENTRY_DIRECTORY; + else if (!av_strcasecmp(value, "file")) + next->type = AVIO_ENTRY_FILE; + else if (!av_strcasecmp(value, "OS.unix=slink:")) + next->type = AVIO_ENTRY_SYMBOLIC_LINK; + } else if (!av_strcasecmp(fact, "modify")) { + next->modification_timestamp = ftp_parse_date(value); + } else if (!av_strcasecmp(fact, "UNIX.mode")) { + next->filemode = strtoumax(value, NULL, 8); + } else if (!av_strcasecmp(fact, "UNIX.uid") || !av_strcasecmp(fact, "UNIX.owner")) + next->user_id = strtoumax(value, NULL, 10); + else if (!av_strcasecmp(fact, "UNIX.gid") || !av_strcasecmp(fact, "UNIX.group")) + next->group_id = strtoumax(value, NULL, 10); + else if (!av_strcasecmp(fact, "size") || !av_strcasecmp(fact, "sizd")) + next->size = strtoll(value, NULL, 10); + } + return 0; +} + +/** + * @return 0 on success, negative on error, positive on entry to discard. + */ +static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next) +{ + FTPContext *s = h->priv_data; + + switch (s->listing_method) { + case MLSD: + return ftp_parse_entry_mlsd(line, next); + case NLST: + return ftp_parse_entry_nlst(line, next); + case UNKNOWN_METHOD: + default: + return -1; + } +} + +static int ftp_read_dir(URLContext *h, AVIODirEntry **next) +{ + FTPContext *s = h->priv_data; + char *start, *found; + int ret, retried; + + do { + retried = 0; + start = s->dir_buffer + s->dir_buffer_offset; + while (!(found = strstr(start, "\n"))) { + if (retried) + return AVERROR(EIO); + s->dir_buffer_size -= s->dir_buffer_offset; + s->dir_buffer_offset = 0; + if (s->dir_buffer_size) + memmove(s->dir_buffer, start, s->dir_buffer_size); + ret = ffurl_read(s->conn_data, s->dir_buffer + s->dir_buffer_size, DIR_BUFFER_SIZE - (s->dir_buffer_size + 1)); + if (ret < 0) + return ret; + if (!ret) { + *next = NULL; + return 0; + } + s->dir_buffer_size += ret; + s->dir_buffer[s->dir_buffer_size] = 0; + start = s->dir_buffer; + retried = 1; + } + s->dir_buffer_offset += (found + 1 - start); + found[0] = 0; + if (found > start && found[-1] == '\r') + found[-1] = 0; + + *next = ff_alloc_dir_entry(); + if (!*next) + return AVERROR(ENOMEM); + (*next)->utf8 = s->utf8; + ret = ftp_parse_entry(h, start, *next); + if (ret) { + avio_free_directory_entry(next); + if (ret < 0) + return ret; + } + } while (ret > 0); + return 0; +} + +static int ftp_close_dir(URLContext *h) +{ + FTPContext *s = h->priv_data; + av_freep(&s->dir_buffer); + ffurl_closep(&s->conn_control); + ffurl_closep(&s->conn_data); + return 0; +} + +static int ftp_delete(URLContext *h) +{ + FTPContext *s = h->priv_data; + char command[MAX_URL_SIZE]; + static const int del_codes[] = {250, 421, 450, 500, 501, 502, 530, 550, 0}; + static const int rmd_codes[] = {250, 421, 500, 501, 502, 530, 550, 0}; + int ret; + + if ((ret = ftp_connect(h, h->filename)) < 0) + goto cleanup; + + snprintf(command, sizeof(command), "DELE %s\r\n", s->path); + if (ftp_send_command(s, command, del_codes, NULL) == 250) { + ret = 0; + goto cleanup; + } + + snprintf(command, sizeof(command), "RMD %s\r\n", s->path); + if (ftp_send_command(s, command, rmd_codes, NULL) == 250) + ret = 0; + else + ret = AVERROR(EIO); + +cleanup: + ftp_close(h); + return ret; +} + +static int ftp_move(URLContext *h_src, URLContext *h_dst) +{ + FTPContext *s = h_src->priv_data; + char command[MAX_URL_SIZE], path[MAX_URL_SIZE]; + static const int rnfr_codes[] = {350, 421, 450, 500, 501, 502, 503, 530, 0}; + static const int rnto_codes[] = {250, 421, 500, 501, 502, 503, 530, 532, 553, 0}; + int ret; + + if ((ret = ftp_connect(h_src, h_src->filename)) < 0) + goto cleanup; + + snprintf(command, sizeof(command), "RNFR %s\r\n", s->path); + if (ftp_send_command(s, command, rnfr_codes, NULL) != 350) { + ret = AVERROR(EIO); + goto cleanup; + } + + av_url_split(0, 0, 0, 0, 0, 0, 0, + path, sizeof(path), + h_dst->filename); + snprintf(command, sizeof(command), "RNTO %s\r\n", path); + if (ftp_send_command(s, command, rnto_codes, NULL) == 250) + ret = 0; + else + ret = AVERROR(EIO); + +cleanup: + ftp_close(h_src); + return ret; +} + URLProtocol ff_ftp_protocol = { .name = "ftp", .url_open = ftp_open, @@ -815,5 +1108,10 @@ URLProtocol ff_ftp_protocol = { .url_shutdown = ftp_shutdown, .priv_data_size = sizeof(FTPContext), .priv_data_class = &ftp_context_class, + .url_open_dir = ftp_open_dir, + .url_read_dir = ftp_read_dir, + .url_close_dir = ftp_close_dir, + .url_delete = ftp_delete, + .url_move = ftp_move, .flags = URL_PROTOCOL_FLAG_NETWORK, }; diff --git a/chromium/third_party/ffmpeg/libavformat/gifdec.c b/chromium/third_party/ffmpeg/libavformat/gifdec.c index bb4c6ec6e64..1ac47fee504 100644 --- a/chromium/third_party/ffmpeg/libavformat/gifdec.c +++ b/chromium/third_party/ffmpeg/libavformat/gifdec.c @@ -52,6 +52,9 @@ typedef struct GIFDemuxContext { int total_iter; int iter_count; int ignore_loop; + + int nb_frames; + int last_duration; } GIFDemuxContext; /** @@ -279,6 +282,9 @@ parse_keyframe: pkt->stream_index = 0; pkt->duration = gdc->delay; + gdc->nb_frames ++; + gdc->last_duration = pkt->duration; + /* Graphic Control Extension's scope is single frame. * Remove its influence. */ gdc->delay = gdc->default_delay; @@ -299,6 +305,9 @@ resync: } if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) { + if (gdc->nb_frames == 1) { + s->streams[0]->r_frame_rate = (AVRational) {100, gdc->last_duration}; + } /* This might happen when there is no image block * between extension blocks and GIF_TRAILER or EOF */ if (!gdc->ignore_loop && (block_label == GIF_TRAILER || avio_feof(pb)) diff --git a/chromium/third_party/ffmpeg/libavformat/hevc.c b/chromium/third_party/ffmpeg/libavformat/hevc.c index 643b71596ad..7c294ef8a24 100644 --- a/chromium/third_party/ffmpeg/libavformat/hevc.c +++ b/chromium/third_party/ffmpeg/libavformat/hevc.c @@ -565,7 +565,10 @@ static int hvcc_parse_sps(GetBitContext *gb, } if (get_bits1(gb)) { // long_term_ref_pics_present_flag - for (i = 0; i < get_ue_golomb_long(gb); i++) { // num_long_term_ref_pics_sps + unsigned num_long_term_ref_pics_sps = get_ue_golomb_long(gb); + if (num_long_term_ref_pics_sps > 31U) + return AVERROR_INVALIDDATA; + for (i = 0; i < num_long_term_ref_pics_sps; i++) { // num_long_term_ref_pics_sps int len = FFMIN(log2_max_pic_order_cnt_lsb_minus4 + 4, 16); skip_bits (gb, len); // lt_ref_pic_poc_lsb_sps[i] skip_bits1(gb); // used_by_curr_pic_lt_sps_flag[i] @@ -616,11 +619,12 @@ static int hvcc_parse_pps(GetBitContext *gb, get_se_golomb_long(gb); // pps_cr_qp_offset /* + * pps_slice_chroma_qp_offsets_present_flag u(1) * weighted_pred_flag u(1) * weighted_bipred_flag u(1) * transquant_bypass_enabled_flag u(1) */ - skip_bits(gb, 3); + skip_bits(gb, 4); tiles_enabled_flag = get_bits1(gb); entropy_coding_sync_enabled_flag = get_bits1(gb); @@ -644,7 +648,7 @@ static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, uint8_t *dst; uint32_t i, len; - dst = av_malloc(src_len); + dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); if (!dst) return NULL; diff --git a/chromium/third_party/ffmpeg/libavformat/hls.c b/chromium/third_party/ffmpeg/libavformat/hls.c index 3f1d97eb6f2..c16c7708f42 100644 --- a/chromium/third_party/ffmpeg/libavformat/hls.c +++ b/chromium/third_party/ffmpeg/libavformat/hls.c @@ -182,6 +182,7 @@ typedef struct HLSContext { char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context + AVDictionary *avio_opts; } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -481,7 +482,9 @@ static void handle_rendition_args(struct rendition_info *info, const char *key, /* used by parse_playlist to allocate a new variant+playlist when the * playlist is detected to be a Media Playlist (not Master Playlist) * and we have no parent Master Playlist (parsing of which would have - * allocated the variant and playlist already) */ + * allocated the variant and playlist already) + * *pls == NULL => Master Playlist or parentless Media Playlist + * *pls != NULL => parented Media Playlist, playlist+variant allocated */ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url) { if (*pls) @@ -492,8 +495,55 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url return 0; } -/* pls = NULL => Master Playlist or parentless Media Playlist - * pls = !NULL => parented Media Playlist, playlist+variant allocated */ +static int open_in(HLSContext *c, AVIOContext **in, const char *url) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, c->avio_opts, 0); + + ret = avio_open2(in, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); + + av_dict_free(&tmp); + return ret; +} + +static int url_connect(struct playlist *pls, AVDictionary *opts, AVDictionary *opts2) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, opts, 0); + av_dict_copy(&tmp, opts2, 0); + + if ((ret = av_opt_set_dict(pls->input, &tmp)) < 0) + goto fail; + + if ((ret = ffurl_connect(pls->input, NULL)) < 0) { + ffurl_close(pls->input); + pls->input = NULL; + } + +fail: + av_dict_free(&tmp); + return ret; +} + +static int open_url(HLSContext *c, URLContext **uc, const char *url, AVDictionary *opts) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, c->avio_opts, 0); + av_dict_copy(&tmp, opts, 0); + + ret = ffurl_open(uc, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); + + av_dict_free(&tmp); + + return ret; +} + static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { @@ -513,6 +563,7 @@ static int parse_playlist(HLSContext *c, const char *url, char tmp_str[MAX_URL_SIZE]; if (!in) { +#if 1 AVDictionary *opts = NULL; close_in = 1; /* Some HLS servers don't like being sent the range header */ @@ -528,6 +579,12 @@ static int parse_playlist(HLSContext *c, const char *url, av_dict_free(&opts); if (ret < 0) return ret; +#else + ret = open_in(c, &in, url); + if (ret < 0) + return ret; + close_in = 1; +#endif } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) @@ -752,7 +809,7 @@ static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata, if (apic) { int size = pls->ctx->streams[1]->attached_pic.size; - if (size != apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE) + if (size != apic->buf->size - AV_INPUT_BUFFER_PADDING_SIZE) return 1; if (memcmp(apic->buf->data, pls->ctx->streams[1]->attached_pic.data, size) != 0) @@ -940,15 +997,13 @@ static int open_input(HLSContext *c, struct playlist *pls) seg->url, seg->url_offset, pls->index); if (seg->key_type == KEY_NONE) { - ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ, - &pls->parent->interrupt_callback, &opts); - + ret = open_url(pls->parent->priv_data, &pls->input, seg->url, opts); } else if (seg->key_type == KEY_AES_128) { +// HLSContext *c = var->parent->priv_data; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { URLContext *uc; - if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, - &pls->parent->interrupt_callback, &opts2) == 0) { + if (open_url(pls->parent->priv_data, &uc, seg->key, opts2) == 0) { if (ffurl_read_complete(uc, pls->key, sizeof(pls->key)) != sizeof(pls->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", @@ -970,15 +1025,14 @@ static int open_input(HLSContext *c, struct playlist *pls) snprintf(url, sizeof(url), "crypto+%s", seg->url); else snprintf(url, sizeof(url), "crypto:%s", seg->url); + if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ, &pls->parent->interrupt_callback)) < 0) goto cleanup; av_opt_set(pls->input->priv_data, "key", key, 0); av_opt_set(pls->input->priv_data, "iv", iv, 0); - if ((ret = ffurl_connect(pls->input, &opts)) < 0) { - ffurl_close(pls->input); - pls->input = NULL; + if ((ret = url_connect(pls, c->avio_opts, opts)) < 0) { goto cleanup; } ret = 0; @@ -1085,6 +1139,8 @@ reload: ret = open_input(c, v); if (ret < 0) { + if (ff_check_interrupt(c->interrupt_callback)) + return AVERROR_EXIT; av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n", v->index); v->cur_seq_no += 1; @@ -1252,6 +1308,26 @@ static int select_cur_seq_no(HLSContext *c, struct playlist *pls) return pls->start_seq_no; } +static int save_avio_options(AVFormatContext *s) +{ + HLSContext *c = s->priv_data; + const char *opts[] = { "headers", "user_agent", "user-agent", "cookies", NULL }, **opt = opts; + uint8_t *buf; + int ret = 0; + + while (*opt) { + if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { + ret = av_dict_set(&c->avio_opts, *opt, buf, + AV_DICT_DONT_STRDUP_VAL); + if (ret < 0) + return ret; + } + opt++; + } + + return ret; +} + static int hls_read_header(AVFormatContext *s) { URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; @@ -1279,6 +1355,12 @@ static int hls_read_header(AVFormatContext *s) if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; + if ((ret = save_avio_options(s)) < 0) + goto fail; + + /* Some HLS servers don't like being sent the range header */ + av_dict_set(&c->avio_opts, "seekable", "0", 0); + if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; @@ -1629,6 +1711,9 @@ static int hls_close(AVFormatContext *s) free_playlist_list(c); free_variant_list(c); free_rendition_list(c); + + av_dict_free(&c->avio_opts); + return 0; } @@ -1729,7 +1814,7 @@ static int hls_probe(AVProbeData *p) #define FLAGS AV_OPT_FLAG_DECODING_PARAM static const AVOption hls_options[] = { {"live_start_index", "segment index to start live streams at (negative values are from the end)", - OFFSET(live_start_index), FF_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS}, + OFFSET(live_start_index), AV_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS}, {NULL} }; diff --git a/chromium/third_party/ffmpeg/libavformat/hlsenc.c b/chromium/third_party/ffmpeg/libavformat/hlsenc.c index cf29f4f737f..473ca3a7223 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsenc.c @@ -32,6 +32,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/log.h" +#include "libavutil/time_internal.h" #include "avformat.h" #include "internal.h" @@ -42,6 +43,7 @@ typedef struct HLSSegment { char filename[1024]; + char sub_filename[1024]; double duration; /* in seconds */ int64_t pos; int64_t size; @@ -67,8 +69,10 @@ typedef struct HLSContext { int64_t sequence; int64_t start_sequence; AVOutputFormat *oformat; + AVOutputFormat *vtt_oformat; AVFormatContext *avf; + AVFormatContext *vtt_avf; float time; // Set by a private option. int max_nb_segments; // Set by a private option. @@ -76,9 +80,11 @@ typedef struct HLSContext { uint32_t flags; // enum HLSFlags char *segment_filename; + int use_localtime; ///< flag to expand filename with localtime int allowcache; int64_t recording_time; int has_video; + int has_subtitle; int64_t start_pts; int64_t end_pts; double duration; // last segment duration computed so far, in seconds @@ -92,8 +98,12 @@ typedef struct HLSContext { HLSSegment *old_segments; char *basename; + char *vtt_basename; + char *vtt_m3u8_name; char *baseurl; char *format_options_str; + char *vtt_format_options_str; + char *subtitle_filename; AVDictionary *format_options; char *key_info_file; @@ -101,14 +111,19 @@ typedef struct HLSContext { char key_uri[LINE_BUFFER_SIZE + 1]; char key_string[KEYSIZE*2 + 1]; char iv_string[KEYSIZE*2 + 1]; + AVDictionary *vtt_format_options; + + char *method; + } HLSContext; static int hls_delete_old_segments(HLSContext *hls) { HLSSegment *segment, *previous_segment = NULL; float playlist_duration = 0.0f; - int ret = 0, path_size; - char *dirname = NULL, *p, *path; + int ret = 0, path_size, sub_path_size; + char *dirname = NULL, *p, *sub_path; + char *path = NULL; segment = hls->segments; while (segment) { @@ -150,19 +165,35 @@ static int hls_delete_old_segments(HLSContext *hls) { ret = AVERROR(ENOMEM); goto fail; } + sub_path_size = strlen(dirname) + strlen(segment->sub_filename) + 1; + sub_path = av_malloc(sub_path_size); + if (!sub_path) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(path, dirname, path_size); av_strlcat(path, segment->filename, path_size); if (unlink(path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", path, strerror(errno)); } - av_free(path); + + av_strlcpy(sub_path, dirname, sub_path_size); + av_strlcat(sub_path, segment->sub_filename, sub_path_size); + if (unlink(sub_path) < 0) { + av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", + sub_path, strerror(errno)); + } + av_freep(&path); + av_free(sub_path); previous_segment = segment; segment = previous_segment->next; av_free(previous_segment); } fail: + av_free(path); av_free(dirname); return ret; @@ -226,6 +257,7 @@ static int hls_mux_init(AVFormatContext *s) { HLSContext *hls = s->priv_data; AVFormatContext *oc; + AVFormatContext *vtt_oc = NULL; int i, ret; ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL); @@ -238,9 +270,24 @@ static int hls_mux_init(AVFormatContext *s) oc->max_delay = s->max_delay; av_dict_copy(&oc->metadata, s->metadata, 0); + if(hls->vtt_oformat) { + ret = avformat_alloc_output_context2(&hls->vtt_avf, hls->vtt_oformat, NULL, NULL); + if (ret < 0) + return ret; + vtt_oc = hls->vtt_avf; + vtt_oc->oformat = hls->vtt_oformat; + av_dict_copy(&vtt_oc->metadata, s->metadata, 0); + } + for (i = 0; i < s->nb_streams; i++) { AVStream *st; - if (!(st = avformat_new_stream(oc, NULL))) + AVFormatContext *loc; + if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) + loc = vtt_oc; + else + loc = oc; + + if (!(st = avformat_new_stream(loc, NULL))) return AVERROR(ENOMEM); avcodec_copy_context(st->codec, s->streams[i]->codec); st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; @@ -263,6 +310,9 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, av_strlcpy(en->filename, av_basename(hls->avf->filename), sizeof(en->filename)); + if(hls->has_subtitle) + av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename)); + en->duration = duration; en->pos = pos; en->size = size; @@ -310,6 +360,12 @@ static void hls_free_segments(HLSSegment *p) } } +static void set_http_options(AVDictionary **options, HLSContext *c) +{ + if (c->method) + av_dict_set(options, "method", c->method, 0); +} + static int hls_window(AVFormatContext *s, int last) { HLSContext *hls = s->priv_data; @@ -317,6 +373,7 @@ static int hls_window(AVFormatContext *s, int last) int target_duration = 0; int ret = 0; AVIOContext *out = NULL; + AVIOContext *sub_out = NULL; char temp_filename[1024]; int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries); int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3; @@ -325,13 +382,15 @@ static int hls_window(AVFormatContext *s, int last) static unsigned warned_non_file; char *key_uri = NULL; char *iv_string = NULL; + AVDictionary *options = NULL; if (!use_rename && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n"); + set_http_options(&options, hls); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); if ((ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + &s->interrupt_callback, &options)) < 0) goto fail; for (en = hls->segments; en; en = en->next) { @@ -380,8 +439,40 @@ static int hls_window(AVFormatContext *s, int last) if (last && (hls->flags & HLS_OMIT_ENDLIST)==0) avio_printf(out, "#EXT-X-ENDLIST\n"); + if( hls->vtt_m3u8_name ) { + if ((ret = avio_open2(&sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, + &s->interrupt_callback, &options)) < 0) + goto fail; + avio_printf(sub_out, "#EXTM3U\n"); + avio_printf(sub_out, "#EXT-X-VERSION:%d\n", version); + if (hls->allowcache == 0 || hls->allowcache == 1) { + avio_printf(sub_out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); + } + avio_printf(sub_out, "#EXT-X-TARGETDURATION:%d\n", target_duration); + avio_printf(sub_out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + + av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", + sequence); + + for (en = hls->segments; en; en = en->next) { + avio_printf(sub_out, "#EXTINF:%f,\n", en->duration); + if (hls->flags & HLS_SINGLE_FILE) + avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", + en->size, en->pos); + if (hls->baseurl) + avio_printf(sub_out, "%s", hls->baseurl); + avio_printf(sub_out, "%s\n", en->sub_filename); + } + + if (last) + avio_printf(sub_out, "#EXT-X-ENDLIST\n"); + + } + fail: + av_dict_free(&options); avio_closep(&out); + avio_closep(&sub_out); if (ret >= 0 && use_rename) ff_rename(temp_filename, s->filename, s); return ret; @@ -391,37 +482,60 @@ static int hls_start(AVFormatContext *s) { HLSContext *c = s->priv_data; AVFormatContext *oc = c->avf; + AVFormatContext *vtt_oc = c->vtt_avf; AVDictionary *options = NULL; char *filename, iv_string[KEYSIZE*2 + 1]; int err = 0; - if (c->flags & HLS_SINGLE_FILE) + if (c->flags & HLS_SINGLE_FILE) { av_strlcpy(oc->filename, c->basename, sizeof(oc->filename)); - else - if (av_get_frame_filename(oc->filename, sizeof(oc->filename), + if (c->vtt_basename) + av_strlcpy(vtt_oc->filename, c->vtt_basename, + sizeof(vtt_oc->filename)); + } else { + if (c->use_localtime) { + time_t now0; + struct tm *tm, tmpbuf; + time(&now0); + tm = localtime_r(&now0, &tmpbuf); + if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) { + av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); + return AVERROR(EINVAL); + } + } else if (av_get_frame_filename(oc->filename, sizeof(oc->filename), c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) { - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try use -use_localtime 1 with it\n", c->basename); return AVERROR(EINVAL); } + if( c->vtt_basename) { + if (av_get_frame_filename(vtt_oc->filename, sizeof(vtt_oc->filename), + c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) { + av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename); + return AVERROR(EINVAL); + } + } + } c->number++; + set_http_options(&options, c); + if (c->key_info_file) { if ((err = hls_encryption_start(s)) < 0) - return err; + goto fail; if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0)) < 0) - return err; + goto fail; err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string)); if (!err) snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, c->sequence); if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0) - return err; + goto fail; filename = av_asprintf("crypto:%s", oc->filename); if (!filename) { - av_dict_free(&options); - return AVERROR(ENOMEM); + err = AVERROR(ENOMEM); + goto fail; } err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, &options); @@ -431,13 +545,27 @@ static int hls_start(AVFormatContext *s) return err; } else if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) - return err; + &s->interrupt_callback, &options)) < 0) + goto fail; + if (c->vtt_basename) { + set_http_options(&options, c); + if ((err = avio_open2(&vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE, + &s->interrupt_callback, &options)) < 0) + goto fail; + } + av_dict_free(&options); if (oc->oformat->priv_class && oc->priv_data) av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0); + if (c->vtt_basename) + avformat_write_header(vtt_oc,NULL); + return 0; +fail: + av_dict_free(&options); + + return err; } static int hls_write_header(AVFormatContext *s) @@ -446,8 +574,11 @@ static int hls_write_header(AVFormatContext *s) int ret, i; char *p; const char *pattern = "%d.ts"; + const char *pattern_localtime_fmt = "-%s.ts"; + const char *vtt_pattern = "%d.vtt"; AVDictionary *options = NULL; int basename_size; + int vtt_basename_size; hls->sequence = hls->start_sequence; hls->recording_time = hls->time * AV_TIME_BASE; @@ -461,9 +592,12 @@ static int hls_write_header(AVFormatContext *s) } } - for (i = 0; i < s->nb_streams; i++) + for (i = 0; i < s->nb_streams; i++) { hls->has_video += s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO; + hls->has_subtitle += + s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE; + } if (hls->has_video > 1) av_log(s, AV_LOG_WARNING, @@ -477,6 +611,14 @@ static int hls_write_header(AVFormatContext *s) goto fail; } + if(hls->has_subtitle) { + hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL); + if (!hls->oformat) { + ret = AVERROR_MUXER_NOT_FOUND; + goto fail; + } + } + if (hls->segment_filename) { hls->basename = av_strdup(hls->segment_filename); if (!hls->basename) { @@ -487,7 +629,11 @@ static int hls_write_header(AVFormatContext *s) if (hls->flags & HLS_SINGLE_FILE) pattern = ".ts"; - basename_size = strlen(s->filename) + strlen(pattern) + 1; + if (hls->use_localtime) { + basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1; + } else { + basename_size = strlen(s->filename) + strlen(pattern) + 1; + } hls->basename = av_malloc(basename_size); if (!hls->basename) { ret = AVERROR(ENOMEM); @@ -499,7 +645,40 @@ static int hls_write_header(AVFormatContext *s) p = strrchr(hls->basename, '.'); if (p) *p = '\0'; - av_strlcat(hls->basename, pattern, basename_size); + if (hls->use_localtime) { + av_strlcat(hls->basename, pattern_localtime_fmt, basename_size); + } else { + av_strlcat(hls->basename, pattern, basename_size); + } + } + + if(hls->has_subtitle) { + + if (hls->flags & HLS_SINGLE_FILE) + vtt_pattern = ".vtt"; + vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1; + hls->vtt_basename = av_malloc(vtt_basename_size); + if (!hls->vtt_basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + hls->vtt_m3u8_name = av_malloc(vtt_basename_size); + if (!hls->vtt_m3u8_name ) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size); + p = strrchr(hls->vtt_basename, '.'); + if (p) + *p = '\0'; + + if( hls->subtitle_filename ) { + strcpy(hls->vtt_m3u8_name, hls->subtitle_filename); + } else { + strcpy(hls->vtt_m3u8_name, hls->vtt_basename); + av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size); + } + av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size); } if ((ret = hls_mux_init(s)) < 0) @@ -515,10 +694,19 @@ static int hls_write_header(AVFormatContext *s) ret = AVERROR(EINVAL); goto fail; } - av_assert0(s->nb_streams == hls->avf->nb_streams); + //av_assert0(s->nb_streams == hls->avf->nb_streams); for (i = 0; i < s->nb_streams; i++) { - AVStream *inner_st = hls->avf->streams[i]; + AVStream *inner_st; AVStream *outer_st = s->streams[i]; + if (outer_st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) + inner_st = hls->avf->streams[i]; + else if (hls->vtt_avf) + inner_st = hls->vtt_avf->streams[0]; + else { + /* We have a subtitle stream, when the user does not want one */ + inner_st = NULL; + continue; + } avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den); } fail: @@ -526,8 +714,12 @@ fail: av_dict_free(&options); if (ret < 0) { av_freep(&hls->basename); + av_freep(&hls->vtt_basename); if (hls->avf) avformat_free_context(hls->avf); + if (hls->vtt_avf) + avformat_free_context(hls->vtt_avf); + } return ret; } @@ -535,12 +727,20 @@ fail: static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) { HLSContext *hls = s->priv_data; - AVFormatContext *oc = hls->avf; + AVFormatContext *oc = NULL; AVStream *st = s->streams[pkt->stream_index]; int64_t end_pts = hls->recording_time * hls->number; int is_ref_pkt = 1; int ret, can_split = 1; + int stream_index = 0; + if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE ) { + oc = hls->vtt_avf; + stream_index = 0; + } else { + oc = hls->avf; + stream_index = pkt->stream_index; + } if (hls->start_pts == AV_NOPTS_VALUE) { hls->start_pts = pkt->pts; hls->end_pts = pkt->pts; @@ -579,6 +779,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) hls->number++; } else { avio_closep(&oc->pb); + if (hls->vtt_avf) + avio_close(hls->vtt_avf->pb); ret = hls_start(s); } @@ -586,13 +788,16 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (ret < 0) return ret; + if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE ) + oc = hls->vtt_avf; + else oc = hls->avf; if ((ret = hls_window(s, 0)) < 0) return ret; } - ret = ff_write_chained(oc, pkt->stream_index, pkt, s, 0); + ret = ff_write_chained(oc, stream_index, pkt, s, 0); return ret; } @@ -601,6 +806,7 @@ static int hls_write_trailer(struct AVFormatContext *s) { HLSContext *hls = s->priv_data; AVFormatContext *oc = hls->avf; + AVFormatContext *vtt_oc = hls->vtt_avf; av_write_trailer(oc); if (oc->pb) { @@ -608,8 +814,22 @@ static int hls_write_trailer(struct AVFormatContext *s) avio_closep(&oc->pb); hls_append_segment(hls, hls->duration, hls->start_pos, hls->size); } + + if (vtt_oc) { + if (vtt_oc->pb) + av_write_trailer(vtt_oc); + hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos; + avio_closep(&vtt_oc->pb); + } av_freep(&hls->basename); avformat_free_context(oc); + + if (vtt_oc) { + av_freep(&hls->vtt_basename); + av_freep(&hls->vtt_m3u8_name); + avformat_free_context(vtt_oc); + } + hls->avf = NULL; hls_window(s, 1); @@ -625,17 +845,21 @@ static const AVOption options[] = { {"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E}, {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E}, {"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"hls_vtt_options","set hls vtt list of options for the container format used for hls", OFFSET(vtt_format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E}, {"hls_allow_cache", "explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments", OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, E}, {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_key_info_file", "file with key URI and key file path", OFFSET(key_info_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"}, {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"}, {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"}, + { "use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, E }, + {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, { NULL }, }; @@ -655,6 +879,7 @@ AVOutputFormat ff_hls_muxer = { .priv_data_size = sizeof(HLSContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, + .subtitle_codec = AV_CODEC_ID_WEBVTT, .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH, .write_header = hls_write_header, .write_packet = hls_write_packet, diff --git a/chromium/third_party/ffmpeg/libavformat/http.c b/chromium/third_party/ffmpeg/libavformat/http.c index 676bfd5c5a8..075dda77b85 100644 --- a/chromium/third_party/ffmpeg/libavformat/http.c +++ b/chromium/third_party/ffmpeg/libavformat/http.c @@ -25,8 +25,10 @@ #include <zlib.h> #endif /* CONFIG_ZLIB */ +#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/opt.h" +#include "libavutil/time.h" #include "avformat.h" #include "http.h" @@ -44,6 +46,14 @@ * path names). */ #define BUFFER_SIZE MAX_URL_SIZE #define MAX_REDIRECTS 8 +#define HTTP_SINGLE 1 +#define HTTP_MUTLI 2 +typedef enum { + LOWER_PROTO, + READ_HEADERS, + WRITE_REPLY_HEADERS, + FINISH +}HandshakeState; typedef struct HTTPContext { const AVClass *class; @@ -96,7 +106,16 @@ typedef struct HTTPContext { int send_expect_100; char *method; int reconnect; + int reconnect_at_eof; + int reconnect_streamed; + int reconnect_delay; + int reconnect_delay_max; int listen; + char *resource; + int reply_code; + int is_multi_client; + HandshakeState handshake_step; + int is_connected_server; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) @@ -128,7 +147,12 @@ static const AVOption options[] = { { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D }, { "method", "Override the HTTP method or set the expected HTTP method from a client", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D }, - { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E }, + { "reconnect_at_eof", "auto reconnect at EOF", OFFSET(reconnect_at_eof), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D }, + { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D }, + { "reconnect_delay_max", "max reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_max), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D }, + { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E }, + { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, + { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E}, { NULL } }; @@ -299,51 +323,143 @@ int ff_http_averror(int status_code, int default_averror) return default_averror; } -static void handle_http_errors(URLContext *h, int error) +static int http_write_reply(URLContext* h, int status_code) { - static const char bad_request[] = "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n"; - static const char internal_server_error[] = "HTTP/1.1 500 Internal server error\r\nContent-Type: text/plain\r\n\r\n500 Internal server error\r\n"; + int ret, body = 0, reply_code, message_len; + const char *reply_text, *content_type; HTTPContext *s = h->priv_data; - if (h->is_connected) { - switch(error) { - case AVERROR_HTTP_BAD_REQUEST: - ffurl_write(s->hd, bad_request, strlen(bad_request)); - break; - default: - av_log(h, AV_LOG_ERROR, "Unhandled HTTP error.\n"); - ffurl_write(s->hd, internal_server_error, strlen(internal_server_error)); + char message[BUFFER_SIZE]; + content_type = "text/plain"; + + if (status_code < 0) + body = 1; + switch (status_code) { + case AVERROR_HTTP_BAD_REQUEST: + case 400: + reply_code = 400; + reply_text = "Bad Request"; + break; + case AVERROR_HTTP_FORBIDDEN: + case 403: + reply_code = 403; + reply_text = "Forbidden"; + break; + case AVERROR_HTTP_NOT_FOUND: + case 404: + reply_code = 404; + reply_text = "Not Found"; + break; + case 200: + reply_code = 200; + reply_text = "OK"; + content_type = "application/octet-stream"; + break; + case AVERROR_HTTP_SERVER_ERROR: + case 500: + reply_code = 500; + reply_text = "Internal server error"; + break; + default: + return AVERROR(EINVAL); + } + if (body) { + s->chunked_post = 0; + message_len = snprintf(message, sizeof(message), + "HTTP/1.1 %03d %s\r\n" + "Content-Type: %s\r\n" + "Content-Length: %zu\r\n" + "\r\n" + "%03d %s\r\n", + reply_code, + reply_text, + content_type, + strlen(reply_text) + 6, // 3 digit status code + space + \r\n + reply_code, + reply_text); + } else { + s->chunked_post = 1; + message_len = snprintf(message, sizeof(message), + "HTTP/1.1 %03d %s\r\n" + "Content-Type: %s\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n", + reply_code, + reply_text, + content_type); + } + av_log(h, AV_LOG_TRACE, "HTTP reply header: \n%s----\n", message); + if ((ret = ffurl_write(s->hd, message, message_len)) < 0) + return ret; + return 0; +} + +static void handle_http_errors(URLContext *h, int error) +{ + av_assert0(error < 0); + http_write_reply(h, error); +} + +static int http_handshake(URLContext *c) +{ + int ret, err, new_location; + HTTPContext *ch = c->priv_data; + URLContext *cl = ch->hd; + switch (ch->handshake_step) { + case LOWER_PROTO: + av_log(c, AV_LOG_TRACE, "Lower protocol\n"); + if ((ret = ffurl_handshake(cl)) > 0) + return 2 + ret; + if (ret < 0) + return ret; + ch->handshake_step = READ_HEADERS; + ch->is_connected_server = 1; + return 2; + case READ_HEADERS: + av_log(c, AV_LOG_TRACE, "Read headers\n"); + if ((err = http_read_header(c, &new_location)) < 0) { + handle_http_errors(c, err); + return err; } + ch->handshake_step = WRITE_REPLY_HEADERS; + return 1; + case WRITE_REPLY_HEADERS: + av_log(c, AV_LOG_TRACE, "Reply code: %d\n", ch->reply_code); + if ((err = http_write_reply(c, ch->reply_code)) < 0) + return err; + ch->handshake_step = FINISH; + return 1; + case FINISH: + return 0; } + // this should never be reached. + return AVERROR(EINVAL); } static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; int ret; - static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; char hostname[1024], proto[10]; char lower_url[100]; const char *lower_proto = "tcp"; - int port, new_location; - s->chunked_post = 1; + int port; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); if (!strcmp(proto, "https")) lower_proto = "tls"; ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port, NULL); - av_dict_set(options, "listen", "1", 0); + if ((ret = av_dict_set_int(options, "listen", s->listen, 0)) < 0) + goto fail; if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options)) < 0) goto fail; - if ((ret = http_read_header(h, &new_location)) < 0) - goto fail; - if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) - goto fail; - return 0; - + s->handshake_step = LOWER_PROTO; + if (s->listen == HTTP_SINGLE) { /* single client */ + s->reply_code = 200; + while ((ret = http_handshake(h)) > 0); + } fail: - handle_http_errors(h, ret); av_dict_free(&s->chained_options); return ret; } @@ -368,9 +484,16 @@ static int http_open(URLContext *h, const char *uri, int flags, if (s->headers) { int len = strlen(s->headers); - if (len < 2 || strcmp("\r\n", s->headers + len - 2)) + if (len < 2 || strcmp("\r\n", s->headers + len - 2)) { av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n"); + ret = av_reallocp(&s->headers, len + 3); + if (ret < 0) + return ret; + s->headers[len] = '\r'; + s->headers[len + 1] = '\n'; + s->headers[len + 2] = '\0'; + } } if (s->listen) { @@ -382,6 +505,26 @@ static int http_open(URLContext *h, const char *uri, int flags, return ret; } +static int http_accept(URLContext *s, URLContext **c) +{ + int ret; + HTTPContext *sc = s->priv_data; + HTTPContext *cc; + URLContext *sl = sc->hd; + URLContext *cl = NULL; + + av_assert0(sc->listen); + if ((ret = ffurl_alloc(c, s->filename, s->flags, &sl->interrupt_callback)) < 0) + goto fail; + cc = (*c)->priv_data; + if ((ret = ffurl_accept(sl, &cl)) < 0) + goto fail; + cc->hd = cl; + cc->is_multi_client = 1; +fail: + return ret; +} + static int http_getc(HTTPContext *s) { int len; @@ -576,10 +719,10 @@ static int process_line(URLContext *h, char *line, int line_count, p = line; if (line_count == 0) { - if (s->listen) { + if (s->is_connected_server) { // HTTP method method = p; - while (!av_isspace(*p)) + while (*p && !av_isspace(*p)) p++; *(p++) = '\0'; av_log(h, AV_LOG_TRACE, "Received method: %s\n", method); @@ -597,6 +740,8 @@ static int process_line(URLContext *h, char *line, int line_count, "(%s autodetected %s received)\n", auto_method, method); return ff_http_averror(400, AVERROR(EIO)); } + if (!(s->method = av_strdup(method))) + return AVERROR(ENOMEM); } // HTTP resource @@ -607,12 +752,14 @@ static int process_line(URLContext *h, char *line, int line_count, p++; *(p++) = '\0'; av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource); + if (!(s->resource = av_strdup(resource))) + return AVERROR(ENOMEM); // HTTP version while (av_isspace(*p)) p++; version = p; - while (!av_isspace(*p)) + while (*p && !av_isspace(*p)) p++; *p = '\0'; if (av_strncasecmp(version, "HTTP/", 5)) { @@ -1102,16 +1249,25 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) return http_buf_read_compressed(h, buf, size); #endif /* CONFIG_ZLIB */ read_ret = http_buf_read(h, buf, size); - if (read_ret < 0 && s->reconnect && !h->is_streamed && s->filesize > 0 && s->off < s->filesize) { - av_log(h, AV_LOG_INFO, "Will reconnect at %"PRId64".\n", s->off); - seek_ret = http_seek_internal(h, s->off, SEEK_SET, 1); - if (seek_ret != s->off) { - av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRId64".\n", s->off); + if ( (read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize) + || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { + int64_t target = h->is_streamed ? 0 : s->off; + + if (s->reconnect_delay > s->reconnect_delay_max) + return AVERROR(EIO); + + av_log(h, AV_LOG_INFO, "Will reconnect at %"PRId64" error=%s.\n", s->off, av_err2str(read_ret)); + av_usleep(1000U*1000*s->reconnect_delay); + s->reconnect_delay = 1 + 2*s->reconnect_delay; + seek_ret = http_seek_internal(h, target, SEEK_SET, 1); + if (seek_ret != target) { + av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRId64".\n", target); return read_ret; } read_ret = http_buf_read(h, buf, size); - } + } else + s->reconnect_delay = 0; return read_ret; } @@ -1288,7 +1444,7 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo ((whence == SEEK_CUR && off == 0) || (whence == SEEK_SET && off == s->off))) return s->off; - else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed) + else if ((s->filesize == -1 && whence == SEEK_END)) return AVERROR(ENOSYS); if (whence == SEEK_CUR) @@ -1301,6 +1457,9 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo return AVERROR(EINVAL); s->off = off; + if (s->off && h->is_streamed) + return AVERROR(ENOSYS); + /* we save the old context in case the seek fails */ old_buf_size = s->buf_end - s->buf_ptr; memcpy(old_buf, s->buf_ptr, old_buf_size); @@ -1346,6 +1505,8 @@ HTTP_CLASS(http); URLProtocol ff_http_protocol = { .name = "http", .url_open2 = http_open, + .url_accept = http_accept, + .url_handshake = http_handshake, .url_read = http_read, .url_write = http_write, .url_seek = http_seek, diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.c b/chromium/third_party/ffmpeg/libavformat/id3v2.c index 2289bfc15a7..addf937afd2 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.c +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.c @@ -535,6 +535,13 @@ static void free_apic(void *obj) av_freep(&apic); } +static void rstrip_spaces(char *buf) +{ + size_t len = strlen(buf); + while (len > 0 && buf[len - 1] == ' ') + buf[--len] = 0; +} + static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ID3v2ExtraMeta **extra_meta, int isv34) @@ -598,16 +605,20 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, goto fail; } - apic->buf = av_buffer_alloc(taglen + FF_INPUT_BUFFER_PADDING_SIZE); + apic->buf = av_buffer_alloc(taglen + AV_INPUT_BUFFER_PADDING_SIZE); if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen) goto fail; - memset(apic->buf->data + taglen, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(apic->buf->data + taglen, 0, AV_INPUT_BUFFER_PADDING_SIZE); new_extra->tag = "APIC"; new_extra->data = apic; new_extra->next = *extra_meta; *extra_meta = new_extra; + // The description must be unique, and some ID3v2 tag writers add spaces + // to write several APIC entries with the same description. + rstrip_spaces(apic->description); + return; fail: @@ -1083,6 +1094,9 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = apic->id; + if (AV_RB64(apic->buf->data) == 0x89504e470d0a1a0a) + st->codec->codec_id = AV_CODEC_ID_PNG; + if (apic->description[0]) av_dict_set(&st->metadata, "title", apic->description, 0); @@ -1091,7 +1105,7 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) av_init_packet(&st->attached_pic); st->attached_pic.buf = apic->buf; st->attached_pic.data = apic->buf->data; - st->attached_pic.size = apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE; + st->attached_pic.size = apic->buf->size - AV_INPUT_BUFFER_PADDING_SIZE; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; diff --git a/chromium/third_party/ffmpeg/libavformat/iff.c b/chromium/third_party/ffmpeg/libavformat/iff.c index 7235bc1c9c1..8ea3b38ac62 100644 --- a/chromium/third_party/ffmpeg/libavformat/iff.c +++ b/chromium/third_party/ffmpeg/libavformat/iff.c @@ -455,7 +455,7 @@ static int iff_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE; - st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) @@ -682,7 +682,7 @@ static int iff_read_header(AVFormatContext *s) if (!st->codec->extradata) { st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE; - st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); } diff --git a/chromium/third_party/ffmpeg/libavformat/img2.c b/chromium/third_party/ffmpeg/libavformat/img2.c index cf8a47856f7..50352b53b20 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2.c +++ b/chromium/third_party/ffmpeg/libavformat/img2.c @@ -22,13 +22,9 @@ #include "libavutil/avstring.h" #include "internal.h" +#include "img2.h" -typedef struct IdStrMap { - enum AVCodecID id; - const char *str; -} IdStrMap; - -static const IdStrMap img_tags[] = { +const IdStrMap ff_img_tags[] = { { AV_CODEC_ID_MJPEG, "jpeg" }, { AV_CODEC_ID_MJPEG, "jpg" }, { AV_CODEC_ID_MJPEG, "jps" }, @@ -45,6 +41,7 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_PBM, "pbm" }, { AV_CODEC_ID_PAM, "pam" }, { AV_CODEC_ID_ALIAS_PIX, "pix" }, + { AV_CODEC_ID_DDS, "dds" }, { AV_CODEC_ID_MPEG1VIDEO, "mpg1-img" }, { AV_CODEC_ID_MPEG2VIDEO, "mpg2-img" }, { AV_CODEC_ID_MPEG4, "mpg4-img" }, @@ -102,5 +99,5 @@ static enum AVCodecID av_str2id(const IdStrMap *tags, const char *str) enum AVCodecID ff_guess_image2_codec(const char *filename) { - return av_str2id(img_tags, filename); + return av_str2id(ff_img_tags, filename); } diff --git a/chromium/third_party/ffmpeg/libavformat/img2.h b/chromium/third_party/ffmpeg/libavformat/img2.h index f6b9dd92205..deebcc34a76 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2.h +++ b/chromium/third_party/ffmpeg/libavformat/img2.h @@ -62,6 +62,13 @@ typedef struct VideoDemuxData { int ts_from_file; } VideoDemuxData; +typedef struct IdStrMap { + enum AVCodecID id; + const char *str; +} IdStrMap; + +extern const IdStrMap ff_img_tags[]; + extern const AVOption ff_img_options[]; int ff_img_read_header(AVFormatContext *s1); diff --git a/chromium/third_party/ffmpeg/libavformat/img2dec.c b/chromium/third_party/ffmpeg/libavformat/img2dec.c index 0830f0073c7..70f0b09f180 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/img2dec.c @@ -609,6 +609,17 @@ static int bmp_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION / 4; } +static int dds_probe(AVProbeData *p) +{ + const uint8_t *b = p->buf; + + if ( AV_RB64(b) == 0x444453207c000000 + && AV_RL32(b + 8) + && AV_RL32(b + 12)) + return AVPROBE_SCORE_MAX - 1; + return 0; +} + static int dpx_probe(AVProbeData *p) { const uint8_t *b = p->buf; @@ -649,18 +660,14 @@ static int j2k_probe(AVProbeData *p) static int jpeg_probe(AVProbeData *p) { const uint8_t *b = p->buf; - int i, state = 0xD8, exif_size = 0; + int i, state = 0xD8; if (AV_RB16(b) != 0xFFD8 || AV_RB32(b) == 0xFFD8FFF7) return 0; b += 2; - if (AV_RB16(b) == 0xFFE1 && AV_RB32(b + 4) == AV_RB32("Exif")) { - exif_size = AV_RB16(b + 2) + 2; - b += exif_size; - } - for (i = 0; i + exif_size < p->buf_size - 2; i++) { + for (i = 0; i < p->buf_size - 3; i++) { int c; if (b[i] != 0xFF) continue; @@ -689,6 +696,24 @@ static int jpeg_probe(AVProbeData *p) return 0; state = 0xD9; break; + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + i += AV_RB16(&b[i + 2]) + 1; + break; default: if ( (c >= 0x02 && c <= 0xBF) || c == 0xC8) @@ -714,9 +739,15 @@ static int qdraw_probe(AVProbeData *p) { const uint8_t *b = p->buf; - if (!b[10] && AV_RB32(b+11) == 0x1102ff0c && !b[15] || - p->buf_size >= 528 && !b[522] && AV_RB32(b+523) == 0x1102ff0c && !b[527]) - return AVPROBE_SCORE_EXTENSION + 1; + if ( p->buf_size >= 528 + && (AV_RB64(b + 520) & 0xFFFFFFFFFFFF) == 0x001102ff0c00 + && AV_RB16(b + 520) + && AV_RB16(b + 518)) + return AVPROBE_SCORE_MAX * 3 / 4; + if ( (AV_RB64(b + 8) & 0xFFFFFFFFFFFF) == 0x001102ff0c00 + && AV_RB16(b + 8) + && AV_RB16(b + 6)) + return AVPROBE_SCORE_EXTENSION / 4; return 0; } @@ -799,6 +830,7 @@ AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\ }; IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP) +IMAGEAUTO_DEMUXER(dds, AV_CODEC_ID_DDS) IMAGEAUTO_DEMUXER(dpx, AV_CODEC_ID_DPX) IMAGEAUTO_DEMUXER(exr, AV_CODEC_ID_EXR) IMAGEAUTO_DEMUXER(j2k, AV_CODEC_ID_JPEG2000) diff --git a/chromium/third_party/ffmpeg/libavformat/img2enc.c b/chromium/third_party/ffmpeg/libavformat/img2enc.c index f56c39e6d36..48454fe1d20 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2enc.c +++ b/chromium/third_party/ffmpeg/libavformat/img2enc.c @@ -30,6 +30,7 @@ #include "avformat.h" #include "avio_internal.h" #include "internal.h" +#include "img2.h" typedef struct VideoMuxData { const AVClass *class; /**< Class for private options. */ @@ -116,7 +117,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) if (img->split_planes) { int ysize = codec->width * codec->height; int usize = FF_CEIL_RSHIFT(codec->width, desc->log2_chroma_w) * FF_CEIL_RSHIFT(codec->height, desc->log2_chroma_h); - if (desc->comp[0].depth_minus1 >= 8) { + if (desc->comp[0].depth >= 9) { ysize *= 2; usize *= 2; } @@ -172,6 +173,17 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) return 0; } +static int query_codec(enum AVCodecID id, int std_compliance) +{ + int i; + for (i = 0; ff_img_tags[i].id != AV_CODEC_ID_NONE; i++) + if (ff_img_tags[i].id == id) + return 1; + + // Anything really can be stored in img2 + return std_compliance < FF_COMPLIANCE_NORMAL; +} + #define OFFSET(x) offsetof(VideoMuxData, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption muxoptions[] = { @@ -200,6 +212,7 @@ AVOutputFormat ff_image2_muxer = { .video_codec = AV_CODEC_ID_MJPEG, .write_header = write_header, .write_packet = write_packet, + .query_codec = query_codec, .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS | AVFMT_NOFILE, .priv_class = &img2mux_class, }; @@ -212,6 +225,7 @@ AVOutputFormat ff_image2pipe_muxer = { .video_codec = AV_CODEC_ID_MJPEG, .write_header = write_header, .write_packet = write_packet, + .query_codec = query_codec, .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS }; #endif diff --git a/chromium/third_party/ffmpeg/libavformat/internal.h b/chromium/third_party/ffmpeg/libavformat/internal.h index f90df902421..bd8a0bcf8a9 100644 --- a/chromium/third_party/ffmpeg/libavformat/internal.h +++ b/chromium/third_party/ffmpeg/libavformat/internal.h @@ -31,6 +31,8 @@ #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1 << 20) +#define MAX_PROBE_PACKETS 2500 + #ifdef DEBUG # define hex_dump_debug(class, buf, size) av_hex_dump_log(class, AV_LOG_DEBUG, buf, size) #else @@ -47,6 +49,18 @@ typedef struct CodecMime{ enum AVCodecID id; } CodecMime; +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/** + * The exact value of the fractional number is: 'val + num / den'. + * num is assumed to be 0 <= num < den. + */ +typedef struct FFFrac { + int64_t val, num, den; +} FFFrac; + + struct AVFormatInternal { /** * Number of streams relevant for interleaving. @@ -254,6 +268,8 @@ int ff_add_index_entry(AVIndexEntry **index_entries, unsigned int *index_entries_allocated_size, int64_t pos, int64_t timestamp, int size, int distance, int flags); +void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance); + /** * Add a new chapter. * @@ -447,7 +463,7 @@ uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type, int size); /** - * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end + * Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end * which is always set to 0. * * @param size size of extradata @@ -456,7 +472,7 @@ uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type, int ff_alloc_extradata(AVCodecContext *avctx, int size); /** - * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end + * Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end * which is always set to 0 and fill it from pb. * * @param size size of extradata diff --git a/chromium/third_party/ffmpeg/libavformat/ipmovie.c b/chromium/third_party/ffmpeg/libavformat/ipmovie.c index af518b59d3d..51aed323a24 100644 --- a/chromium/third_party/ffmpeg/libavformat/ipmovie.c +++ b/chromium/third_party/ffmpeg/libavformat/ipmovie.c @@ -78,7 +78,7 @@ #define PALETTE_COUNT 256 typedef struct IPMVEContext { - + AVFormatContext *avf; unsigned char *buf; int buf_size; @@ -212,6 +212,31 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, return chunk_type; } +static int init_audio(AVFormatContext *s) +{ + IPMVEContext *ipmovie = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); + ipmovie->audio_stream_index = st->index; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = ipmovie->audio_type; + st->codec->codec_tag = 0; /* no tag */ + st->codec->channels = ipmovie->audio_channels; + st->codec->channel_layout = st->codec->channels == 1 ? AV_CH_LAYOUT_MONO : + AV_CH_LAYOUT_STEREO; + st->codec->sample_rate = ipmovie->audio_sample_rate; + st->codec->bits_per_coded_sample = ipmovie->audio_bits; + st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * + st->codec->bits_per_coded_sample; + if (st->codec->codec_id == AV_CODEC_ID_INTERPLAY_DPCM) + st->codec->bit_rate /= 2; + st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; + + return 0; +} + /* This function loads and processes a single chunk in an IP movie file. * It returns the type of chunk that was processed. */ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, @@ -516,6 +541,9 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, } } + if (s->avf->nb_streams == 1 && s->audio_type) + init_audio(s->avf); + /* make a note of where the stream is sitting */ s->next_chunk_offset = avio_tell(pb); @@ -551,6 +579,8 @@ static int ipmovie_read_header(AVFormatContext *s) int chunk_type, i; uint8_t signature_buffer[sizeof(signature)]; + ipmovie->avf = s; + avio_read(pb, signature_buffer, sizeof(signature_buffer)); while (memcmp(signature_buffer, signature, sizeof(signature))) { memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1); @@ -600,25 +630,9 @@ static int ipmovie_read_header(AVFormatContext *s) st->codec->bits_per_coded_sample = ipmovie->video_bpp; if (ipmovie->audio_type) { - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); - ipmovie->audio_stream_index = st->index; - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = ipmovie->audio_type; - st->codec->codec_tag = 0; /* no tag */ - st->codec->channels = ipmovie->audio_channels; - st->codec->channel_layout = st->codec->channels == 1 ? AV_CH_LAYOUT_MONO : - AV_CH_LAYOUT_STEREO; - st->codec->sample_rate = ipmovie->audio_sample_rate; - st->codec->bits_per_coded_sample = ipmovie->audio_bits; - st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * - st->codec->bits_per_coded_sample; - if (st->codec->codec_id == AV_CODEC_ID_INTERPLAY_DPCM) - st->codec->bit_rate /= 2; - st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; - } + return init_audio(s); + } else + s->ctx_flags |= AVFMTCTX_NOHEADER; return 0; } @@ -643,7 +657,7 @@ static int ipmovie_read_packet(AVFormatContext *s, else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO) continue; else - ret = -1; + continue; return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/isom.c b/chromium/third_party/ffmpeg/libavformat/isom.c index c99f2dc5db1..eff04ff8a22 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.c +++ b/chromium/third_party/ffmpeg/libavformat/isom.c @@ -110,7 +110,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */ { AV_CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */ - { AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */ + { AV_CODEC_ID_AVRN , MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */ /* { AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, *//* MJPEG with alpha-channel (AVID ABVB/Truevision NuVista) */ { AV_CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') }, /* Motion JPEG OpenDML */ { AV_CODEC_ID_MJPEGB, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */ @@ -258,6 +258,13 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_AIC, MKTAG('i', 'c', 'o', 'd') }, + { AV_CODEC_ID_HAP, MKTAG('H', 'a', 'p', '1') }, + { AV_CODEC_ID_HAP, MKTAG('H', 'a', 'p', '5') }, + { AV_CODEC_ID_HAP, MKTAG('H', 'a', 'p', 'Y') }, + + { AV_CODEC_ID_DXV, MKTAG('D', 'X', 'D', '3') }, + { AV_CODEC_ID_DXV, MKTAG('D', 'X', 'D', 'I') }, + { AV_CODEC_ID_NONE, 0 }, }; @@ -447,19 +454,24 @@ static const AVCodecTag mp4_audio_types[] = { int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb) { enum AVCodecID codec_id; + unsigned v; int len, tag; int ret; int object_type_id = avio_r8(pb); avio_r8(pb); /* stream type */ avio_rb24(pb); /* buffer size db */ - avio_rb32(pb); /* max bitrate */ - avio_rb32(pb); /* avg bitrate */ if(avcodec_is_open(st->codec)) { av_log(fc, AV_LOG_DEBUG, "codec open in read_dec_config_descr\n"); return -1; } + v = avio_rb32(pb); + if (v < INT32_MAX) + st->codec->rc_max_rate = v; + + st->codec->bit_rate = avio_rb32(pb); /* avg bitrate */ + codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); if (codec_id) st->codec->codec_id= codec_id; diff --git a/chromium/third_party/ffmpeg/libavformat/isom.h b/chromium/third_party/ffmpeg/libavformat/isom.h index 5d48989fd90..aee9d6e8c79 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.h +++ b/chromium/third_party/ffmpeg/libavformat/isom.h @@ -198,6 +198,14 @@ typedef struct MOVContext { MOVFragmentIndex** fragment_index_data; unsigned fragment_index_count; int atom_depth; + unsigned int aax_mode; ///< 'aax' file has been detected + uint8_t file_key[20]; + uint8_t file_iv[20]; + void *activation_bytes; + int activation_bytes_size; + void *audible_fixed_key; + int audible_fixed_key_size; + struct AVAES *aes_decrypt; } MOVContext; int ff_mp4_read_descr_len(AVIOContext *pb); diff --git a/chromium/third_party/ffmpeg/libavformat/ivfenc.c b/chromium/third_party/ffmpeg/libavformat/ivfenc.c index 1d76c5c7cb7..2053c509f9f 100644 --- a/chromium/third_party/ffmpeg/libavformat/ivfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/ivfenc.c @@ -20,6 +20,11 @@ #include "avformat.h" #include "libavutil/intreadwrite.h" +typedef struct IVFEncContext { + unsigned frame_cnt; + uint64_t last_pts, sum_delta_pts; +} IVFEncContext; + static int ivf_write_header(AVFormatContext *s) { AVCodecContext *ctx; @@ -43,7 +48,7 @@ static int ivf_write_header(AVFormatContext *s) avio_wl16(pb, ctx->height); avio_wl32(pb, s->streams[0]->time_base.den); avio_wl32(pb, s->streams[0]->time_base.num); - avio_wl64(pb, s->streams[0]->duration); // TODO: duration or number of frames?!? + avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL); return 0; } @@ -51,14 +56,36 @@ static int ivf_write_header(AVFormatContext *s) static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; + IVFEncContext *ctx = s->priv_data; + avio_wl32(pb, pkt->size); avio_wl64(pb, pkt->pts); avio_write(pb, pkt->data, pkt->size); + if (ctx->frame_cnt) + ctx->sum_delta_pts += pkt->pts - ctx->last_pts; + ctx->frame_cnt++; + ctx->last_pts = pkt->pts; + + return 0; +} + +static int ivf_write_trailer(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + if (pb->seekable) { + IVFEncContext *ctx = s->priv_data; + size_t end = avio_tell(pb); + + avio_seek(pb, 24, SEEK_SET); + avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1)); + avio_seek(pb, end, SEEK_SET); + } return 0; } AVOutputFormat ff_ivf_muxer = { + .priv_data_size = sizeof(IVFEncContext), .name = "ivf", .long_name = NULL_IF_CONFIG_SMALL("On2 IVF"), .extensions = "ivf", @@ -66,4 +93,5 @@ AVOutputFormat ff_ivf_muxer = { .video_codec = AV_CODEC_ID_VP8, .write_header = ivf_write_header, .write_packet = ivf_write_packet, + .write_trailer = ivf_write_trailer, }; diff --git a/chromium/third_party/ffmpeg/libavformat/jacosubdec.c b/chromium/third_party/ffmpeg/libavformat/jacosubdec.c index 1ca00558774..5e543634fd3 100644 --- a/chromium/third_party/ffmpeg/libavformat/jacosubdec.c +++ b/chromium/third_party/ffmpeg/libavformat/jacosubdec.c @@ -172,7 +172,7 @@ static int jacosub_read_header(AVFormatContext *s) jacosub->timeres = 30; - av_bprint_init(&header, 1024+FF_INPUT_BUFFER_PADDING_SIZE, 4096); + av_bprint_init(&header, 1024+AV_INPUT_BUFFER_PADDING_SIZE, 4096); while (!avio_feof(pb)) { int cmd_len; @@ -240,7 +240,7 @@ static int jacosub_read_header(AVFormatContext *s) AVPacket *sub = &jacosub->q.subs[i]; read_ts(jacosub, sub->data, &sub->pts, &sub->duration); } - ff_subtitles_queue_finalize(&jacosub->q); + ff_subtitles_queue_finalize(s, &jacosub->q); return 0; fail: diff --git a/chromium/third_party/ffmpeg/libavformat/jvdec.c b/chromium/third_party/ffmpeg/libavformat/jvdec.c index 64d31e0ee69..4d4f0c78c53 100644 --- a/chromium/third_party/ffmpeg/libavformat/jvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/jvdec.c @@ -196,7 +196,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return ret; if (ret < size) { memset(pkt->data + JV_PREAMBLE_SIZE + ret, 0, - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); pkt->flags |= AV_PKT_FLAG_CORRUPT; } pkt->size = ret + JV_PREAMBLE_SIZE; diff --git a/chromium/third_party/ffmpeg/libavformat/latmenc.c b/chromium/third_party/ffmpeg/libavformat/latmenc.c index 17dbf33b721..db6977e5853 100644 --- a/chromium/third_party/ffmpeg/libavformat/latmenc.c +++ b/chromium/third_party/ffmpeg/libavformat/latmenc.c @@ -124,7 +124,8 @@ static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs) if (!ctx->channel_conf) { GetBitContext gb; - init_get_bits8(&gb, avctx->extradata, avctx->extradata_size); + int ret = init_get_bits8(&gb, avctx->extradata, avctx->extradata_size); + av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail skip_bits_long(&gb, ctx->off + 3); avpriv_copy_pce_data(bs, &gb); } diff --git a/chromium/third_party/ffmpeg/libavformat/libsmbclient.c b/chromium/third_party/ffmpeg/libavformat/libsmbclient.c index 1af8163674c..84fef7f1620 100644 --- a/chromium/third_party/ffmpeg/libavformat/libsmbclient.c +++ b/chromium/third_party/ffmpeg/libavformat/libsmbclient.c @@ -287,6 +287,67 @@ static int libsmbc_close_dir(URLContext *h) return 0; } +static int libsmbc_delete(URLContext *h) +{ + LIBSMBContext *libsmbc = h->priv_data; + int ret; + struct stat st; + + if ((ret = libsmbc_connect(h)) < 0) + goto cleanup; + + if ((libsmbc->fd = smbc_open(h->filename, O_WRONLY, 0666)) < 0) { + ret = AVERROR(errno); + goto cleanup; + } + + if (smbc_fstat(libsmbc->fd, &st) < 0) { + ret = AVERROR(errno); + goto cleanup; + } + + smbc_close(libsmbc->fd); + libsmbc->fd = -1; + + if (S_ISDIR(st.st_mode)) { + if (smbc_rmdir(h->filename) < 0) { + ret = AVERROR(errno); + goto cleanup; + } + } else { + if (smbc_unlink(h->filename) < 0) { + ret = AVERROR(errno); + goto cleanup; + } + } + + ret = 0; + +cleanup: + libsmbc_close(h); + return ret; +} + +static int libsmbc_move(URLContext *h_src, URLContext *h_dst) +{ + LIBSMBContext *libsmbc = h_src->priv_data; + int ret; + + if ((ret = libsmbc_connect(h_src)) < 0) + goto cleanup; + + if ((libsmbc->dh = smbc_rename(h_src->filename, h_dst->filename)) < 0) { + ret = AVERROR(errno); + goto cleanup; + } + + ret = 0; + +cleanup: + libsmbc_close(h_src); + return ret; +} + #define OFFSET(x) offsetof(LIBSMBContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM @@ -311,6 +372,8 @@ URLProtocol ff_libsmbclient_protocol = { .url_write = libsmbc_write, .url_seek = libsmbc_seek, .url_close = libsmbc_close, + .url_delete = libsmbc_delete, + .url_move = libsmbc_move, .url_open_dir = libsmbc_open_dir, .url_read_dir = libsmbc_read_dir, .url_close_dir = libsmbc_close_dir, diff --git a/chromium/third_party/ffmpeg/libavformat/libssh.c b/chromium/third_party/ffmpeg/libavformat/libssh.c index fac6114210c..3c056f874ad 100644 --- a/chromium/third_party/ffmpeg/libavformat/libssh.c +++ b/chromium/third_party/ffmpeg/libavformat/libssh.c @@ -24,6 +24,7 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/attributes.h" +#include "libavformat/avio.h" #include "avformat.h" #include "internal.h" #include "url.h" @@ -33,6 +34,7 @@ typedef struct { ssh_session session; sftp_session sftp; sftp_file file; + sftp_dir dir; int64_t filesize; int rw_timeout; int trunc; @@ -187,11 +189,11 @@ static av_cold int libssh_close(URLContext *h) return 0; } -static av_cold int libssh_open(URLContext *h, const char *url, int flags) +static av_cold int libssh_connect(URLContext *h, const char *url, char *path, size_t path_size) { LIBSSHContext *libssh = h->priv_data; - char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024]; - int port, ret; + char proto[10], hostname[1024], credencials[1024]; + int port = 22, ret; const char *user = NULL, *pass = NULL; char *end = NULL; @@ -199,23 +201,38 @@ static av_cold int libssh_open(URLContext *h, const char *url, int flags) credencials, sizeof(credencials), hostname, sizeof(hostname), &port, - path, sizeof(path), + path, path_size, url); + if (!(*path)) + av_strlcpy(path, "/", path_size); + // a port of 0 will use a port from ~/.ssh/config or the default value 22 if (port < 0 || port > 65535) port = 0; if ((ret = libssh_create_ssh_session(libssh, hostname, port)) < 0) - goto fail; + return ret; user = av_strtok(credencials, ":", &end); pass = av_strtok(end, ":", &end); if ((ret = libssh_authentication(libssh, user, pass)) < 0) - goto fail; + return ret; if ((ret = libssh_create_sftp_session(libssh)) < 0) + return ret; + + return 0; +} + +static av_cold int libssh_open(URLContext *h, const char *url, int flags) +{ + int ret; + LIBSSHContext *libssh = h->priv_data; + char path[MAX_URL_SIZE]; + + if ((ret = libssh_connect(h, url, path, sizeof(path))) < 0) goto fail; if ((ret = libssh_open_file(libssh, flags, path)) < 0) @@ -293,6 +310,168 @@ static int libssh_write(URLContext *h, const unsigned char *buf, int size) return bytes_written; } +static int libssh_open_dir(URLContext *h) +{ + LIBSSHContext *libssh = h->priv_data; + int ret; + char path[MAX_URL_SIZE]; + + if ((ret = libssh_connect(h, h->filename, path, sizeof(path))) < 0) + goto fail; + + if (!(libssh->dir = sftp_opendir(libssh->sftp, path))) { + av_log(libssh, AV_LOG_ERROR, "Error opening sftp dir: %s\n", ssh_get_error(libssh->session)); + ret = AVERROR(EIO); + goto fail; + } + + return 0; + + fail: + libssh_close(h); + return ret; +} + +static int libssh_read_dir(URLContext *h, AVIODirEntry **next) +{ + LIBSSHContext *libssh = h->priv_data; + sftp_attributes attr = NULL; + AVIODirEntry *entry; + + *next = entry = ff_alloc_dir_entry(); + if (!entry) + return AVERROR(ENOMEM); + + do { + if (attr) + sftp_attributes_free(attr); + attr = sftp_readdir(libssh->sftp, libssh->dir); + if (!attr) { + av_freep(next); + if (sftp_dir_eof(libssh->dir)) + return 0; + return AVERROR(EIO); + } + } while (!strcmp(attr->name, ".") || !strcmp(attr->name, "..")); + + entry->name = av_strdup(attr->name); + entry->group_id = attr->gid; + entry->user_id = attr->uid; + entry->size = attr->size; + entry->access_timestamp = INT64_C(1000000) * attr->atime; + entry->modification_timestamp = INT64_C(1000000) * attr->mtime; + entry->filemode = attr->permissions & 0777; + switch(attr->type) { + case SSH_FILEXFER_TYPE_REGULAR: + entry->type = AVIO_ENTRY_FILE; + break; + case SSH_FILEXFER_TYPE_DIRECTORY: + entry->type = AVIO_ENTRY_DIRECTORY; + break; + case SSH_FILEXFER_TYPE_SYMLINK: + entry->type = AVIO_ENTRY_SYMBOLIC_LINK; + break; + case SSH_FILEXFER_TYPE_SPECIAL: + /* Special type includes: sockets, char devices, block devices and pipes. + It is probably better to return unknown type, to not confuse anybody. */ + case SSH_FILEXFER_TYPE_UNKNOWN: + default: + entry->type = AVIO_ENTRY_UNKNOWN; + } + sftp_attributes_free(attr); + return 0; +} + +static int libssh_close_dir(URLContext *h) +{ + LIBSSHContext *libssh = h->priv_data; + if (libssh->dir) + sftp_closedir(libssh->dir); + libssh->dir = NULL; + libssh_close(h); + return 0; +} + +static int libssh_delete(URLContext *h) +{ + int ret; + LIBSSHContext *libssh = h->priv_data; + sftp_attributes attr = NULL; + char path[MAX_URL_SIZE]; + + if ((ret = libssh_connect(h, h->filename, path, sizeof(path))) < 0) + goto cleanup; + + if (!(attr = sftp_stat(libssh->sftp, path))) { + ret = AVERROR(sftp_get_error(libssh->sftp)); + goto cleanup; + } + + if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) { + if (sftp_rmdir(libssh->sftp, path) < 0) { + ret = AVERROR(sftp_get_error(libssh->sftp)); + goto cleanup; + } + } else { + if (sftp_unlink(libssh->sftp, path) < 0) { + ret = AVERROR(sftp_get_error(libssh->sftp)); + goto cleanup; + } + } + + ret = 0; + +cleanup: + if (attr) + sftp_attributes_free(attr); + libssh_close(h); + return ret; +} + +static int libssh_move(URLContext *h_src, URLContext *h_dst) +{ + int ret; + LIBSSHContext *libssh = h_src->priv_data; + char path_src[MAX_URL_SIZE], path_dst[MAX_URL_SIZE]; + char hostname_src[1024], hostname_dst[1024]; + char credentials_src[1024], credentials_dst[1024]; + int port_src = 22, port_dst = 22; + + av_url_split(NULL, 0, + credentials_src, sizeof(credentials_src), + hostname_src, sizeof(hostname_src), + &port_src, + path_src, sizeof(path_src), + h_src->filename); + + av_url_split(NULL, 0, + credentials_dst, sizeof(credentials_dst), + hostname_dst, sizeof(hostname_dst), + &port_dst, + path_dst, sizeof(path_dst), + h_dst->filename); + + if (strcmp(credentials_src, credentials_dst) || + strcmp(hostname_src, hostname_dst) || + port_src != port_dst) { + return AVERROR(EINVAL); + } + + if ((ret = libssh_connect(h_src, h_src->filename, path_src, sizeof(path_src))) < 0) + goto cleanup; + + if (sftp_rename(libssh->sftp, path_src, path_dst) < 0) { + ret = AVERROR(sftp_get_error(libssh->sftp)); + goto cleanup; + } + + ret = 0; + +cleanup: + libssh_close(h_src); + return ret; +} + #define OFFSET(x) offsetof(LIBSSHContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM @@ -317,6 +496,11 @@ URLProtocol ff_libssh_protocol = { .url_write = libssh_write, .url_seek = libssh_seek, .url_close = libssh_close, + .url_delete = libssh_delete, + .url_move = libssh_move, + .url_open_dir = libssh_open_dir, + .url_read_dir = libssh_read_dir, + .url_close_dir = libssh_close_dir, .priv_data_size = sizeof(LIBSSHContext), .priv_data_class = &libssh_context_class, .flags = URL_PROTOCOL_FLAG_NETWORK, diff --git a/chromium/third_party/ffmpeg/libavformat/lrcdec.c b/chromium/third_party/ffmpeg/libavformat/lrcdec.c index df61853d2b2..d3655fccd50 100644 --- a/chromium/third_party/ffmpeg/libavformat/lrcdec.c +++ b/chromium/third_party/ffmpeg/libavformat/lrcdec.c @@ -210,7 +210,7 @@ static int lrc_read_header(AVFormatContext *s) } } } - ff_subtitles_queue_finalize(&lrc->q); + ff_subtitles_queue_finalize(s, &lrc->q); ff_metadata_conv_ctx(s, NULL, ff_lrc_metadata_conv); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/matroskadec.c b/chromium/third_party/ffmpeg/libavformat/matroskadec.c index 3edde1ec34d..756e49c2b9b 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskadec.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskadec.c @@ -812,7 +812,7 @@ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num) /* big-endian ordering; build up number */ while (n++ < size) - *num = (*num << 8) | avio_r8(pb); + *num = ((uint64_t)*num << 8) | avio_r8(pb); } return 0; @@ -1798,7 +1798,7 @@ static int matroska_parse_tracks(AVFormatContext *s) ffio_init_context(&b, track->codec_priv.data, track->codec_priv.size, 0, NULL, NULL, NULL, NULL); - ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size, 0); + ret = ff_get_wav_header(s, &b, st->codec, track->codec_priv.size, 0); if (ret < 0) return ret; codec_id = st->codec->codec_id; @@ -1859,7 +1859,7 @@ static int matroska_parse_tracks(AVFormatContext *s) } else if (codec_id == AV_CODEC_ID_AAC && !track->codec_priv.size) { int profile = matroska_aac_profile(track->codec_id); int sri = matroska_aac_sri(track->audio.samplerate); - extradata = av_mallocz(5 + FF_INPUT_BUFFER_PADDING_SIZE); + extradata = av_mallocz(5 + AV_INPUT_BUFFER_PADDING_SIZE); if (!extradata) return AVERROR(ENOMEM); extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1); @@ -1872,13 +1872,13 @@ static int matroska_parse_tracks(AVFormatContext *s) extradata_size = 5; } else extradata_size = 2; - } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) { + } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - AV_INPUT_BUFFER_PADDING_SIZE) { /* Only ALAC's magic cookie is stored in Matroska's track headers. * Create the "atom size", "tag", and "tag version" fields the * decoder expects manually. */ extradata_size = 12 + track->codec_priv.size; extradata = av_mallocz(extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!extradata) return AVERROR(ENOMEM); AV_WB32(extradata, extradata_size); @@ -1888,7 +1888,7 @@ static int matroska_parse_tracks(AVFormatContext *s) track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { extradata_size = 30; - extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!extradata) return AVERROR(ENOMEM); ffio_init_context(&b, extradata, extradata_size, 1, @@ -2077,7 +2077,9 @@ static int matroska_parse_tracks(AVFormatContext *s) st->codec->channels = track->audio.channels; if (!st->codec->bits_per_coded_sample) st->codec->bits_per_coded_sample = track->audio.bitdepth; - if (st->codec->codec_id != AV_CODEC_ID_AAC) + if (st->codec->codec_id == AV_CODEC_ID_MP3) + st->need_parsing = AVSTREAM_PARSE_FULL; + else if (st->codec->codec_id != AV_CODEC_ID_AAC) st->need_parsing = AVSTREAM_PARSE_HEADERS; if (track->codec_delay > 0) { st->codec->delay = av_rescale_q(track->codec_delay, diff --git a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c index 3b525ad4d4d..2b2d034e00c 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c @@ -44,6 +44,7 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" +#include "libavutil/rational.h" #include "libavutil/samplefmt.h" #include "libavutil/sha.h" #include "libavutil/stereo3d.h" @@ -131,6 +132,9 @@ typedef struct MatroskaMuxContext { int64_t last_track_timestamp[MAX_TRACKS]; + int64_t* stream_durations; + int64_t* stream_duration_offsets; + int allow_raw_vfw; } MatroskaMuxContext; @@ -305,6 +309,23 @@ static void put_xiph_size(AVIOContext *pb, int size) } /** + * Free the members allocated in the mux context. + */ +static void mkv_free(MatroskaMuxContext *mkv) { + if (mkv->main_seekhead) { + av_freep(&mkv->main_seekhead->entries); + av_freep(&mkv->main_seekhead); + } + if (mkv->cues) { + av_freep(&mkv->cues->entries); + av_freep(&mkv->cues); + } + av_freep(&mkv->tracks); + av_freep(&mkv->stream_durations); + av_freep(&mkv->stream_duration_offsets); +} + +/** * Initialize a mkv_seekhead element to be ready to index level 1 Matroska * elements. If a maximum number of elements is specified, enough space * will be reserved at the current file location to write a seek head of @@ -364,8 +385,9 @@ static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid * @return The file offset where the seekhead was written, * -1 if an error occurred. */ -static int64_t mkv_write_seekhead(AVIOContext *pb, mkv_seekhead *seekhead) +static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv) { + mkv_seekhead *seekhead = mkv->main_seekhead; ebml_master metaseek, seekentry; int64_t currentpos; int i; @@ -402,8 +424,8 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, mkv_seekhead *seekhead) currentpos = seekhead->filepos; } fail: - av_freep(&seekhead->entries); - av_free(seekhead); + av_freep(&mkv->main_seekhead->entries); + av_freep(&mkv->main_seekhead); return currentpos; } @@ -1151,12 +1173,12 @@ static int mkv_write_simpletag(AVIOContext *pb, AVDictionaryEntry *t) return 0; } -static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, - unsigned int uid, ebml_master *tags) +static int mkv_write_tag_targets(AVFormatContext *s, + unsigned int elementid, unsigned int uid, + ebml_master *tags, ebml_master* tag) { MatroskaMuxContext *mkv = s->priv_data; - ebml_master tag, targets; - AVDictionaryEntry *t = NULL; + ebml_master targets; int ret; if (!tags->pos) { @@ -1166,11 +1188,24 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme *tags = start_ebml_master(s->pb, MATROSKA_ID_TAGS, 0); } - tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); + *tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); targets = start_ebml_master(s->pb, MATROSKA_ID_TAGTARGETS, 0); if (elementid) put_ebml_uint(s->pb, elementid, uid); end_ebml_master(s->pb, targets); + return 0; +} + +static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, + unsigned int uid, ebml_master *tags) +{ + ebml_master tag; + int ret; + AVDictionaryEntry *t = NULL; + + ret = mkv_write_tag_targets(s, elementid, uid, tags, &tag); + if (ret < 0) + return ret; while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { if (av_strcasecmp(t->key, "title") && @@ -1220,6 +1255,25 @@ static int mkv_write_tags(AVFormatContext *s) if (ret < 0) return ret; } + if (!mkv->is_live) { + for (i = 0; i < s->nb_streams; i++) { + ebml_master tag_target; + ebml_master tag; + + mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags, &tag_target); + + tag = start_ebml_master(s->pb, MATROSKA_ID_SIMPLETAG, 0); + put_ebml_string(s->pb, MATROSKA_ID_TAGNAME, "DURATION"); + mkv->stream_duration_offsets[i] = avio_tell(s->pb); + + // Reserve space to write duration as a 20-byte string. + // 2 (ebml id) + 1 (data size) + 20 (data) + put_ebml_void(s->pb, 23); + end_ebml_master(s->pb, tag); + end_ebml_master(s->pb, tag_target); + } + } + for (i = 0; i < s->nb_chapters; i++) { AVChapter *ch = s->chapters[i]; @@ -1361,9 +1415,10 @@ static int mkv_write_header(AVFormatContext *s) } mkv->tracks = av_mallocz_array(s->nb_streams, sizeof(*mkv->tracks)); - if (!mkv->tracks) - return AVERROR(ENOMEM); - + if (!mkv->tracks) { + ret = AVERROR(ENOMEM); + goto fail; + } ebml_header = start_ebml_master(pb, EBML_ID_HEADER, 0); put_ebml_uint (pb, EBML_ID_EBMLVERSION , 1); put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1); @@ -1383,11 +1438,13 @@ static int mkv_write_header(AVFormatContext *s) // isn't more than 10 elements if we only write one of each other // currently defined level 1 element mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10); - if (!mkv->main_seekhead) - return AVERROR(ENOMEM); + if (!mkv->main_seekhead) { + ret = AVERROR(ENOMEM); + goto fail; + } ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, avio_tell(pb)); - if (ret < 0) return ret; + if (ret < 0) goto fail; segment_info = start_ebml_master(pb, MATROSKA_ID_INFO, 0); put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); @@ -1430,9 +1487,13 @@ static int mkv_write_header(AVFormatContext *s) } end_ebml_master(pb, segment_info); + // initialize stream_duration fields + mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); + mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); + ret = mkv_write_tracks(s); if (ret < 0) - return ret; + goto fail; for (i = 0; i < s->nb_chapters; i++) mkv->chapter_id_offset = FFMAX(mkv->chapter_id_offset, 1LL - s->chapters[i]->id); @@ -1440,24 +1501,25 @@ static int mkv_write_header(AVFormatContext *s) if (mkv->mode != MODE_WEBM) { ret = mkv_write_chapters(s); if (ret < 0) - return ret; + goto fail; ret = mkv_write_tags(s); if (ret < 0) - return ret; + goto fail; ret = mkv_write_attachments(s); if (ret < 0) - return ret; + goto fail; } if (!s->pb->seekable && !mkv->is_live) - mkv_write_seekhead(pb, mkv->main_seekhead); + mkv_write_seekhead(pb, mkv); mkv->cues = mkv_start_cues(mkv->segment_offset); - if (!mkv->cues) - return AVERROR(ENOMEM); - + if (!mkv->cues) { + ret = AVERROR(ENOMEM); + goto fail; + } if (pb->seekable && mkv->reserve_cues_space) { mkv->cues_pos = avio_tell(pb); put_ebml_void(pb, mkv->reserve_cues_space); @@ -1484,6 +1546,9 @@ static int mkv_write_header(AVFormatContext *s) } return 0; +fail: + mkv_free(mkv); + return ret; } static int mkv_blockgroup_size(int pkt_size) @@ -1772,33 +1837,40 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) { mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe); - if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue) { + if (s->pb->seekable && (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue)) { ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, mkv->cluster_pos, relative_packet_pos, -1); if (ret < 0) return ret; } } else { - if (codec->codec_id == AV_CODEC_ID_WEBVTT) { - duration = mkv_write_vtt_blocks(s, pb, pkt); - } else { - ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, - mkv_blockgroup_size(pkt->size)); - /* For backward compatibility, prefer convergence_duration. */ - if (pkt->convergence_duration > 0) { - duration = pkt->convergence_duration; + if (codec->codec_id == AV_CODEC_ID_WEBVTT) { + duration = mkv_write_vtt_blocks(s, pb, pkt); + } else { + ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, + mkv_blockgroup_size(pkt->size)); + /* For backward compatibility, prefer convergence_duration. */ + if (pkt->convergence_duration > 0) { + duration = pkt->convergence_duration; + } + /* All subtitle blocks are considered to be keyframes. */ + mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 1); + put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration); + end_ebml_master(pb, blockgroup); } - /* All subtitle blocks are considered to be keyframes. */ - mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 1); - put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration); - end_ebml_master(pb, blockgroup); - } - ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, - mkv->cluster_pos, relative_packet_pos, duration); - if (ret < 0) - return ret; + if (s->pb->seekable) { + ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, + mkv->cluster_pos, relative_packet_pos, duration); + if (ret < 0) + return ret; + } } mkv->duration = FFMAX(mkv->duration, ts + duration); + + if (mkv->stream_durations) + mkv->stream_durations[pkt->stream_index] = + FFMAX(mkv->stream_durations[pkt->stream_index], ts + duration); + return 0; } @@ -1968,7 +2040,7 @@ static int mkv_write_trailer(AVFormatContext *s) return ret; } - mkv_write_seekhead(pb, mkv->main_seekhead); + mkv_write_seekhead(pb, mkv); // update the duration av_log(s, AV_LOG_DEBUG, "end duration = %" PRIu64 "\n", mkv->duration); @@ -1976,16 +2048,37 @@ static int mkv_write_trailer(AVFormatContext *s) avio_seek(pb, mkv->duration_offset, SEEK_SET); put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); + // update stream durations + if (mkv->stream_durations) { + int i; + for (i = 0; i < s->nb_streams; ++i) { + AVStream *st = s->streams[i]; + double duration_sec = mkv->stream_durations[i] * av_q2d(st->time_base); + char duration_string[20] = ""; + + av_log(s, AV_LOG_DEBUG, "stream %d end duration = %" PRIu64 "\n", i, + mkv->stream_durations[i]); + + if (!mkv->is_live && mkv->stream_duration_offsets[i] > 0) { + avio_seek(pb, mkv->stream_duration_offsets[i], SEEK_SET); + + snprintf(duration_string, 20, "%02d:%02d:%012.9f", + (int) duration_sec / 3600, ((int) duration_sec / 60) % 60, + fmod(duration_sec, 60)); + + put_ebml_binary(pb, MATROSKA_ID_TAGSTRING, duration_string, 20); + } + } + } + avio_seek(pb, currentpos, SEEK_SET); } if (!mkv->is_live) { end_ebml_master(pb, mkv->segment); } - av_freep(&mkv->tracks); - av_freep(&mkv->cues->entries); - av_freep(&mkv->cues); + mkv_free(mkv); return 0; } @@ -2097,8 +2190,8 @@ AVOutputFormat ff_webm_muxer = { .mime_type = "video/webm", .extensions = "webm", .priv_data_size = sizeof(MatroskaMuxContext), - .audio_codec = AV_CODEC_ID_VORBIS, - .video_codec = AV_CODEC_ID_VP8, + .audio_codec = CONFIG_LIBOPUS_ENCODER ? AV_CODEC_ID_OPUS : AV_CODEC_ID_VORBIS, + .video_codec = CONFIG_LIBVPX_VP9_ENCODER? AV_CODEC_ID_VP9 : AV_CODEC_ID_VP8, .subtitle_codec = AV_CODEC_ID_WEBVTT, .write_header = mkv_write_header, .write_packet = mkv_write_flush_packet, diff --git a/chromium/third_party/ffmpeg/libavformat/md5enc.c b/chromium/third_party/ffmpeg/libavformat/md5enc.c index 8e87f095c99..e1a53684b6f 100644 --- a/chromium/third_party/ffmpeg/libavformat/md5enc.c +++ b/chromium/third_party/ffmpeg/libavformat/md5enc.c @@ -107,7 +107,8 @@ AVOutputFormat ff_md5_muxer = { .write_header = write_header, .write_packet = write_packet, .write_trailer = write_trailer, - .flags = AVFMT_NOTIMESTAMPS, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, .priv_class = &md5enc_class, }; #endif diff --git a/chromium/third_party/ffmpeg/libavformat/microdvddec.c b/chromium/third_party/ffmpeg/libavformat/microdvddec.c index a3839051a45..727ff947e7e 100644 --- a/chromium/third_party/ffmpeg/libavformat/microdvddec.c +++ b/chromium/third_party/ffmpeg/libavformat/microdvddec.c @@ -141,7 +141,7 @@ static int microdvd_read_header(AVFormatContext *s) sub->pts = get_pts(line); sub->duration = get_duration(line); } - ff_subtitles_queue_finalize(µdvd->q); + ff_subtitles_queue_finalize(s, µdvd->q); if (has_real_fps) { /* export the FPS info only if set in the file */ microdvd->frame_rate = pts_info; diff --git a/chromium/third_party/ffmpeg/libavformat/mlvdec.c b/chromium/third_party/ffmpeg/libavformat/mlvdec.c index aa1ba60d37e..48a429eb23a 100644 --- a/chromium/third_party/ffmpeg/libavformat/mlvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mlvdec.c @@ -143,7 +143,7 @@ static int scan_file(AVFormatContext *avctx, AVStream *vst, AVStream *ast, int f vst->codec->codec_tag = MKTAG('B', 'I', 'T', 16); size -= 164; } else if (ast && type == MKTAG('W', 'A', 'V', 'I') && size >= 16) { - ret = ff_get_wav_header(pb, ast->codec, 16, 0); + ret = ff_get_wav_header(avctx, pb, ast->codec, 16, 0); if (ret < 0) return ret; size -= 16; diff --git a/chromium/third_party/ffmpeg/libavformat/mov.c b/chromium/third_party/ffmpeg/libavformat/mov.c index 5ea69328011..c57aaeb178d 100644 --- a/chromium/third_party/ffmpeg/libavformat/mov.c +++ b/chromium/third_party/ffmpeg/libavformat/mov.c @@ -29,6 +29,7 @@ #include "libavutil/attributes.h" #include "libavutil/channel_layout.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" @@ -37,6 +38,8 @@ #include "libavutil/dict.h" #include "libavutil/display.h" #include "libavutil/opt.h" +#include "libavutil/aes.h" +#include "libavutil/sha.h" #include "libavutil/timecode.h" #include "libavcodec/ac3tab.h" #include "avformat.h" @@ -769,7 +772,7 @@ static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; st = c->fc->streams[c->fc->nb_streams-1]; - if ((ret = ff_get_wav_header(pb, st->codec, atom.size, 0)) < 0) + if ((ret = ff_get_wav_header(c->fc, pb, st->codec, atom.size, 0)) < 0) av_log(c->fc, AV_LOG_WARNING, "get_wav_header failed\n"); return ret; @@ -807,6 +810,120 @@ static int mov_read_mdat(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; /* now go for moov */ } +#define DRM_BLOB_SIZE 56 + +static int mov_read_adrm(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + uint8_t intermediate_key[20]; + uint8_t intermediate_iv[20]; + uint8_t input[64]; + uint8_t output[64]; + uint8_t file_checksum[20]; + uint8_t calculated_checksum[20]; + struct AVSHA *sha; + int i; + int ret = 0; + uint8_t *activation_bytes = c->activation_bytes; + uint8_t *fixed_key = c->audible_fixed_key; + + c->aax_mode = 1; + + sha = av_sha_alloc(); + if (!sha) + return AVERROR(ENOMEM); + c->aes_decrypt = av_aes_alloc(); + if (!c->aes_decrypt) { + ret = AVERROR(ENOMEM); + goto fail; + } + + /* drm blob processing */ + avio_read(pb, output, 8); // go to offset 8, absolute postion 0x251 + avio_read(pb, input, DRM_BLOB_SIZE); + avio_read(pb, output, 4); // go to offset 4, absolute postion 0x28d + avio_read(pb, file_checksum, 20); + + av_log(c->fc, AV_LOG_INFO, "[aax] file checksum == "); // required by external tools + for (i = 0; i < 20; i++) + av_log(sha, AV_LOG_INFO, "%02x", file_checksum[i]); + av_log(c->fc, AV_LOG_INFO, "\n"); + + /* verify activation data */ + if (!activation_bytes) { + av_log(c->fc, AV_LOG_WARNING, "[aax] activation_bytes option is missing!\n"); + ret = 0; /* allow ffprobe to continue working on .aax files */ + goto fail; + } + if (c->activation_bytes_size != 4) { + av_log(c->fc, AV_LOG_FATAL, "[aax] activation_bytes value needs to be 4 bytes!\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + /* verify fixed key */ + if (c->audible_fixed_key_size != 16) { + av_log(c->fc, AV_LOG_FATAL, "[aax] audible_fixed_key value needs to be 16 bytes!\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + /* AAX (and AAX+) key derivation */ + av_sha_init(sha, 160); + av_sha_update(sha, fixed_key, 16); + av_sha_update(sha, activation_bytes, 4); + av_sha_final(sha, intermediate_key); + av_sha_init(sha, 160); + av_sha_update(sha, fixed_key, 16); + av_sha_update(sha, intermediate_key, 20); + av_sha_update(sha, activation_bytes, 4); + av_sha_final(sha, intermediate_iv); + av_sha_init(sha, 160); + av_sha_update(sha, intermediate_key, 16); + av_sha_update(sha, intermediate_iv, 16); + av_sha_final(sha, calculated_checksum); + if (memcmp(calculated_checksum, file_checksum, 20)) { // critical error + av_log(c->fc, AV_LOG_ERROR, "[aax] mismatch in checksums!\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + av_aes_init(c->aes_decrypt, intermediate_key, 128, 1); + av_aes_crypt(c->aes_decrypt, output, input, DRM_BLOB_SIZE >> 4, intermediate_iv, 1); + for (i = 0; i < 4; i++) { + // file data (in output) is stored in big-endian mode + if (activation_bytes[i] != output[3 - i]) { // critical error + av_log(c->fc, AV_LOG_ERROR, "[aax] error in drm blob decryption!\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + } + memcpy(c->file_key, output + 8, 16); + memcpy(input, output + 26, 16); + av_sha_init(sha, 160); + av_sha_update(sha, input, 16); + av_sha_update(sha, c->file_key, 16); + av_sha_update(sha, fixed_key, 16); + av_sha_final(sha, c->file_iv); + +fail: + av_free(sha); + + return ret; +} + +// Audible AAX (and AAX+) bytestream decryption +static int aax_filter(uint8_t *input, int size, MOVContext *c) +{ + int blocks = 0; + unsigned char iv[16]; + + memcpy(iv, c->file_iv, 16); // iv is overwritten + blocks = size >> 4; // trailing bytes are not encrypted! + av_aes_init(c->aes_decrypt, c->file_key, 128, 1); + av_aes_crypt(c->aes_decrypt, input, input, blocks, iv, 1); + + return 0; +} + /* read major brand, minor version and compatible brands and store them as metadata */ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) { @@ -1024,7 +1141,7 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; char color_parameter_type[5] = { 0 }; - int color_primaries, color_trc, color_matrix; + uint16_t color_primaries, color_trc, color_matrix; int ret; if (c->fc->nb_streams < 1) @@ -1130,14 +1247,14 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_realloc_extradata(AVCodecContext *codec, MOVAtom atom) { int err = 0; - uint64_t size = (uint64_t)codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE; + uint64_t size = (uint64_t)codec->extradata_size + atom.size + 8 + AV_INPUT_BUFFER_PADDING_SIZE; if (size > INT_MAX || (uint64_t)atom.size > INT_MAX) return AVERROR_INVALIDDATA; if ((err = av_reallocp(&codec->extradata, size)) < 0) { codec->extradata_size = 0; return err; } - codec->extradata_size = size - FF_INPUT_BUFFER_PADDING_SIZE; + codec->extradata_size = size - AV_INPUT_BUFFER_PADDING_SIZE; return 0; } @@ -1159,7 +1276,7 @@ static int64_t mov_read_atom_into_extradata(MOVContext *c, AVIOContext *pb, MOVA codec->extradata_size -= atom.size - err; result = err; } - memset(buf + 8 + err, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(buf + 8 + err, 0, AV_INPUT_BUFFER_PADDING_SIZE); return result; } @@ -1277,7 +1394,7 @@ static int mov_read_aclr(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c, AV_LOG_WARNING, "ignored unknown aclr value (%d)\n", range_value); break; } - av_dlog(c, "color_range: %d\n", codec->color_range); + ff_dlog(c, "color_range: %d\n", codec->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"); @@ -1319,6 +1436,32 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) return ret; } else if (atom.size > 8) { /* to read frma, esds atoms */ + if (st->codec->codec_id == AV_CODEC_ID_ALAC && atom.size >= 24) { + uint64_t buffer; + ret = ffio_ensure_seekback(pb, 8); + if (ret < 0) + return ret; + buffer = avio_rb64(pb); + atom.size -= 8; + if ( (buffer & 0xFFFFFFFF) == MKBETAG('f','r','m','a') + && buffer >> 32 <= atom.size + && buffer >> 32 >= 8) { + avio_skip(pb, -8); + atom.size += 8; + } else if (!st->codec->extradata_size) { +#define ALAC_EXTRADATA_SIZE 36 + st->codec->extradata = av_mallocz(ALAC_EXTRADATA_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata_size = ALAC_EXTRADATA_SIZE; + AV_WB32(st->codec->extradata , ALAC_EXTRADATA_SIZE); + AV_WB32(st->codec->extradata + 4, MKTAG('a','l','a','c')); + AV_WB64(st->codec->extradata + 12, buffer); + avio_read(pb, st->codec->extradata + 20, 16); + avio_skip(pb, atom.size - 24); + return 0; + } + } if ((ret = mov_read_default(c, pb, atom)) < 0) return ret; } else @@ -1567,7 +1710,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) { /* for palette traversal */ unsigned int color_start, color_count, color_end; - unsigned char a, r, g, b; + unsigned int a, r, g, b; if (color_greyscale) { int color_index, color_dec; @@ -1669,6 +1812,15 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, flags); } + if (version == 0 || (version == 1 && sc->audio_cid != -2)) { + /* can't correctly handle variable sized packet as audio unit */ + switch (st->codec->codec_id) { + case AV_CODEC_ID_MP2: + case AV_CODEC_ID_MP3: + st->need_parsing = AVSTREAM_PARSE_FULL; + break; + } + } } switch (st->codec->codec_id) { @@ -1774,7 +1926,7 @@ static int mov_rewrite_dvd_sub_extradata(AVStream *st) av_freep(&st->codec->extradata); st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(strlen(buf) + FF_INPUT_BUFFER_PADDING_SIZE); + st->codec->extradata = av_mallocz(strlen(buf) + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); st->codec->extradata_size = strlen(buf); @@ -1802,7 +1954,7 @@ static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb, val = AV_RB32(st->codec->extradata + 4); tmcd_ctx->tmcd_flags = val; if (val & 1) - st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; + st->codec->flags2 |= AV_CODEC_FLAG2_DROP_FRAME_TIMECODE; st->codec->time_base.den = st->codec->extradata[16]; /* number of frame */ st->codec->time_base.num = 1; /* adjust for per frame dur in counter mode */ @@ -1889,7 +2041,6 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, case AV_CODEC_ID_MP3: /* force type after stsd for m1a hdlr */ st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->need_parsing = AVSTREAM_PARSE_FULL; break; case AV_CODEC_ID_GSM: case AV_CODEC_ID_ADPCM_MS: @@ -1985,9 +2136,10 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) id = mov_codec_id(st, format); - av_log(c->fc, AV_LOG_TRACE, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size, + av_log(c->fc, AV_LOG_TRACE, + "size=%"PRId64" 4CC= %c%c%c%c/0x%08x codec_type=%d\n", size, (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, - (format >> 24) & 0xff, st->codec->codec_type); + (format >> 24) & 0xff, format, st->codec->codec_type); if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) { st->codec->codec_id = id; @@ -2211,7 +2363,7 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) num_bytes = (entries*field_size+4)>>3; - buf = av_malloc(num_bytes+FF_INPUT_BUFFER_PADDING_SIZE); + buf = av_malloc(num_bytes+AV_INPUT_BUFFER_PADDING_SIZE); if (!buf) { av_freep(&sc->sample_sizes); return AVERROR(ENOMEM); @@ -2354,7 +2506,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n", count, duration); - if (FFABS(duration) > (1<<28) && i+2<entries) { + if (FFNABS(duration) < -(1<<28) && i+2<entries) { av_log(c->fc, AV_LOG_WARNING, "CTTS invalid\n"); av_freep(&sc->ctts_data); sc->ctts_count = 0; @@ -2689,6 +2841,35 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } +static int test_same_origin(const char *src, const char *ref) { + char src_proto[64]; + char ref_proto[64]; + char src_auth[256]; + char ref_auth[256]; + char src_host[256]; + char ref_host[256]; + int src_port=-1; + int ref_port=-1; + + av_url_split(src_proto, sizeof(src_proto), src_auth, sizeof(src_auth), src_host, sizeof(src_host), &src_port, NULL, 0, src); + av_url_split(ref_proto, sizeof(ref_proto), ref_auth, sizeof(ref_auth), ref_host, sizeof(ref_host), &ref_port, NULL, 0, ref); + + if (strlen(src) == 0) { + return -1; + } else if (strlen(src_auth) + 1 >= sizeof(src_auth) || + strlen(ref_auth) + 1 >= sizeof(ref_auth) || + strlen(src_host) + 1 >= sizeof(src_host) || + strlen(ref_host) + 1 >= sizeof(ref_host)) { + return 0; + } else if (strcmp(src_proto, ref_proto) || + strcmp(src_auth, ref_auth) || + strcmp(src_host, ref_host) || + src_port != ref_port) { + return 0; + } else + return 1; +} + static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDref *ref, AVIOInterruptCB *int_cb) { @@ -2699,7 +2880,7 @@ static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDr /* try relative path, we do not try the absolute because it can leak information about our system to an attacker */ - if (ref->nlvl_to > 0 && ref->nlvl_from > 0 && ref->path[0] != '/') { + if (ref->nlvl_to > 0 && ref->nlvl_from > 0) { char filename[1025]; const char *src_path; int i, l; @@ -2729,9 +2910,23 @@ static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDr av_strlcat(filename, "../", sizeof(filename)); av_strlcat(filename, ref->path + l + 1, sizeof(filename)); - if (!c->use_absolute_path && !c->fc->open_cb) - if(strstr(ref->path + l + 1, "..") || ref->nlvl_from > 1) + if (!c->use_absolute_path && !c->fc->open_cb) { + int same_origin = test_same_origin(src, filename); + + if (!same_origin) { + av_log(c->fc, AV_LOG_ERROR, + "Reference with mismatching origin, %s not tried for security reasons, " + "set demuxer option use_absolute_path to allow it anyway\n", + ref->path); + 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)) return AVERROR(ENOENT); + } if (strlen(filename) + 1 == sizeof(filename)) return AVERROR(ENOENT); @@ -3233,7 +3428,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) int64_t dts; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; - int flags, distance, i, found_keyframe = 0, err; + int flags, distance, i, err; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -3320,8 +3515,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_count++; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) keyframe = 1; - else if (!found_keyframe) - keyframe = found_keyframe = + else + keyframe = !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC | MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); if (keyframe) @@ -3585,6 +3780,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('e','l','s','t'), mov_read_elst }, { MKTAG('e','n','d','a'), mov_read_enda }, { MKTAG('f','i','e','l'), mov_read_fiel }, +{ MKTAG('a','d','r','m'), mov_read_adrm }, { MKTAG('f','t','y','p'), mov_read_ftyp }, { MKTAG('g','l','b','l'), mov_read_glbl }, { MKTAG('h','d','l','r'), mov_read_hdlr }, @@ -3964,6 +4160,9 @@ static int mov_read_close(AVFormatContext *s) AVStream *st = s->streams[i]; MOVStreamContext *sc = st->priv_data; + if (!sc) + continue; + av_freep(&sc->ctts_data); for (j = 0; j < sc->drefs_count; j++) { av_freep(&sc->drefs[j].path); @@ -4003,6 +4202,8 @@ static int mov_read_close(AVFormatContext *s) } av_freep(&mov->fragment_index_data); + av_freep(&mov->aes_decrypt); + return 0; } @@ -4290,6 +4491,7 @@ static int mov_read_header(AVFormatContext *s) break; } } + ff_configure_buffers_for_index(s, AV_TIME_BASE); return 0; } @@ -4421,6 +4623,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0; pkt->pos = sample->pos; + if (mov->aax_mode) + aax_filter(pkt->data, pkt->size, mov); + return 0; } @@ -4511,17 +4716,17 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti static const AVOption mov_options[] = { {"use_absolute_path", "allow using absolute path when opening alias, this is a possible security issue", - OFFSET(use_absolute_path), FF_OPT_TYPE_INT, {.i64 = 0}, + OFFSET(use_absolute_path), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS}, {"seek_streams_individually", "Seek each stream individually to the to the closest point", OFFSET(seek_individually), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS}, - {"ignore_editlist", "", OFFSET(ignore_editlist), FF_OPT_TYPE_INT, {.i64 = 0}, + {"ignore_editlist", "", OFFSET(ignore_editlist), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS}, {"use_mfra_for", "use mfra for fragment timestamps", - OFFSET(use_mfra_for), FF_OPT_TYPE_INT, {.i64 = FF_MOV_FLAG_MFRA_AUTO}, + OFFSET(use_mfra_for), AV_OPT_TYPE_INT, {.i64 = FF_MOV_FLAG_MFRA_AUTO}, -1, FF_MOV_FLAG_MFRA_PTS, FLAGS, "use_mfra_for"}, {"auto", "auto", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_AUTO}, 0, 0, @@ -4531,9 +4736,15 @@ static const AVOption mov_options[] = { {"pts", "pts", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_PTS}, 0, 0, FLAGS, "use_mfra_for" }, { "export_all", "Export unrecognized metadata entries", OFFSET(export_all), - AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS }, + AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS }, { "export_xmp", "Export full XMP metadata", OFFSET(export_xmp), - AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS }, + 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_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"}, + .flags = AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.c b/chromium/third_party/ffmpeg/libavformat/movenc.c index adde4b2c230..08d0c2a7720 100644 --- a/chromium/third_party/ffmpeg/libavformat/movenc.c +++ b/chromium/third_party/ffmpeg/libavformat/movenc.c @@ -66,6 +66,7 @@ static const AVOption options[] = { { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "write_colr", "Write colr atom (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), @@ -733,7 +734,7 @@ static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf) "dvc1 atom. Set the delay_moov flag to fix this.\n"); } - unescaped = av_mallocz(track->vos_len + FF_INPUT_BUFFER_PADDING_SIZE); + unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE); if (!unescaped) return AVERROR(ENOMEM); start = find_next_marker(track->vos_data, end); @@ -2573,7 +2574,7 @@ static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov, int ret, size; uint8_t *buf; - if (!st || mov->fc->flags & AVFMT_FLAG_BITEXACT) + if (!st) return 0; ret = avio_open_dyn_buf(&pb_buf); @@ -2919,9 +2920,10 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1); mov_write_string_metadata(s, pb, "\251alb", "album" , 1); mov_write_string_metadata(s, pb, "\251day", "date" , 1); - if (!mov->exact && - !mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) - mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1); + if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) { + if (!(s->flags & AVFMT_FLAG_BITEXACT)) + mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1); + } mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1); mov_write_string_metadata(s, pb, "\251gen", "genre" , 1); mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1); @@ -3115,7 +3117,6 @@ static void mov_write_psp_udta_tag(AVIOContext *pb, static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) { - MOVMuxContext *mov = s->priv_data; AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); int64_t pos, pos2; @@ -3140,7 +3141,7 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) avio_wb16(pb, 0x0); /* ? */ avio_wb16(pb, 0x021C); /* data */ - if (!mov->exact) + if (!(s->flags & AVFMT_FLAG_BITEXACT)) mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04); mov_write_psp_udta_tag(pb, title->value, "eng", 0x01); mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03); @@ -3275,7 +3276,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov) avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n"); avio_printf(pb, "<head>\n"); - if (!mov->exact) + if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT)) avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n", LIBAVFORMAT_IDENT); avio_printf(pb, "</head>\n"); @@ -3680,6 +3681,8 @@ static int mov_write_sidx_tag(AVIOContext *pb, } } else { entries = track->nb_frag_info; + if (entries <= 0) + return 0; presentation_time = track->frag_info[0].time; } @@ -3763,7 +3766,7 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks, mov_write_moof_tag_internal(avio_buf, mov, tracks, 0); moof_size = ffio_close_null_buf(avio_buf); - if (mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_FASTSTART)) + if (mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)) mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size); if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0) @@ -3903,7 +3906,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) else if (mov->mode == MODE_MP4) ffio_wfourcc(pb, "mp41"); - if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_FASTSTART) + if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) ffio_wfourcc(pb, "dash"); return update_size(pb, pos); @@ -4165,8 +4168,8 @@ static int mov_flush_fragment(AVFormatContext *s) return ret; if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) { - if (mov->flags & FF_MOV_FLAG_FASTSTART) - mov->reserved_moov_pos = avio_tell(s->pb); + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) + mov->reserved_header_pos = avio_tell(s->pb); avio_flush(s->pb); mov->moov_written = 1; return 0; @@ -4179,6 +4182,9 @@ static int mov_flush_fragment(AVFormatContext *s) avio_write(s->pb, buf, buf_size); av_free(buf); + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) + mov->reserved_header_pos = avio_tell(s->pb); + mov->moov_written = 1; mov->mdat_size = 0; for (i = 0; i < mov->nb_streams; i++) { @@ -4455,7 +4461,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with * the next fragment. This means the cts of the first sample must * be the same in all fragments. */ - if ((mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_FASTSTART)) || + if ((mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)) || mov->mode == MODE_ISM) pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts; } else { @@ -4960,9 +4966,6 @@ static int mov_write_header(AVFormatContext *s) else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V; } - if (s->flags & AVFMT_FLAG_BITEXACT) - mov->exact = 1; - if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) mov->flags |= FF_MOV_FLAG_EMPTY_MOOV; @@ -5230,7 +5233,7 @@ static int mov_write_header(AVFormatContext *s) if (mov->reserved_moov_size){ - mov->reserved_moov_pos= avio_tell(pb); + mov->reserved_header_pos = avio_tell(pb); if (mov->reserved_moov_size > 0) avio_skip(pb, mov->reserved_moov_size); } @@ -5243,12 +5246,17 @@ static int mov_write_header(AVFormatContext *s) mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; } else { if (mov->flags & FF_MOV_FLAG_FASTSTART) - mov->reserved_moov_pos = avio_tell(pb); + mov->reserved_header_pos = avio_tell(pb); mov_write_mdat_tag(pb, mov); } - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { mov->time = ff_iso8601_to_unix_time(t->value); + if (mov->time < 0) { + av_log(s, AV_LOG_WARNING, "Failed to parse creation_time %s\n", t->value); + mov->time = 0; + } + } if (mov->time) mov->time += 0x7C25B080; // 1970 based -> 1904 based @@ -5297,8 +5305,8 @@ static int mov_write_header(AVFormatContext *s) if ((ret = mov_write_moov_tag(pb, mov, s)) < 0) return ret; mov->moov_written = 1; - if (mov->flags & FF_MOV_FLAG_FASTSTART) - mov->reserved_moov_pos = avio_tell(pb); + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) + mov->reserved_header_pos = avio_tell(pb); } return 0; @@ -5415,10 +5423,10 @@ static int shift_data(AVFormatContext *s) /* mark the end of the shift to up to the last data we wrote, and get ready * for writing */ pos_end = avio_tell(s->pb); - avio_seek(s->pb, mov->reserved_moov_pos + moov_size, SEEK_SET); + avio_seek(s->pb, mov->reserved_header_pos + moov_size, SEEK_SET); /* start reading at where the new moov will be placed */ - avio_seek(read_pb, mov->reserved_moov_pos, SEEK_SET); + avio_seek(read_pb, mov->reserved_header_pos, SEEK_SET); pos = avio_tell(read_pb); #define READ_BLOCK do { \ @@ -5492,13 +5500,13 @@ static int mov_write_trailer(AVFormatContext *s) ffio_wfourcc(pb, "mdat"); avio_wb64(pb, mov->mdat_size + 16); } - avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET); + avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET); if (mov->flags & FF_MOV_FLAG_FASTSTART) { av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n"); res = shift_data(s); if (res == 0) { - avio_seek(pb, mov->reserved_moov_pos, SEEK_SET); + avio_seek(pb, mov->reserved_header_pos, SEEK_SET); if ((res = mov_write_moov_tag(pb, mov, s)) < 0) goto error; } @@ -5506,7 +5514,7 @@ static int mov_write_trailer(AVFormatContext *s) int64_t size; if ((res = mov_write_moov_tag(pb, mov, s)) < 0) goto error; - size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); + size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos); if (size < 8){ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size); res = AVERROR(EINVAL); @@ -5525,12 +5533,12 @@ static int mov_write_trailer(AVFormatContext *s) mov_auto_flush_fragment(s); for (i = 0; i < mov->nb_streams; i++) mov->tracks[i].data_offset = 0; - if (mov->flags & FF_MOV_FLAG_FASTSTART) { + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) { av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n"); res = shift_data(s); if (res == 0) { int64_t end = avio_tell(pb); - avio_seek(pb, mov->reserved_moov_pos, SEEK_SET); + avio_seek(pb, mov->reserved_header_pos, SEEK_SET); mov_write_sidx_tags(pb, mov, -1, 0); avio_seek(pb, end, SEEK_SET); mov_write_mfra_tag(pb, mov); @@ -5588,7 +5596,7 @@ MOV_CLASS(mp4) AVOutputFormat ff_mp4_muxer = { .name = "mp4", .long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"), - .mime_type = "application/mp4", + .mime_type = "video/mp4", .extensions = "mp4", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = AV_CODEC_ID_AAC, @@ -5642,7 +5650,7 @@ MOV_CLASS(ipod) AVOutputFormat ff_ipod_muxer = { .name = "ipod", .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"), - .mime_type = "application/mp4", + .mime_type = "video/mp4", .extensions = "m4v,m4a", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = AV_CODEC_ID_AAC, @@ -5660,7 +5668,7 @@ MOV_CLASS(ismv) AVOutputFormat ff_ismv_muxer = { .name = "ismv", .long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"), - .mime_type = "application/mp4", + .mime_type = "video/mp4", .extensions = "ismv,isma", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = AV_CODEC_ID_AAC, diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.h b/chromium/third_party/ffmpeg/libavformat/movenc.h index 744d14e5b2d..06adf2b1217 100644 --- a/chromium/third_party/ffmpeg/libavformat/movenc.h +++ b/chromium/third_party/ffmpeg/libavformat/movenc.h @@ -164,7 +164,6 @@ typedef struct MOVMuxContext { int flags; int rtp_flags; - int exact; int iods_skip; int iods_video_profile; @@ -182,7 +181,7 @@ typedef struct MOVMuxContext { int video_track_timescale; int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise - int64_t reserved_moov_pos; + int64_t reserved_header_pos; char *major_brand; @@ -210,8 +209,9 @@ typedef struct MOVMuxContext { #define FF_MOV_FLAG_DASH (1 << 11) #define FF_MOV_FLAG_FRAG_DISCONT (1 << 12) #define FF_MOV_FLAG_DELAY_MOOV (1 << 13) -#define FF_MOV_FLAG_WRITE_COLR (1 << 14) -#define FF_MOV_FLAG_WRITE_GAMA (1 << 15) +#define FF_MOV_FLAG_GLOBAL_SIDX (1 << 14) +#define FF_MOV_FLAG_WRITE_COLR (1 << 15) +#define FF_MOV_FLAG_WRITE_GAMA (1 << 16) int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); diff --git a/chromium/third_party/ffmpeg/libavformat/mp3dec.c b/chromium/third_party/ffmpeg/libavformat/mp3dec.c index 4023c8223e6..7354c2841bb 100644 --- a/chromium/third_party/ffmpeg/libavformat/mp3dec.c +++ b/chromium/third_party/ffmpeg/libavformat/mp3dec.c @@ -54,7 +54,7 @@ typedef struct { int is_cbr; } MP3DecContext; -static int check(AVFormatContext *s, int64_t pos); +static int check(AVIOContext *pb, int64_t pos); /* mp3 read */ @@ -98,7 +98,7 @@ static int mp3_read_probe(AVProbeData *p) avcodec_free_context(&avctx); // keep this in sync with ac3 probe, both need to avoid // issues with MPEG-files! - if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1; + if (first_frames>=7) return AVPROBE_SCORE_EXTENSION + 1; else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; else if(max_frames>=4 && max_frames >= p->buf_size/10000) return AVPROBE_SCORE_EXTENSION / 2; else if(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size) @@ -148,6 +148,8 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, MP3DecContext *mp3 = s->priv_data; static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; + uint64_t fsize = avio_size(s->pb); + fsize = fsize >= avio_tell(s->pb) ? fsize - avio_tell(s->pb) : 0; /* Check for Xing / Info tag */ avio_skip(s->pb, xing_offtbl[c->lsf == 1][c->nb_channels == 1]); @@ -161,6 +163,19 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, mp3->frames = avio_rb32(s->pb); if (v & XING_FLAG_SIZE) mp3->header_filesize = avio_rb32(s->pb); + if (fsize && mp3->header_filesize) { + uint64_t min, delta; + min = FFMIN(fsize, mp3->header_filesize); + delta = FFMAX(fsize, mp3->header_filesize) - min; + if (fsize > mp3->header_filesize && delta > min >> 4) { + mp3->frames = 0; + av_log(s, AV_LOG_WARNING, + "invalid concatenated file detected - using bitrate for duration\n"); + } else if (delta > min >> 4) { + av_log(s, AV_LOG_WARNING, + "filesize and duration do not match (growing file?)\n"); + } + } if (v & XING_FLAG_TOC) read_xing_toc(s, mp3->header_filesize, av_rescale_q(mp3->frames, (AVRational){spf, c->sample_rate}, @@ -223,6 +238,14 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, st->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf; st->last_discard_sample = mp3->frames * (int64_t)spf; } + // TODO(dalecurtis): Chrome expects to handle this start time change + // itself, instead of ffmpeg magically moving the start time into + // the future. + // + // if (!st->start_time) + // st->start_time = av_rescale_q(st->start_skip_samples, + // (AVRational){1, c->sample_rate}, + // st->time_base); av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad); } @@ -323,7 +346,7 @@ static int mp3_read_header(AVFormatContext *s) int i; if (mp3->usetoc < 0) - mp3->usetoc = (s->flags & AVFMT_FLAG_FAST_SEEK) ? 0 : 2; + mp3->usetoc = (s->flags & AVFMT_FLAG_FAST_SEEK) ? 1 : 2; st = avformat_new_stream(s, NULL); if (!st) @@ -357,7 +380,7 @@ static int mp3_read_header(AVFormatContext *s) for (i = 0; i < 64 * 1024; i++) { if (!(i&1023)) ffio_ensure_seekback(s->pb, i + 1024 + 4); - if (check(s, off + i) >= 0) { + if (check(s->pb, off + i) >= 0) { av_log(s, AV_LOG_INFO, "Skipping %d bytes of junk at %"PRId64".\n", i, off); avio_seek(s->pb, off + i, SEEK_SET); break; @@ -396,73 +419,45 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->flags &= ~AV_PKT_FLAG_CORRUPT; pkt->stream_index = 0; - if (ret >= ID3v1_TAG_SIZE && - memcmp(&pkt->data[ret - ID3v1_TAG_SIZE], "TAG", 3) == 0) - ret -= ID3v1_TAG_SIZE; - - /* note: we need to modify the packet size here to handle the last - packet */ - pkt->size = ret; return ret; } -static int check(AVFormatContext *s, int64_t pos) +#define SEEK_WINDOW 4096 + +static int check(AVIOContext *pb, int64_t pos) { - int64_t ret = avio_seek(s->pb, pos, SEEK_SET); + int64_t ret = avio_seek(pb, pos, SEEK_SET); unsigned header; MPADecodeHeader sd; if (ret < 0) return ret; - header = avio_rb32(s->pb); + + header = avio_rb32(pb); if (ff_mpa_check_header(header) < 0) return -1; if (avpriv_mpegaudio_decode_header(&sd, header) == 1) return -1; + return sd.frame_size; } -static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, - int flags) +static int64_t mp3_sync(AVFormatContext *s, int64_t target_pos, int flags) { - MP3DecContext *mp3 = s->priv_data; - AVIndexEntry *ie, ie1; - AVStream *st = s->streams[0]; - int64_t ret = av_index_search_timestamp(st, timestamp, flags); - int i, j; int dir = (flags&AVSEEK_FLAG_BACKWARD) ? -1 : 1; int64_t best_pos; - int best_score; + int best_score, i, j; + int64_t ret; - if (mp3->usetoc == 2) - return -1; // generic index code - - if ( mp3->is_cbr - && (mp3->usetoc == 0 || !mp3->xing_toc) - && st->duration > 0 - && mp3->header_filesize > s->internal->data_offset) { - ie = &ie1; - timestamp = av_clip64(timestamp, 0, st->duration); - ie->timestamp = timestamp; - ie->pos = av_rescale(timestamp, mp3->header_filesize, st->duration) + s->internal->data_offset; - } else if (mp3->xing_toc) { - if (ret < 0) - return ret; - - ie = &st->index_entries[ret]; - } else { - return -1; - } - - avio_seek(s->pb, FFMAX(ie->pos - 4096, 0), SEEK_SET); - ret = avio_seek(s->pb, ie->pos, SEEK_SET); + avio_seek(s->pb, FFMAX(target_pos - SEEK_WINDOW, 0), SEEK_SET); + ret = avio_seek(s->pb, target_pos, SEEK_SET); if (ret < 0) return ret; #define MIN_VALID 3 - best_pos = ie->pos; + best_pos = target_pos; best_score = 999; - for(i=0; i<4096; i++) { - int64_t pos = ie->pos + (dir > 0 ? i - 1024 : -i); + for(i=0; i<SEEK_WINDOW; i++) { + int64_t pos = target_pos + (dir > 0 ? i - SEEK_WINDOW/4 : -i); int64_t candidate = -1; int score = 999; @@ -470,10 +465,10 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, continue; for(j=0; j<MIN_VALID; j++) { - ret = check(s, pos); + ret = check(s->pb, pos); if(ret < 0) break; - if ((ie->pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) { + if ((target_pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) { candidate = pos; score = abs(MIN_VALID/2-j); } @@ -487,11 +482,51 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, } } - ret = avio_seek(s->pb, best_pos, SEEK_SET); - if (ret < 0) - return ret; + return avio_seek(s->pb, best_pos, SEEK_SET); +} + +static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, + int flags) +{ + MP3DecContext *mp3 = s->priv_data; + AVIndexEntry *ie, ie1; + AVStream *st = s->streams[0]; + int64_t ret = av_index_search_timestamp(st, timestamp, flags); + int64_t best_pos; + int fast_seek = (s->flags & AVFMT_FLAG_FAST_SEEK) ? 1 : 0; + int64_t filesize = mp3->header_filesize; + + if (mp3->usetoc == 2) + return -1; // generic index code + + if (filesize <= 0) { + int64_t size = avio_size(s->pb); + if (size > 0 && size > s->internal->data_offset) + filesize = size - s->internal->data_offset; + } + + if ( (mp3->is_cbr || fast_seek) + && (mp3->usetoc == 0 || !mp3->xing_toc) + && st->duration > 0 + && filesize > 0) { + ie = &ie1; + timestamp = av_clip64(timestamp, 0, st->duration); + ie->timestamp = timestamp; + ie->pos = av_rescale(timestamp, filesize, st->duration) + s->internal->data_offset; + } else if (mp3->xing_toc) { + if (ret < 0) + return ret; + + ie = &st->index_entries[ret]; + } else { + return -1; + } + + best_pos = mp3_sync(s, ie->pos, flags); + if (best_pos < 0) + return best_pos; - if (mp3->is_cbr && ie == &ie1) { + if (mp3->is_cbr && ie == &ie1 && mp3->frames) { int frame_duration = av_rescale(st->duration, 1, mp3->frames); ie1.timestamp = frame_duration * av_rescale(best_pos - s->internal->data_offset, mp3->frames, mp3->header_filesize); } diff --git a/chromium/third_party/ffmpeg/libavformat/mpc8.c b/chromium/third_party/ffmpeg/libavformat/mpc8.c index 0cef65ff7d0..bf597b88a58 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpc8.c +++ b/chromium/third_party/ffmpeg/libavformat/mpc8.c @@ -154,7 +154,7 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) av_log(s, AV_LOG_ERROR, "Bad seek table size\n"); return; } - if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE))) + if(!(buf = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE))) return; ret = avio_read(s->pb, buf, size); if (ret != size) { @@ -162,7 +162,7 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) av_free(buf); return; } - memset(buf+size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(buf+size, 0, AV_INPUT_BUFFER_PADDING_SIZE); init_get_bits(&gb, buf, size * 8); size = gb_get_v(&gb); diff --git a/chromium/third_party/ffmpeg/libavformat/mpeg.c b/chromium/third_party/ffmpeg/libavformat/mpeg.c index edb134f7405..223b6906d68 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/mpeg.c @@ -612,7 +612,7 @@ found: if (st->discard >= AVDISCARD_ALL) goto skip; if (startcode >= 0xa0 && startcode <= 0xaf) { - if (lpcm_header_len == 6 && st->codec->codec_id == AV_CODEC_ID_MLP) { + if (st->codec->codec_id == AV_CODEC_ID_MLP) { if (len < 6) goto skip; avio_skip(s->pb, 6); @@ -857,7 +857,7 @@ static int vobsub_read_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { vobsub->q[i].sort = SUB_SORT_POS_TS; - ff_subtitles_queue_finalize(&vobsub->q[i]); + ff_subtitles_queue_finalize(s, &vobsub->q[i]); } if (!av_bprint_is_complete(&header)) { diff --git a/chromium/third_party/ffmpeg/libavformat/mpegenc.c b/chromium/third_party/ffmpeg/libavformat/mpegenc.c index 2520f49db19..b3ee2a09b9d 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegenc.c @@ -410,7 +410,9 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->max_buffer_size = 16 * 1024; break; default: - return -1; + av_log(ctx, AV_LOG_ERROR, "Invalid media type %s for output stream #%d\n", + av_get_media_type_string(st->codec->codec_type), i); + return AVERROR(EINVAL); } stream->fifo = av_fifo_alloc(16); if (!stream->fifo) diff --git a/chromium/third_party/ffmpeg/libavformat/mpegts.c b/chromium/third_party/ffmpeg/libavformat/mpegts.c index 84946e3cfd5..ed0a86b337d 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegts.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegts.c @@ -21,6 +21,7 @@ #include "libavutil/buffer.h" #include "libavutil/crc.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/dict.h" @@ -161,19 +162,19 @@ struct MpegTSContext { }; #define MPEGTS_OPTIONS \ - { "resync_size", "Size limit for looking up a new synchronization.", offsetof(MpegTSContext, resync_size), AV_OPT_TYPE_INT, { .i64 = MAX_RESYNC_SIZE}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM } + { "resync_size", "set size limit for looking up a new synchronization", offsetof(MpegTSContext, resync_size), AV_OPT_TYPE_INT, { .i64 = MAX_RESYNC_SIZE}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM } static const AVOption options[] = { MPEGTS_OPTIONS, - {"fix_teletext_pts", "Try to fix pts values of dvb teletext streams.", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT, + {"fix_teletext_pts", "try to fix pts values of dvb teletext streams", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, - {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, + {"ts_packetsize", "output option carrying the raw packet size", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, - {"scan_all_pmts", "Scan and combine all PMTs", offsetof(MpegTSContext, scan_all_pmts), AV_OPT_TYPE_INT, + {"scan_all_pmts", "scan and combine all PMTs", offsetof(MpegTSContext, scan_all_pmts), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM }, - {"skip_changes", "Skip changing / adding streams / programs.", offsetof(MpegTSContext, skip_changes), AV_OPT_TYPE_INT, + {"skip_changes", "skip changing / adding streams / programs", offsetof(MpegTSContext, skip_changes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0 }, - {"skip_clear", "Skip clearing programs.", offsetof(MpegTSContext, skip_clear), AV_OPT_TYPE_INT, + {"skip_clear", "skip clearing programs", offsetof(MpegTSContext, skip_clear), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0 }, { NULL }, }; @@ -187,10 +188,10 @@ static const AVClass mpegts_class = { static const AVOption raw_options[] = { MPEGTS_OPTIONS, - { "compute_pcr", "Compute exact PCR for each transport stream packet.", + { "compute_pcr", "compute exact PCR for each transport stream packet", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, - { "ts_packetsize", "Output option carrying the raw packet size.", + { "ts_packetsize", "output option carrying the raw packet size", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, @@ -698,6 +699,7 @@ static const StreamType ISO_types[] = { #endif { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, + { 0x21, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000 }, { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, @@ -716,6 +718,7 @@ static const StreamType HDMV_types[] = { { 0xa1, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */ { 0xa2, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS Express Secondary Audio */ { 0x90, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_HDMV_PGS_SUBTITLE }, + { 0x92, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_HDMV_TEXT_SUBTITLE }, { 0 }, }; @@ -838,7 +841,7 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes, if ((st->codec->codec_id == AV_CODEC_ID_NONE || (st->request_probe > 0 && st->request_probe < AVPROBE_SCORE_STREAM_RETRY / 5)) && !avcodec_is_open(st->codec) && - stream_type == 6) { + stream_type == STREAM_TYPE_PRIVATE_DATA) { st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = AV_CODEC_ID_BIN_DATA; st->request_probe = AVPROBE_SCORE_STREAM_RETRY / 5; @@ -870,7 +873,7 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt) av_log(pes->stream, AV_LOG_WARNING, "PES packet size mismatch\n"); pes->flags |= AV_PKT_FLAG_CORRUPT; } - memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); // Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID if (pes->sub_st && pes->stream_type == 0x83 && pes->extended_stream_id == 0x76) @@ -902,8 +905,8 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, int padding_flag = 0, padding_bits = 0, inst_bitrate_flag = 0; int dts_flag = -1, cts_flag = -1; int64_t dts = AV_NOPTS_VALUE, cts = AV_NOPTS_VALUE; - uint8_t buf_padded[128 + FF_INPUT_BUFFER_PADDING_SIZE]; - int buf_padded_size = FFMIN(buf_size, sizeof(buf_padded) - FF_INPUT_BUFFER_PADDING_SIZE); + uint8_t buf_padded[128 + AV_INPUT_BUFFER_PADDING_SIZE]; + int buf_padded_size = FFMIN(buf_size, sizeof(buf_padded) - AV_INPUT_BUFFER_PADDING_SIZE); memcpy(buf_padded, buf, buf_padded_size); @@ -1035,7 +1038,7 @@ static int mpegts_push_data(MpegTSFilter *filter, /* allocate pes buffer */ pes->buffer = av_buffer_alloc(pes->total_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!pes->buffer) return AVERROR(ENOMEM); @@ -1052,6 +1055,7 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->st->request_probe = 1; } } else { + pes->pes_header_size = 6; pes->state = MPEGTS_PAYLOAD; pes->data_index = 0; } @@ -1139,7 +1143,10 @@ skip: p += 5; buf_size -= 5; } - if (pes->ts->fix_teletext_pts && pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) { + if ( pes->ts->fix_teletext_pts + && ( pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT + || pes->st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) + ) { AVProgram *p = NULL; while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) { if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) { @@ -1168,7 +1175,11 @@ skip: pes->st->pts_wrap_behavior = st->pts_wrap_behavior; if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { pes->pts = pes->dts = pcr; - } else if (pes->dts > pcr + 3654 + 9000) { + } else if (pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT && + pes->dts > pcr + 3654 + 9000) { + pes->pts = pes->dts = pcr + 3654 + 9000; + } else if (pes->st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE && + pes->dts > pcr + 10*90000) { //10sec pes->pts = pes->dts = pcr + 3654 + 9000; } break; @@ -1186,7 +1197,7 @@ skip: new_pes_packet(pes, ts->pkt); pes->total_size = MAX_PES_PAYLOAD; pes->buffer = av_buffer_alloc(pes->total_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!pes->buffer) return AVERROR(ENOMEM); ts->stop_parse = 1; @@ -1643,9 +1654,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type if (language_count > 0) { /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */ - if (language_count > sizeof(language) / 4) { - language_count = sizeof(language) / 4; - } + av_assert0(language_count <= sizeof(language) / 4); if (st->codec->extradata == NULL) { if (ff_alloc_extradata(st->codec, language_count * 2)) { @@ -1695,9 +1704,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type uint8_t *extradata; /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */ - if (language_count > sizeof(language) / 4) { - language_count = sizeof(language) / 4; - } + av_assert0(language_count <= sizeof(language) / 4); if (st->codec->extradata == NULL) { if (ff_alloc_extradata(st->codec, language_count * 5)) { @@ -1789,7 +1796,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type ext_desc_tag == 0x80) { /* User defined (provisional Opus) */ if (!st->codec->extradata) { st->codec->extradata = av_mallocz(sizeof(opus_default_extradata) + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); @@ -2378,7 +2385,7 @@ static void finished_reading_packet(AVFormatContext *s, int raw_packet_size) static int handle_packets(MpegTSContext *ts, int64_t nb_packets) { AVFormatContext *s = ts->stream; - uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; + uint8_t packet[TS_PACKET_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; const uint8_t *data; int64_t packet_num; int ret = 0; @@ -2405,7 +2412,7 @@ static int handle_packets(MpegTSContext *ts, int64_t nb_packets) ts->stop_parse = 0; packet_num = 0; - memset(packet + TS_PACKET_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(packet + TS_PACKET_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE); for (;;) { packet_num++; if (nb_packets != 0 && packet_num >= nb_packets || @@ -2439,7 +2446,7 @@ static int mpegts_probe(AVProbeData *p) #define CHECK_BLOCK 100 if (check_count < CHECK_COUNT) - return AVERROR_INVALIDDATA; + return 0; for (i = 0; i<check_count; i+=CHECK_BLOCK) { int left = FFMIN(check_count - i, CHECK_BLOCK); @@ -2454,12 +2461,12 @@ static int mpegts_probe(AVProbeData *p) sumscore = sumscore * CHECK_COUNT / check_count; maxscore = maxscore * CHECK_COUNT / CHECK_BLOCK; - av_dlog(0, "TS score: %d %d\n", sumscore, maxscore); + ff_dlog(0, "TS score: %d %d\n", sumscore, maxscore); if (sumscore > 6) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT; else if (maxscore > 6) return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT; else - return AVERROR_INVALIDDATA; + return 0; } /* return the 90kHz PCR and the extension for the 27MHz PCR. return @@ -2505,7 +2512,12 @@ static int mpegts_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; uint8_t buf[8 * 1024] = {0}; int len; - int64_t pos, probesize = s->probesize ? s->probesize : s->probesize2; + int64_t pos, probesize = +#if FF_API_PROBESIZE_32 + s->probesize ? s->probesize : s->probesize2; +#else + s->probesize; +#endif if (ffio_ensure_seekback(pb, probesize) < 0) av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c index 9efa9fc3624..45bab1ce01a 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c @@ -98,9 +98,14 @@ typedef struct MpegTSWrite { int pcr_period; #define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01 #define MPEGTS_FLAG_AAC_LATM 0x02 +#define MPEGTS_FLAG_PAT_PMT_AT_FRAMES 0x04 int flags; int copyts; int tables_version; + float pat_period; + float sdt_period; + int64_t last_pat_ts; + int64_t last_sdt_ts; int omit_video_pes_length; } MpegTSWrite; @@ -783,6 +788,16 @@ static int mpegts_write_header(AVFormatContext *s) service->pcr_packet_period = 1; } + ts->last_pat_ts = AV_NOPTS_VALUE; + ts->last_sdt_ts = AV_NOPTS_VALUE; + // The user specified a period, use only it + if (ts->pat_period < INT_MAX/2) { + ts->pat_packet_period = INT_MAX; + } + if (ts->sdt_period < INT_MAX/2) { + ts->sdt_packet_period = INT_MAX; + } + // output a PCR as soon as possible service->pcr_packet_count = service->pcr_packet_period; ts->pat_packet_count = ts->pat_packet_period - 1; @@ -833,17 +848,27 @@ fail: } /* send SDT, PAT and PMT tables regulary */ -static void retransmit_si_info(AVFormatContext *s, int force_pat) +static void retransmit_si_info(AVFormatContext *s, int force_pat, int64_t dts) { MpegTSWrite *ts = s->priv_data; int i; - if (++ts->sdt_packet_count == ts->sdt_packet_period) { + if (++ts->sdt_packet_count == ts->sdt_packet_period || + (dts != AV_NOPTS_VALUE && ts->last_sdt_ts == AV_NOPTS_VALUE) || + (dts != AV_NOPTS_VALUE && dts - ts->last_sdt_ts >= ts->sdt_period*90000.0) + ) { ts->sdt_packet_count = 0; + if (dts != AV_NOPTS_VALUE) + ts->last_sdt_ts = FFMAX(dts, ts->last_sdt_ts); mpegts_write_sdt(s); } - if (++ts->pat_packet_count == ts->pat_packet_period || force_pat) { + if (++ts->pat_packet_count == ts->pat_packet_period || + (dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) || + (dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) || + force_pat) { ts->pat_packet_count = 0; + if (dts != AV_NOPTS_VALUE) + ts->last_pat_ts = FFMAX(dts, ts->last_pat_ts); mpegts_write_pat(s); for (i = 0; i < ts->nb_services; i++) mpegts_write_pmt(s, ts->services[i]); @@ -971,9 +996,14 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE); int force_pat = st->codec->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key; + av_assert0(ts_st->payload != buf || st->codec->codec_type != AVMEDIA_TYPE_VIDEO); + if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + force_pat = 1; + } + is_start = 1; while (payload_size > 0) { - retransmit_si_info(s, force_pat); + retransmit_si_info(s, force_pat, dts); force_pat = 0; write_pcr = 0; @@ -1313,9 +1343,9 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) if (!ts_st->amux) { av_log(s, AV_LOG_ERROR, "AAC bitstream not in ADTS format " "and extradata missing\n"); - return AVERROR_INVALIDDATA; - } - + if (!st->nb_frames) + return AVERROR_INVALIDDATA; + } else { av_init_packet(&pkt2); pkt2.data = pkt->data; pkt2.size = pkt->size; @@ -1334,6 +1364,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) size = avio_close_dyn_buf(ts_st->amux->pb, &data); ts_st->amux->pb = NULL; buf = data; + } } } else if (st->codec->codec_id == AV_CODEC_ID_HEVC) { int ret = check_hevc_startcode(s, st, pkt); @@ -1504,6 +1535,9 @@ static const AVOption options[] = { { "latm", "Use LATM packetization for AAC", 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_AAC_LATM }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, + { "pat_pmt_at_frames", "Reemit PAT and PMT at each video frame", + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_PAT_PMT_AT_FRAMES}, 0, INT_MAX, + AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, // backward compatibility { "resend_headers", "Reemit PAT/PMT before writing the next packet", offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT, @@ -1520,6 +1554,12 @@ static const AVOption options[] = { { "pcr_period", "PCR retransmission time", offsetof(MpegTSWrite, pcr_period), AV_OPT_TYPE_INT, { .i64 = PCR_RETRANS_TIME }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { "pat_period", "PAT/PMT retransmission time limit in seconds", + offsetof(MpegTSWrite, pat_period), AV_OPT_TYPE_FLOAT, + { .dbl = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { "sdt_period", "SDT retransmission time limit in seconds", + offsetof(MpegTSWrite, sdt_period), AV_OPT_TYPE_FLOAT, + { .dbl = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, }; @@ -1541,6 +1581,6 @@ AVOutputFormat ff_mpegts_muxer = { .write_header = mpegts_write_header, .write_packet = mpegts_write_packet, .write_trailer = mpegts_write_end, - .flags = AVFMT_ALLOW_FLUSH, + .flags = AVFMT_ALLOW_FLUSH | AVFMT_VARIABLE_FPS, .priv_class = &mpegts_muxer_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/mpjpeg.c b/chromium/third_party/ffmpeg/libavformat/mpjpeg.c index 7b975e28d6c..3904ccb2b43 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpjpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/mpjpeg.c @@ -33,10 +33,7 @@ typedef struct MPJPEGContext { static int mpjpeg_write_header(AVFormatContext *s) { MPJPEGContext *mpj = s->priv_data; - uint8_t buf1[256]; - - snprintf(buf1, sizeof(buf1), "--%s\r\n", mpj->boundary_tag); - avio_write(s->pb, buf1, strlen(buf1)); + avio_printf(s->pb, "--%s\r\n", mpj->boundary_tag); avio_flush(s->pb); return 0; } @@ -44,17 +41,12 @@ static int mpjpeg_write_header(AVFormatContext *s) static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt) { MPJPEGContext *mpj = s->priv_data; - uint8_t buf1[256]; - - snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\r\n"); - avio_write(s->pb, buf1, strlen(buf1)); - - snprintf(buf1, sizeof(buf1), "Content-length: %d\r\n\r\n", pkt->size); - avio_write(s->pb, buf1, strlen(buf1)); + avio_printf(s->pb, "Content-type: image/jpeg\r\n"); + avio_printf(s->pb, "Content-length: %d\r\n\r\n", + pkt->size); avio_write(s->pb, pkt->data, pkt->size); - snprintf(buf1, sizeof(buf1), "\r\n--%s\r\n", mpj->boundary_tag); - avio_write(s->pb, buf1, strlen(buf1)); + avio_printf(s->pb, "\r\n--%s\r\n", mpj->boundary_tag); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/mpjpegdec.c b/chromium/third_party/ffmpeg/libavformat/mpjpegdec.c index 845e95cb744..d9553040e85 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpjpegdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mpjpegdec.c @@ -40,6 +40,19 @@ static int get_line(AVIOContext *pb, char *line, int line_size) return 0; } + +static void trim_right(char* p) +{ + char *end; + if (!p || !*p) + return; + end = p + strlen(p) - 1; + while (end != p && av_isspace(*end)) { + *end = '\0'; + end--; + } +} + static int split_tag_value(char **tag, char **value, char *line) { char *p = line; @@ -51,6 +64,7 @@ static int split_tag_value(char **tag, char **value, char *line) *p = '\0'; *tag = line; + trim_right(*tag); p++; @@ -58,6 +72,7 @@ static int split_tag_value(char **tag, char **value, char *line) p++; *value = p; + trim_right(*value); return 0; } @@ -77,6 +92,8 @@ static int check_content_type(char *line) return 0; } +static int parse_multipart_header(AVIOContext *pb, void *log_ctx); + static int mpjpeg_read_probe(AVProbeData *p) { AVIOContext *pb; @@ -90,17 +107,7 @@ static int mpjpeg_read_probe(AVProbeData *p) if (!pb) return AVERROR(ENOMEM); - while (!pb->eof_reached) { - ret = get_line(pb, line, sizeof(line)); - if (ret < 0) - break; - - ret = check_content_type(line); - if (!ret) { - ret = AVPROBE_SCORE_MAX; - break; - } - } + ret = (parse_multipart_header(pb, NULL)>0)?AVPROBE_SCORE_MAX:0; av_free(pb); @@ -123,6 +130,8 @@ static int mpjpeg_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_MJPEG; @@ -145,25 +154,28 @@ static int parse_content_length(const char *value) return val; } -static int parse_multipart_header(AVFormatContext *s) +static int parse_multipart_header(AVIOContext *pb, void *log_ctx) { char line[128]; int found_content_type = 0; int ret, size = -1; - ret = get_line(s->pb, line, sizeof(line)); + ret = get_line(pb, line, sizeof(line)); if (ret < 0) return ret; if (strncmp(line, "--", 2)) return AVERROR_INVALIDDATA; - while (!s->pb->eof_reached) { + while (!pb->eof_reached) { char *tag, *value; - ret = get_line(s->pb, line, sizeof(line)); - if (ret < 0) + ret = get_line(pb, line, sizeof(line)); + if (ret < 0) { + if (ret == AVERROR_EOF) + break; return ret; + } if (line[0] == '\0') break; @@ -174,9 +186,12 @@ static int parse_multipart_header(AVFormatContext *s) if (!av_strcasecmp(tag, "Content-type")) { if (av_strcasecmp(value, "image/jpeg")) { - av_log(s, AV_LOG_ERROR, - "Unexpected %s : %s\n", - tag, value); + if (log_ctx) { + av_log(log_ctx, AV_LOG_ERROR, + "Unexpected %s : %s\n", + tag, value); + } + return AVERROR_INVALIDDATA; } else found_content_type = 1; @@ -197,7 +212,7 @@ static int parse_multipart_header(AVFormatContext *s) static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret; - int size = parse_multipart_header(s); + int size = parse_multipart_header(s->pb, s); if (size < 0) return size; diff --git a/chromium/third_party/ffmpeg/libavformat/mpl2dec.c b/chromium/third_party/ffmpeg/libavformat/mpl2dec.c index 260b7be0ecd..81cc0bbb2d9 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpl2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/mpl2dec.c @@ -108,7 +108,7 @@ static int mpl2_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&mpl2->q); + ff_subtitles_queue_finalize(s, &mpl2->q); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/mpsubdec.c b/chromium/third_party/ffmpeg/libavformat/mpsubdec.c index 7c26d4f42ce..c5a50ecb5cf 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpsubdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mpsubdec.c @@ -103,7 +103,7 @@ static int mpsub_read_header(AVFormatContext *s) st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_TEXT; - ff_subtitles_queue_finalize(&mpsub->q); + ff_subtitles_queue_finalize(s, &mpsub->q); end: av_bprint_finalize(&buf, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/msnwc_tcp.c b/chromium/third_party/ffmpeg/libavformat/msnwc_tcp.c index 60225af61cd..2ec18fb5542 100644 --- a/chromium/third_party/ffmpeg/libavformat/msnwc_tcp.c +++ b/chromium/third_party/ffmpeg/libavformat/msnwc_tcp.c @@ -67,7 +67,7 @@ static int msnwc_tcp_probe(AVProbeData *p) } } - return -1; + return 0; } static int msnwc_tcp_read_header(AVFormatContext *ctx) diff --git a/chromium/third_party/ffmpeg/libavformat/mux.c b/chromium/third_party/ffmpeg/libavformat/mux.c index f1d7927b8ea..3856d8271a4 100644 --- a/chromium/third_party/ffmpeg/libavformat/mux.c +++ b/chromium/third_party/ffmpeg/libavformat/mux.c @@ -61,7 +61,7 @@ * @param num must be >= 0 * @param den must be >= 1 */ -static void frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den) +static void frac_init(FFFrac *f, int64_t val, int64_t num, int64_t den) { num += (den >> 1); if (num >= den) { @@ -79,7 +79,7 @@ static void frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den) * @param f fractional number * @param incr increment, can be positive or negative */ -static void frac_add(AVFrac *f, int64_t incr) +static void frac_add(FFFrac *f, int64_t incr) { int64_t num, den; @@ -250,10 +250,23 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) (ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; + if (s->nb_streams && s->streams[0]->codec->flags & AV_CODEC_FLAG_BITEXACT) { + if (!(s->flags & AVFMT_FLAG_BITEXACT)) { #if FF_API_LAVF_BITEXACT - if (s->nb_streams && s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT) - s->flags |= AVFMT_FLAG_BITEXACT; + av_log(s, AV_LOG_WARNING, + "Setting the AVFormatContext to bitexact mode, because " + "the AVCodecContext is in that mode. This behavior will " + "change in the future. To keep the current behavior, set " + "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); + s->flags |= AVFMT_FLAG_BITEXACT; +#else + av_log(s, AV_LOG_WARNING, + "The AVFormatContext is not in set to bitexact mode, only " + "the AVCodecContext. If this is not intended, set " + "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); #endif + } + } // some sanity checks if (s->nb_streams == 0 && !(of->flags & AVFMT_NOSTREAMS)) { @@ -348,7 +361,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (of->flags & AVFMT_GLOBALHEADER && - !(codec->flags & CODEC_FLAG_GLOBAL_HEADER)) + !(codec->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) av_log(s, AV_LOG_WARNING, "Codec for stream %d does not use global headers " "but container format requires global headers\n", i); @@ -414,13 +427,19 @@ static int init_pts(AVFormatContext *s) default: break; } + + if (!st->priv_pts) + st->priv_pts = av_mallocz(sizeof(*st->priv_pts)); + if (!st->priv_pts) + return AVERROR(ENOMEM); + if (den != AV_NOPTS_VALUE) { if (den <= 0) return AVERROR_INVALIDDATA; #if FF_API_LAVF_FRAC FF_DISABLE_DEPRECATION_WARNINGS - frac_init(&st->pts, 0, 0, den); + frac_init(st->priv_pts, 0, 0, den); FF_ENABLE_DEPRECATION_WARNINGS #endif } @@ -508,7 +527,7 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) FF_DISABLE_DEPRECATION_WARNINGS pkt->dts = // pkt->pts= st->cur_dts; - pkt->pts = st->pts.val; + pkt->pts = st->priv_pts->val; FF_ENABLE_DEPRECATION_WARNINGS #endif } @@ -548,7 +567,7 @@ FF_ENABLE_DEPRECATION_WARNINGS st->cur_dts = pkt->dts; #if FF_API_LAVF_FRAC FF_DISABLE_DEPRECATION_WARNINGS - st->pts.val = pkt->dts; + st->priv_pts->val = pkt->dts; FF_ENABLE_DEPRECATION_WARNINGS #endif @@ -564,8 +583,8 @@ FF_ENABLE_DEPRECATION_WARNINGS * had the real timestamps from the encoder */ #if FF_API_LAVF_FRAC FF_DISABLE_DEPRECATION_WARNINGS - if (frame_size >= 0 && (pkt->size || st->pts.num != st->pts.den >> 1 || st->pts.val)) { - frac_add(&st->pts, (int64_t)st->time_base.den * frame_size); + if (frame_size >= 0 && (pkt->size || st->priv_pts->num != st->priv_pts->den >> 1 || st->priv_pts->val)) { + frac_add(st->priv_pts, (int64_t)st->time_base.den * frame_size); FF_ENABLE_DEPRECATION_WARNINGS #endif } @@ -573,7 +592,7 @@ FF_ENABLE_DEPRECATION_WARNINGS case AVMEDIA_TYPE_VIDEO: #if FF_API_LAVF_FRAC FF_DISABLE_DEPRECATION_WARNINGS - frac_add(&st->pts, (int64_t)st->time_base.den * st->codec->time_base.num); + frac_add(st->priv_pts, (int64_t)st->time_base.den * st->codec->time_base.num); FF_ENABLE_DEPRECATION_WARNINGS #endif break; @@ -661,8 +680,13 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) ret = s->oformat->write_packet(s, pkt); } - if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) - avio_flush(s->pb); + if (s->pb && ret >= 0) { + if (s->flush_packets && s->flags & AVFMT_FLAG_FLUSH_PACKETS) + avio_flush(s->pb); + if (s->pb->error < 0) + ret = s->pb->error; + } + if (did_split) av_packet_merge_side_data(pkt); @@ -737,11 +761,6 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, if (!this_pktl) return AVERROR(ENOMEM); this_pktl->pkt = *pkt; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = NULL; // do not free original but only the copy -FF_ENABLE_DEPRECATION_WARNINGS -#endif pkt->buf = NULL; pkt->side_data = NULL; pkt->side_data_elems = 0; @@ -1065,7 +1084,8 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, pkt->buf = local_pkt.buf; #if FF_API_DESTRUCT_PACKET FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = local_pkt.destruct; + pkt->side_data = local_pkt.side_data; + pkt->side_data_elems = local_pkt.side_data_elems; FF_ENABLE_DEPRECATION_WARNINGS #endif return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.c b/chromium/third_party/ffmpeg/libavformat/mxf.c index ecfb8a23933..4d77ada71e9 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.c +++ b/chromium/third_party/ffmpeg/libavformat/mxf.c @@ -42,6 +42,16 @@ const MXFCodecUL ff_mxf_codec_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x20,0x02,0x03 }, 14, AV_CODEC_ID_MPEG4 }, /* XDCAM proxy_pal030926.mxf */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x01,0x02,0x00 }, 13, AV_CODEC_ID_DVVIDEO }, /* DV25 IEC PAL */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x01,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 SP@LL */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x02,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 SP@ML */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x03,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 MP@LL */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x04,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 MP@ML */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x05,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 MP@HL */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x06,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 AP@L0 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x07,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 AP@L1 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x08,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 AP@L2 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x09,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 AP@L3 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x04,0x0A,0x00,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC1 AP@L4 */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x01,0x7F,0x00,0x00,0x00 }, 13, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, 15, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed 422 8-bit */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x71,0x00,0x00,0x00 }, 13, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */ @@ -69,6 +79,11 @@ const MXFCodecUL ff_mxf_pixel_format_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_PIX_FMT_NONE }, }; +const MXFCodecUL ff_mxf_codec_tag_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x03,0x01,0x01,0x03,0x01,0x00 }, 15, MKTAG('A', 'V', 'u', 'p') }, /* Avid 1:1 */ + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, 0 }, +}; + static const struct { enum AVPixelFormat pix_fmt; const char data[16]; diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.h b/chromium/third_party/ffmpeg/libavformat/mxf.h index 1763063a695..f3db1f939bb 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.h +++ b/chromium/third_party/ffmpeg/libavformat/mxf.h @@ -78,6 +78,7 @@ typedef struct { extern const MXFCodecUL ff_mxf_data_definition_uls[]; extern const MXFCodecUL ff_mxf_codec_uls[]; extern const MXFCodecUL ff_mxf_pixel_format_uls[]; +extern const MXFCodecUL ff_mxf_codec_tag_uls[]; int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt); const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base); diff --git a/chromium/third_party/ffmpeg/libavformat/mxfdec.c b/chromium/third_party/ffmpeg/libavformat/mxfdec.c index b3c25b765e5..00d420b4450 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfdec.c @@ -233,6 +233,7 @@ typedef struct MXFIndexTable { int nb_segments; MXFIndexTableSegment **segments; /* sorted by IndexStartPosition */ AVIndexEntry *fake_index; /* used for calling ff_index_search_timestamp() */ + int8_t *offsets; /* temporal offsets for display order to stored order conversion */ } MXFIndexTable; typedef struct MXFContext { @@ -1120,7 +1121,11 @@ static void *mxf_resolve_strong_ref(MXFContext *mxf, UID *strong_ref, enum MXFMe static const MXFCodecUL mxf_picture_essence_container_uls[] = { // video essence container uls + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, 14, AV_CODEC_ID_H264 }, /* H264 Frame wrapped */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x12,0x01,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC-1 Frame wrapped */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x04,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* Type D-10 mapping of 40Mbps 525/60-I */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */ { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4f }, 14, AV_CODEC_ID_RAWVIDEO }, /* Legacy ?? Uncompressed Picture */ @@ -1155,11 +1160,6 @@ static const MXFCodecUL mxf_data_essence_container_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; -static const MXFCodecUL mxf_codec_uls[] = { - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, - { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, -}; - static const char* const mxf_data_essence_descriptor[] = { "vbi_vanc_smpte_436M", }; @@ -1334,6 +1334,7 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta { int i, j, x; int8_t max_temporal_offset = -128; + uint8_t *flags; /* first compute how many entries we have */ for (i = 0; i < index_table->nb_segments; i++) { @@ -1352,8 +1353,12 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta return 0; if (!(index_table->ptses = av_calloc(index_table->nb_ptses, sizeof(int64_t))) || - !(index_table->fake_index = av_calloc(index_table->nb_ptses, sizeof(AVIndexEntry)))) { + !(index_table->fake_index = av_calloc(index_table->nb_ptses, sizeof(AVIndexEntry))) || + !(index_table->offsets = av_calloc(index_table->nb_ptses, sizeof(int8_t))) || + !(flags = av_calloc(index_table->nb_ptses, sizeof(uint8_t)))) { av_freep(&index_table->ptses); + av_freep(&index_table->fake_index); + av_freep(&index_table->offsets); return AVERROR(ENOMEM); } @@ -1411,8 +1416,7 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta break; } - index_table->fake_index[x].timestamp = x; - index_table->fake_index[x].flags = !(s->flag_entries[j] & 0x30) ? AVINDEX_KEYFRAME : 0; + flags[x] = !(s->flag_entries[j] & 0x30) ? AVINDEX_KEYFRAME : 0; if (index < 0 || index >= index_table->nb_ptses) { av_log(mxf->fc, AV_LOG_ERROR, @@ -1421,11 +1425,20 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta continue; } + index_table->offsets[x] = offset; index_table->ptses[index] = x; max_temporal_offset = FFMAX(max_temporal_offset, offset); } } + /* calculate the fake index table in display order */ + for (x = 0; x < index_table->nb_ptses; x++) { + index_table->fake_index[x].timestamp = x; + if (index_table->ptses[x] != AV_NOPTS_VALUE) + index_table->fake_index[index_table->ptses[x]].flags = flags[x]; + } + av_freep(&flags); + index_table->first_dts = -max_temporal_offset; return 0; @@ -1960,7 +1973,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul); st->codec->codec_id = (enum AVCodecID)codec_ul->id; if (st->codec->codec_id == AV_CODEC_ID_NONE) { - codec_ul = mxf_get_codec_ul(mxf_codec_uls, &descriptor->codec_ul); + codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->codec_ul); st->codec->codec_id = (enum AVCodecID)codec_ul->id; } @@ -1988,10 +2001,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->width = descriptor->width; st->codec->height = descriptor->height; /* Field height, not frame height */ switch (descriptor->frame_layout) { - case SegmentedFrame: - /* This one is a weird layout I don't fully understand. */ - av_log(mxf->fc, AV_LOG_INFO, "SegmentedFrame layout isn't currently supported\n"); - break; case FullFrame: st->codec->field_order = AV_FIELD_PROGRESSIVE; break; @@ -2003,6 +2012,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) It's also for compatibility with the old behavior. */ case MixedFields: break; + case SegmentedFrame: + st->codec->field_order = AV_FIELD_PROGRESSIVE; case SeparateFields: switch (descriptor->field_dominance) { case MXF_TFF: @@ -2031,12 +2042,16 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) &descriptor->essence_codec_ul); st->codec->pix_fmt = (enum AVPixelFormat)pix_fmt_ul->id; if (st->codec->pix_fmt == AV_PIX_FMT_NONE) { - /* support files created before RP224v10 by defaulting to UYVY422 - if subsampling is 4:2:2 and component depth is 8-bit */ - if (descriptor->horiz_subsampling == 2 && - descriptor->vert_subsampling == 1 && - descriptor->component_depth == 8) { - st->codec->pix_fmt = AV_PIX_FMT_UYVY422; + st->codec->codec_tag = mxf_get_codec_ul(ff_mxf_codec_tag_uls, + &descriptor->essence_codec_ul)->id; + if (!st->codec->codec_tag) { + /* support files created before RP224v10 by defaulting to UYVY422 + if subsampling is 4:2:2 and component depth is 8-bit */ + if (descriptor->horiz_subsampling == 2 && + descriptor->vert_subsampling == 1 && + descriptor->component_depth == 8) { + st->codec->pix_fmt = AV_PIX_FMT_UYVY422; + } } } } @@ -3085,6 +3100,7 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->index_tables[i].segments); av_freep(&mxf->index_tables[i].ptses); av_freep(&mxf->index_tables[i].fake_index); + av_freep(&mxf->index_tables[i].offsets); } } av_freep(&mxf->index_tables); @@ -3158,6 +3174,8 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti /* behave as if we have a proper index */ if ((sample_time = ff_index_search_timestamp(t->fake_index, t->nb_ptses, sample_time, flags)) < 0) return sample_time; + /* get the stored order index from the display order index */ + sample_time += t->offsets[sample_time]; } else { /* no IndexEntryArray (one or more CBR segments) * make sure we don't seek past the end */ @@ -3191,6 +3209,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti AVInputFormat ff_mxf_demuxer = { .name = "mxf", .long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"), + .flags = AVFMT_SEEK_TO_PTS, .priv_data_size = sizeof(MXFContext), .read_probe = mxf_probe, .read_header = mxf_read_header, diff --git a/chromium/third_party/ffmpeg/libavformat/mxfenc.c b/chromium/third_party/ffmpeg/libavformat/mxfenc.c index db7d2bf4552..84ce979c610 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfenc.c @@ -21,6 +21,10 @@ */ /* + * signal_standard, color_siting and klv_fill_key version fixes sponsored by NOA GmbH + */ + +/* * References * SMPTE 336M KLV Data Encoding Protocol Using Key-Length-Value * SMPTE 377M MXF File Format Specifications @@ -2056,7 +2060,7 @@ static int mxf_write_header(AVFormatContext *s) sc->color_siting = 0xFF; if (pix_desc) { - sc->component_depth = pix_desc->comp[0].depth_minus1 + 1; + sc->component_depth = pix_desc->comp[0].depth; sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w; } switch (ff_choose_chroma_location(s, st)) { diff --git a/chromium/third_party/ffmpeg/libavformat/mxg.c b/chromium/third_party/ffmpeg/libavformat/mxg.c index 34977b8197d..45cc5b5284c 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxg.c +++ b/chromium/third_party/ffmpeg/libavformat/mxg.c @@ -111,7 +111,7 @@ static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size) soi_pos = mxg->soi_ptr - mxg->buffer; buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size, current_pos + cache_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!buffer) return AVERROR(ENOMEM); mxg->buffer = buffer; @@ -171,18 +171,13 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pts = pkt->dts = mxg->dts; pkt->stream_index = 0; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pkt->buf = NULL; pkt->size = mxg->buffer_ptr - mxg->soi_ptr; pkt->data = mxg->soi_ptr; if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) { if (mxg->cache_size > 0) { - memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size); + memmove(mxg->buffer, mxg->buffer_ptr, mxg->cache_size); } mxg->buffer_ptr = mxg->buffer; @@ -214,11 +209,6 @@ FF_ENABLE_DEPRECATION_WARNINGS /* time (GMT) of first sample in usec since 1970, little-endian */ pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8); pkt->stream_index = 1; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pkt->buf = NULL; pkt->size = size - 14; pkt->data = startmarker_ptr + 16; diff --git a/chromium/third_party/ffmpeg/libavformat/network.c b/chromium/third_party/ffmpeg/libavformat/network.c index 47ade8cb62f..7a326d2c4e1 100644 --- a/chromium/third_party/ffmpeg/libavformat/network.c +++ b/chromium/third_party/ffmpeg/libavformat/network.c @@ -187,12 +187,11 @@ int ff_socket(int af, int type, int proto) return fd; } -int ff_listen_bind(int fd, const struct sockaddr *addr, - socklen_t addrlen, int timeout, URLContext *h) +int ff_listen(int fd, const struct sockaddr *addr, + socklen_t addrlen) { int ret; int reuse = 1; - struct pollfd lp = { fd, POLLIN, 0 }; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); } @@ -203,6 +202,13 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, ret = listen(fd, 1); if (ret) return ff_neterrno(); + return ret; +} + +int ff_accept(int fd, int timeout, URLContext *h) +{ + int ret; + struct pollfd lp = { fd, POLLIN, 0 }; ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); if (ret < 0) @@ -211,15 +217,24 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, ret = accept(fd, NULL, NULL); if (ret < 0) return ff_neterrno(); - - closesocket(fd); - if (ff_socket_nonblock(ret, 1) < 0) av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); return ret; } +int ff_listen_bind(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h) +{ + int ret; + if ((ret = ff_listen(fd, addr, addrlen)) < 0) + return ret; + if ((ret = ff_accept(fd, timeout, h)) < 0) + return ret; + closesocket(fd); + return ret; +} + int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next) diff --git a/chromium/third_party/ffmpeg/libavformat/network.h b/chromium/third_party/ffmpeg/libavformat/network.h index 86fb6561647..f83c796a95a 100644 --- a/chromium/third_party/ffmpeg/libavformat/network.h +++ b/chromium/third_party/ffmpeg/libavformat/network.h @@ -255,6 +255,26 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, URLContext *h); /** + * Bind to a file descriptor to an address without accepting connections. + * @param fd First argument of bind(). + * @param addr Second argument of bind(). + * @param addrlen Third argument of bind(). + * @return 0 on success or an AVERROR on failure. + */ +int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen); + +/** + * Poll for a single connection on the passed file descriptor. + * @param fd The listening socket file descriptor. + * @param timeout Polling timeout in milliseconds. + * @param h URLContext providing interrupt check + * callback and logging context. + * @return A non-blocking file descriptor on success + * or an AVERROR on failure. + */ +int ff_accept(int fd, int timeout, URLContext *h); + +/** * Connect to a file descriptor and poll for result. * * @param fd First argument of connect(), diff --git a/chromium/third_party/ffmpeg/libavformat/nutdec.c b/chromium/third_party/ffmpeg/libavformat/nutdec.c index 13fb39924d2..63b0cd2fb95 100644 --- a/chromium/third_party/ffmpeg/libavformat/nutdec.c +++ b/chromium/third_party/ffmpeg/libavformat/nutdec.c @@ -1005,6 +1005,9 @@ static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int AV_WL32(dst+4, skip_end); } + if (avio_tell(bc) >= maxpos) + return AVERROR_INVALIDDATA; + return 0; } @@ -1277,6 +1280,8 @@ static int read_seek(AVFormatContext *s, int stream_index, next_node[1]->pos, next_node[1]->pos, next_node[0]->ts, next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp); + if (pos < 0) + return pos; if (!(flags & AVSEEK_FLAG_BACKWARD)) { dummy.pos = pos + 16; diff --git a/chromium/third_party/ffmpeg/libavformat/nutenc.c b/chromium/third_party/ffmpeg/libavformat/nutenc.c index 1522a0452fe..49d62bfbecc 100644 --- a/chromium/third_party/ffmpeg/libavformat/nutenc.c +++ b/chromium/third_party/ffmpeg/libavformat/nutenc.c @@ -933,6 +933,7 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int break; case AV_PKT_DATA_METADATA_UPDATE: case AV_PKT_DATA_STRINGS_METADATA: + case AV_PKT_DATA_QUALITY_STATS: // belongs into meta, not side data break; } diff --git a/chromium/third_party/ffmpeg/libavformat/oggdec.c b/chromium/third_party/ffmpeg/libavformat/oggdec.c index 4f4d085dbd1..ae56915b580 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggdec.c +++ b/chromium/third_party/ffmpeg/libavformat/oggdec.c @@ -60,6 +60,7 @@ static const struct ogg_codec * const ogg_codecs[] = { static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts); static int ogg_new_stream(AVFormatContext *s, uint32_t serial); +static int ogg_restore(AVFormatContext *s, int discard); //FIXME We could avoid some structure duplication static int ogg_save(AVFormatContext *s) @@ -68,6 +69,7 @@ static int ogg_save(AVFormatContext *s) struct ogg_state *ost = av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams)); int i; + int ret = 0; if (!ost) return AVERROR(ENOMEM); @@ -80,15 +82,21 @@ static int ogg_save(AVFormatContext *s) for (i = 0; i < ogg->nstreams; i++) { struct ogg_stream *os = ogg->streams + i; - os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE); - memcpy(os->buf, ost->streams[i].buf, os->bufpos); + os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); + if (os->buf) + memcpy(os->buf, ost->streams[i].buf, os->bufpos); + else + ret = AVERROR(ENOMEM); os->new_metadata = NULL; os->new_metadata_size = 0; } ogg->state = ost; - return 0; + if (ret < 0) + ogg_restore(s, 0); + + return ret; } static int ogg_restore(AVFormatContext *s, int discard) @@ -255,7 +263,7 @@ static int ogg_new_stream(AVFormatContext *s, uint32_t serial) memset(os, 0, sizeof(*os)); os->serial = serial; os->bufsize = DECODER_BUFFER_SIZE; - os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE); + os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); os->header = -1; os->start_granule = OGG_NOGRANULE_VALUE; if (!os->buf) @@ -277,7 +285,7 @@ static int ogg_new_stream(AVFormatContext *s, uint32_t serial) static int ogg_new_buf(struct ogg *ogg, int idx) { struct ogg_stream *os = ogg->streams + idx; - uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE); + uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); int size = os->bufpos - os->pstart; if (!nb) @@ -416,7 +424,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) } if (os->bufsize - os->bufpos < size) { - uint8_t *nb = av_malloc((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE); + uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE); if (!nb) return AVERROR(ENOMEM); memcpy(nb, os->buf, os->bufpos); @@ -432,7 +440,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) os->granule = gp; os->flags = flags; - memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (sid) *sid = idx; diff --git a/chromium/third_party/ffmpeg/libavformat/oggenc.c b/chromium/third_party/ffmpeg/libavformat/oggenc.c index 2c0a44e4559..49075129891 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggenc.c +++ b/chromium/third_party/ffmpeg/libavformat/oggenc.c @@ -260,7 +260,7 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, if (i == total_segments) page->granule = granule; - if (!header) { + { AVStream *st = s->streams[page->stream_index]; int64_t start = av_rescale_q(page->start_granule, st->time_base, @@ -268,10 +268,13 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, int64_t next = av_rescale_q(page->granule, st->time_base, AV_TIME_BASE_Q); - if (page->segments_count == 255 || - (ogg->pref_size > 0 && page->size >= ogg->pref_size) || - (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) { + if (page->segments_count == 255) { ogg_buffer_page(s, oggstream); + } else if (!header) { + if ((ogg->pref_size > 0 && page->size >= ogg->pref_size) || + (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) { + ogg_buffer_page(s, oggstream); + } } } } diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsedirac.c b/chromium/third_party/ffmpeg/libavformat/oggparsedirac.c index 35be6558214..ab40f96c631 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsedirac.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsedirac.c @@ -31,16 +31,19 @@ static int dirac_header(AVFormatContext *s, int idx) AVStream *st = s->streams[idx]; dirac_source_params source; GetBitContext gb; + int ret; // already parsed the header if (st->codec->codec_id == AV_CODEC_ID_DIRAC) return 0; - if (init_get_bits(&gb, os->buf + os->pstart + 13, (os->psize - 13) * 8) < 0) - return -1; + ret = init_get_bits8(&gb, os->buf + os->pstart + 13, (os->psize - 13)); + if (ret < 0) + return ret; - if (avpriv_dirac_parse_sequence_header(st->codec, &gb, &source) < 0) - return -1; + ret = avpriv_dirac_parse_sequence_header(st->codec, &gb, &source); + if (ret < 0) + return ret; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_DIRAC; diff --git a/chromium/third_party/ffmpeg/libavformat/oggparseogm.c b/chromium/third_party/ffmpeg/libavformat/oggparseogm.c index 54024e0a0ab..ae8c3c850cd 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparseogm.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparseogm.c @@ -102,7 +102,7 @@ ogm_header(AVFormatContext *s, int idx) size -= 4; } if (size > 52) { - av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52); + av_assert0(AV_INPUT_BUFFER_PADDING_SIZE <= 52); size -= 52; ff_alloc_extradata(st->codec, size); bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size); diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c b/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c index 91c70dfec9f..e92d4c5170c 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c @@ -127,11 +127,11 @@ static int theora_header(AVFormatContext *s, int idx) } if ((err = av_reallocp(&st->codec->extradata, - cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { st->codec->extradata_size = 0; return err; } - memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(st->codec->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE); cdp = st->codec->extradata + st->codec->extradata_size; *cdp++ = os->psize >> 8; diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c index dd443374375..b96be989747 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c @@ -242,7 +242,7 @@ static int fixup_vorbis_headers(AVFormatContext *as, offset += priv->len[i]; av_freep(&priv->packet[i]); } - if ((err = av_reallocp(buf, offset + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) + if ((err = av_reallocp(buf, offset + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) return err; return offset; } @@ -406,6 +406,9 @@ static int vorbis_packet(AVFormatContext *s, int idx) struct oggvorbis_private *priv = os->private; int duration, flags = 0; + if (!priv->vp) + return AVERROR_INVALIDDATA; + /* first packet handling * here we parse the duration of each packet in the first page and compare * the total duration to the page granule to find the encoder delay and diff --git a/chromium/third_party/ffmpeg/libavformat/options.c b/chromium/third_party/ffmpeg/libavformat/options.c index d238dd5ab70..9918349703a 100644 --- a/chromium/third_party/ffmpeg/libavformat/options.c +++ b/chromium/third_party/ffmpeg/libavformat/options.c @@ -20,6 +20,8 @@ #include "avformat.h" #include "avio_internal.h" #include "internal.h" + +#include "libavutil/internal.h" #include "libavutil/opt.h" /** @@ -27,7 +29,9 @@ * Options definition for AVFormatContext. */ +FF_DISABLE_DEPRECATION_WARNINGS #include "options_table.h" +FF_ENABLE_DEPRECATION_WARNINGS static const char* format_to_name(void* ptr) { diff --git a/chromium/third_party/ffmpeg/libavformat/options_table.h b/chromium/third_party/ffmpeg/libavformat/options_table.h index 58670b0035d..773814a2b96 100644 --- a/chromium/third_party/ffmpeg/libavformat/options_table.h +++ b/chromium/third_party/ffmpeg/libavformat/options_table.h @@ -36,7 +36,11 @@ static const AVOption avformat_options[] = { {"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"}, {"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"}, +#if FF_API_PROBESIZE_32 {"probesize", "set probing size", OFFSET(probesize2), AV_OPT_TYPE_INT64, {.i64 = 5000000 }, 32, INT64_MAX, D}, +#else +{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT64, {.i64 = 5000000 }, 32, INT64_MAX, D}, +#endif {"formatprobesize", "number of bytes to probe file format", OFFSET(format_probesize), AV_OPT_TYPE_INT, {.i64 = PROBE_BUF_MAX}, 0, INT_MAX-1, D}, {"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E}, {"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D|E, "fflags"}, @@ -54,7 +58,11 @@ static const AVOption avformat_options[] = { {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D}, {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, +#if FF_API_PROBESIZE_32 {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration2), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, +#else +{"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, +#endif {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, {"rtbufsize", "max memory used for buffering real-time frames", OFFSET(max_picture_buffer), AV_OPT_TYPE_INT, {.i64 = 3041280 }, 0, INT_MAX, D}, /* defaults to 1s of 15fps 352x288 YUYV422 video */ diff --git a/chromium/third_party/ffmpeg/libavformat/os_support.c b/chromium/third_party/ffmpeg/libavformat/os_support.c index 7950e448891..718bc6ce59b 100644 --- a/chromium/third_party/ffmpeg/libavformat/os_support.c +++ b/chromium/third_party/ffmpeg/libavformat/os_support.c @@ -340,3 +340,4 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) #endif /* !HAVE_POLL_H */ #endif /* CONFIG_NETWORK */ + diff --git a/chromium/third_party/ffmpeg/libavformat/pjsdec.c b/chromium/third_party/ffmpeg/libavformat/pjsdec.c index 5129b70e5fb..a88d5331928 100644 --- a/chromium/third_party/ffmpeg/libavformat/pjsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/pjsdec.c @@ -100,7 +100,7 @@ static int pjs_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&pjs->q); + ff_subtitles_queue_finalize(s, &pjs->q); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/psxstr.c b/chromium/third_party/ffmpeg/libavformat/psxstr.c index fd50e549ae3..3aa08eb93f7 100644 --- a/chromium/third_party/ffmpeg/libavformat/psxstr.c +++ b/chromium/third_party/ffmpeg/libavformat/psxstr.c @@ -238,11 +238,6 @@ static int str_read_packet(AVFormatContext *s, pkt->data= NULL; pkt->size= -1; pkt->buf = NULL; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/qcp.c b/chromium/third_party/ffmpeg/libavformat/qcp.c index 9e2eedfe85d..ad4a8ae79c6 100644 --- a/chromium/third_party/ffmpeg/libavformat/qcp.c +++ b/chromium/third_party/ffmpeg/libavformat/qcp.c @@ -57,6 +57,11 @@ static const uint8_t guid_evrc[16] = { 0x91, 0xef, 0x73, 0x6a, 0x51, 0x00, 0xce, 0xb4 }; +static const uint8_t guid_4gv[16] = { + 0xca, 0x29, 0xfd, 0x3c, 0x53, 0xf6, 0xf5, 0x4e, + 0x90, 0xe9, 0xf4, 0x23, 0x6d, 0x59, 0x9b, 0x61 +}; + /** * SMV GUID as stored in the file */ @@ -106,6 +111,8 @@ static int qcp_read_header(AVFormatContext *s) st->codec->codec_id = AV_CODEC_ID_EVRC; } else if (!memcmp(buf, guid_smv, 16)) { st->codec->codec_id = AV_CODEC_ID_SMV; + } else if (!memcmp(buf, guid_4gv, 16)) { + st->codec->codec_id = AV_CODEC_ID_4GV; } else { av_log(s, AV_LOG_ERROR, "Unknown codec GUID "FF_PRI_GUID".\n", FF_ARG_GUID(buf)); diff --git a/chromium/third_party/ffmpeg/libavformat/rawdec.c b/chromium/third_party/ffmpeg/libavformat/rawdec.c index b903e63fb48..7684e1dd9a0 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rawdec.c @@ -188,10 +188,10 @@ static int mjpeg_probe(AVProbeData *p) } if (nb_invalid*4 + 1 < nb_frames) { - static const char ct_jpeg[] = "\r\nContent-Type: image/jpeg\r\n\r\n"; + static const char ct_jpeg[] = "\r\nContent-Type: image/jpeg\r\n"; int i; - for (i=0; i<FFMIN(p->buf_size - sizeof(ct_jpeg), 100); i++) + for (i=0; i<FFMIN(p->buf_size - (int)sizeof(ct_jpeg), 100); i++) if (!memcmp(p->buf + i, ct_jpeg, sizeof(ct_jpeg) - 1)) return AVPROBE_SCORE_EXTENSION; diff --git a/chromium/third_party/ffmpeg/libavformat/rawenc.c b/chromium/third_party/ffmpeg/libavformat/rawenc.c index e59f1ae95e6..d65c7c79097 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawenc.c +++ b/chromium/third_party/ffmpeg/libavformat/rawenc.c @@ -56,6 +56,25 @@ AVOutputFormat ff_ac3_muxer = { #endif #if CONFIG_ADX_MUXER + +static int adx_write_trailer(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVCodecContext *avctx = s->streams[0]->codec; + + if (pb->seekable) { + int64_t file_size = avio_tell(pb); + uint64_t sample_count = (file_size - 36) / avctx->channels / 18 * 32; + if (sample_count <= UINT32_MAX) { + avio_seek(pb, 12, SEEK_SET); + avio_wb32(pb, sample_count); + avio_seek(pb, file_size, SEEK_SET); + } + } + + return 0; +} + AVOutputFormat ff_adx_muxer = { .name = "adx", .long_name = NULL_IF_CONFIG_SMALL("CRI ADX"), @@ -64,6 +83,7 @@ AVOutputFormat ff_adx_muxer = { .video_codec = AV_CODEC_ID_NONE, .write_header = force_one_stream, .write_packet = ff_raw_write_packet, + .write_trailer = adx_write_trailer, .flags = AVFMT_NOTIMESTAMPS, }; #endif diff --git a/chromium/third_party/ffmpeg/libavformat/rdt.c b/chromium/third_party/ffmpeg/libavformat/rdt.c index bb56a8ba817..046d2732a47 100644 --- a/chromium/third_party/ffmpeg/libavformat/rdt.c +++ b/chromium/third_party/ffmpeg/libavformat/rdt.c @@ -86,7 +86,7 @@ struct PayloadContext { RMStream **rmst; uint8_t *mlti_data; unsigned int mlti_data_size; - char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE]; + char buffer[RTP_MAX_PACKET_LENGTH + AV_INPUT_BUFFER_PADDING_SIZE]; int audio_pkt_cnt; /**< remaining audio packets in rmdec */ }; @@ -398,7 +398,7 @@ rdt_parse_b64buf (unsigned int *target_len, const char *p) len -= 2; /* skip embracing " at start/end */ } *target_len = len * 3 / 4; - target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE); + target = av_mallocz(*target_len + AV_INPUT_BUFFER_PADDING_SIZE); if (!target) return NULL; av_base64_decode(target, p, *target_len); diff --git a/chromium/third_party/ffmpeg/libavformat/realtextdec.c b/chromium/third_party/ffmpeg/libavformat/realtextdec.c index fff85d6ba92..f13321c91a9 100644 --- a/chromium/third_party/ffmpeg/libavformat/realtextdec.c +++ b/chromium/third_party/ffmpeg/libavformat/realtextdec.c @@ -115,7 +115,7 @@ static int realtext_read_header(AVFormatContext *s) } av_bprint_clear(&buf); } - ff_subtitles_queue_finalize(&rt->q); + ff_subtitles_queue_finalize(s, &rt->q); end: av_bprint_finalize(&buf, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/redspark.c b/chromium/third_party/ffmpeg/libavformat/redspark.c index 13a7b37d254..66c2dc5aae1 100644 --- a/chromium/third_party/ffmpeg/libavformat/redspark.c +++ b/chromium/third_party/ffmpeg/libavformat/redspark.c @@ -67,7 +67,7 @@ static int redspark_read_header(AVFormatContext *s) return AVERROR(ENOMEM); codec = st->codec; - header = av_malloc(HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); + header = av_malloc(HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); if (!header) return AVERROR(ENOMEM); pbc = header; diff --git a/chromium/third_party/ffmpeg/libavformat/riff.c b/chromium/third_party/ffmpeg/libavformat/riff.c index ddfa829251d..768b406a1f9 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.c +++ b/chromium/third_party/ffmpeg/libavformat/riff.c @@ -149,6 +149,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_DVVIDEO, MKTAG('p', 'd', 'v', 'c') }, { AV_CODEC_ID_DVVIDEO, MKTAG('S', 'L', '2', '5') }, { AV_CODEC_ID_DVVIDEO, MKTAG('S', 'L', 'D', 'V') }, + { AV_CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', '1') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') }, @@ -323,6 +324,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'C') }, { AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'K') }, { AV_CODEC_ID_JPEG2000, MKTAG('I', 'P', 'J', '2') }, + { AV_CODEC_ID_JPEG2000, MKTAG('A', 'V', 'j', '2') }, /* Avid jpeg2000 */ { AV_CODEC_ID_VMNC, MKTAG('V', 'M', 'n', 'c') }, { AV_CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') }, { AV_CODEC_ID_PNG, MKTAG('M', 'P', 'N', 'G') }, diff --git a/chromium/third_party/ffmpeg/libavformat/riff.h b/chromium/third_party/ffmpeg/libavformat/riff.h index ae5ecef4c5a..d6d91ef52d6 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.h +++ b/chromium/third_party/ffmpeg/libavformat/riff.h @@ -53,6 +53,11 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *t #define FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX 0x00000001 /** + * Tell ff_put_wav_header() to write an empty channel mask. + */ +#define FF_PUT_WAV_HEADER_SKIP_CHANNELMASK 0x00000002 + +/** * Write WAVEFORMAT header structure. * * @param flags a combination of FF_PUT_WAV_HEADER_* constants @@ -62,7 +67,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *t int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags); enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps); -int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, int big_endian); +int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, AVCodecContext *codec, int size, int big_endian); extern const AVCodecTag ff_codec_bmp_tags[]; // exposed through avformat_get_riff_video_tags() extern const AVCodecTag ff_codec_wav_tags[]; diff --git a/chromium/third_party/ffmpeg/libavformat/riffdec.c b/chromium/third_party/ffmpeg/libavformat/riffdec.c index f44df1e672c..7eecdb24b88 100644 --- a/chromium/third_party/ffmpeg/libavformat/riffdec.c +++ b/chromium/third_party/ffmpeg/libavformat/riffdec.c @@ -31,10 +31,12 @@ int ff_get_guid(AVIOContext *s, ff_asf_guid *g) { + int ret; av_assert0(sizeof(*g) == 16); //compiler will optimize this out - if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) { + ret = avio_read(s, *g, sizeof(*g)); + if (ret < (int)sizeof(*g)) { memset(*g, 0, sizeof(*g)); - return AVERROR_INVALIDDATA; + return ret < 0 ? ret : AVERROR_INVALIDDATA; } return 0; } @@ -81,25 +83,29 @@ static void parse_waveformatex(AVIOContext *pb, AVCodecContext *c) } /* "big_endian" values are needed for RIFX file format */ -int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, int big_endian) +int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, + AVCodecContext *codec, int size, int big_endian) { int id; + uint64_t bitrate; - if (size < 14) + if (size < 14) { avpriv_request_sample(codec, "wav header size < 14"); + return AVERROR_INVALIDDATA; + } codec->codec_type = AVMEDIA_TYPE_AUDIO; if (!big_endian) { id = avio_rl16(pb); codec->channels = avio_rl16(pb); codec->sample_rate = avio_rl32(pb); - codec->bit_rate = avio_rl32(pb) * 8; + bitrate = avio_rl32(pb) * 8LL; codec->block_align = avio_rl16(pb); } else { id = avio_rb16(pb); codec->channels = avio_rb16(pb); codec->sample_rate = avio_rb32(pb); - codec->bit_rate = avio_rb32(pb) * 8; + bitrate = avio_rb32(pb) * 8LL; codec->block_align = avio_rb16(pb); } if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */ @@ -142,8 +148,25 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, int big_ if (size > 0) avio_skip(pb, size); } + + if (bitrate > INT_MAX) { + if (s->error_recognition & AV_EF_EXPLODE) { + av_log(s, AV_LOG_ERROR, + "The bitrate %"PRIu64" is too large.\n", + bitrate); + return AVERROR_INVALIDDATA; + } else { + av_log(s, AV_LOG_WARNING, + "The bitrate %"PRIu64" is too large, resetting to 0.", + bitrate); + codec->bit_rate = 0; + } + } else { + codec->bit_rate = bitrate; + } + if (codec->sample_rate <= 0) { - av_log(NULL, AV_LOG_ERROR, + av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", codec->sample_rate); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/riffenc.c b/chromium/third_party/ffmpeg/libavformat/riffenc.c index 85c953f2efe..ceb27f272ca 100644 --- a/chromium/third_party/ffmpeg/libavformat/riffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/riffenc.c @@ -168,8 +168,9 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags) } /* write WAVEFORMATEXTENSIBLE extensions */ if (waveformatextensible) { - int write_channel_mask = enc->strict_std_compliance < FF_COMPLIANCE_NORMAL || - enc->channel_layout < 0x40000; + int write_channel_mask = !(flags & FF_PUT_WAV_HEADER_SKIP_CHANNELMASK) && + (enc->strict_std_compliance < FF_COMPLIANCE_NORMAL || + enc->channel_layout < 0x40000); /* 22 is WAVEFORMATEXTENSIBLE size */ avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ diff --git a/chromium/third_party/ffmpeg/libavformat/rmdec.c b/chromium/third_party/ffmpeg/libavformat/rmdec.c index 832f15daa45..59a80355e0d 100644 --- a/chromium/third_party/ffmpeg/libavformat/rmdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rmdec.c @@ -220,7 +220,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, if (version == 5) avio_r8(pb); codecdata_length = avio_rb32(pb); - if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ + if(codecdata_length + AV_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); return -1; } @@ -250,7 +250,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, if (version == 5) avio_r8(pb); codecdata_length = avio_rb32(pb); - if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ + if(codecdata_length + AV_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); return -1; } @@ -327,20 +327,6 @@ int ff_rm_read_mdpr_codecdata(AVFormatContext *s, AVIOContext *pb, codec_pos = avio_tell(pb); v = avio_rb32(pb); - if (v == MKBETAG('M', 'L', 'T', 'I')) { - int number_of_streams = avio_rb16(pb); - int number_of_mdpr; - int i; - for (i = 0; i<number_of_streams; i++) - avio_rb16(pb); - number_of_mdpr = avio_rb16(pb); - if (number_of_mdpr != 1) { - avpriv_request_sample(s, "MLTI with multiple MDPR"); - } - avio_rb32(pb); - v = avio_rb32(pb); - } - if (v == MKTAG(0xfd, 'a', 'r', '.')) { /* ra type header */ if (rm_read_audio_stream_info(s, pb, st, rst, 0)) @@ -514,6 +500,8 @@ static int rm_read_header(AVFormatContext *s) char buf[128], mime[128]; int flags = 0; int ret = -1; + unsigned size, v; + int64_t codec_pos; tag = avio_rl32(pb); if (tag == MKTAG('.', 'r', 'a', 0xfd)) { @@ -584,9 +572,55 @@ static int rm_read_header(AVFormatContext *s) st->priv_data = ff_rm_alloc_rmstream(); if (!st->priv_data) return AVERROR(ENOMEM); - if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, - avio_rb32(pb), mime) < 0) - goto fail; + + size = avio_rb32(pb); + codec_pos = avio_tell(pb); + + ffio_ensure_seekback(pb, 4); + v = avio_rb32(pb); + if (v == MKBETAG('M', 'L', 'T', 'I')) { + int number_of_streams = avio_rb16(pb); + int number_of_mdpr; + int i; + unsigned size2; + for (i = 0; i<number_of_streams; i++) + avio_rb16(pb); + number_of_mdpr = avio_rb16(pb); + if (number_of_mdpr != 1) { + avpriv_request_sample(s, "MLTI with multiple (%d) MDPR", number_of_mdpr); + } + for (i = 0; i < number_of_mdpr; i++) { + AVStream *st2; + if (i > 0) { + st2 = avformat_new_stream(s, NULL); + if (!st2) { + ret = AVERROR(ENOMEM); + goto fail; + } + st2->id = st->id + (i<<16); + st2->codec->bit_rate = st->codec->bit_rate; + st2->start_time = st->start_time; + st2->duration = st->duration; + st2->codec->codec_type = AVMEDIA_TYPE_DATA; + st2->priv_data = ff_rm_alloc_rmstream(); + if (!st2->priv_data) + return AVERROR(ENOMEM); + } else + st2 = st; + + size2 = avio_rb32(pb); + if (ff_rm_read_mdpr_codecdata(s, s->pb, st2, st2->priv_data, + size2, mime) < 0) + goto fail; + } + avio_seek(pb, codec_pos + size, SEEK_SET); + } else { + avio_skip(pb, -4); + if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, + size, mime) < 0) + goto fail; + } + break; case MKTAG('D', 'A', 'T', 'A'): goto header_end; @@ -644,9 +678,11 @@ static int rm_sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stre while(!avio_feof(pb)){ int len, num, i; + int mlti_id; *pos= avio_tell(pb) - 3; if(rm->remaining_len > 0){ num= rm->current_stream; + mlti_id = 0; len= rm->remaining_len; *timestamp = AV_NOPTS_VALUE; *flags= 0; @@ -682,12 +718,13 @@ static int rm_sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stre num = avio_rb16(pb); *timestamp = avio_rb32(pb); - avio_r8(pb); /* reserved */ + mlti_id = (avio_r8(pb)>>1)-1<<16; + mlti_id = FFMAX(mlti_id, 0); *flags = avio_r8(pb); /* flags */ } for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; - if (num == st->id) + if (mlti_id + num == st->id) break; } if (i == s->nb_streams) { @@ -797,11 +834,6 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, vst->pkt.data= NULL; vst->pkt.size= 0; vst->pkt.buf = NULL; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - vst->pkt.destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices, vst->videobufpos - 1 - 8*vst->slices); diff --git a/chromium/third_party/ffmpeg/libavformat/rtmp.h b/chromium/third_party/ffmpeg/libavformat/rtmp.h index 8fc8040d89e..6600da74f01 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmp.h +++ b/chromium/third_party/ffmpeg/libavformat/rtmp.h @@ -29,9 +29,6 @@ #define RTMP_HANDSHAKE_PACKET_SIZE 1536 -#define HMAC_IPAD_VAL 0x36 -#define HMAC_OPAD_VAL 0x5C - /** * emulated Flash client version - 9.0.124.2 on Linux * @{ diff --git a/chromium/third_party/ffmpeg/libavformat/rtmppkt.c b/chromium/third_party/ffmpeg/libavformat/rtmppkt.c index c474fb3d588..0d693c27f7f 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmppkt.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmppkt.c @@ -440,6 +440,7 @@ int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end) case AMF_DATA_TYPE_STRING: return 3 + AV_RB16(data); case AMF_DATA_TYPE_LONG_STRING: return 5 + AV_RB32(data); case AMF_DATA_TYPE_NULL: return 1; + case AMF_DATA_TYPE_DATE: return 11; case AMF_DATA_TYPE_ARRAY: parse_key = 0; case AMF_DATA_TYPE_MIXEDARRAY: diff --git a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c index 43ddfe8ecc4..51d9ac601c8 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c @@ -27,12 +27,12 @@ #include "libavcodec/bytestream.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" +#include "libavutil/hmac.h" #include "libavutil/intfloat.h" #include "libavutil/lfg.h" #include "libavutil/md5.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" -#include "libavutil/sha.h" #include "avformat.h" #include "internal.h" @@ -49,8 +49,8 @@ #endif #define APP_MAX_LENGTH 1024 -#define PLAYPATH_MAX_LENGTH 256 -#define TCURL_MAX_LENGTH 512 +#define PLAYPATH_MAX_LENGTH 512 +#define TCURL_MAX_LENGTH 1024 #define FLASHVER_MAX_LENGTH 64 #define RTMP_PKTDATA_DEFAULT_SIZE 4096 #define RTMP_HEADER 11 @@ -956,41 +956,22 @@ static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt, int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, const uint8_t *key, int keylen, uint8_t *dst) { - struct AVSHA *sha; - uint8_t hmac_buf[64+32] = {0}; - int i; + AVHMAC *hmac; - sha = av_sha_alloc(); - if (!sha) + hmac = av_hmac_alloc(AV_HMAC_SHA256); + if (!hmac) return AVERROR(ENOMEM); - if (keylen < 64) { - memcpy(hmac_buf, key, keylen); - } else { - av_sha_init(sha, 256); - av_sha_update(sha,key, keylen); - av_sha_final(sha, hmac_buf); - } - for (i = 0; i < 64; i++) - hmac_buf[i] ^= HMAC_IPAD_VAL; - - av_sha_init(sha, 256); - av_sha_update(sha, hmac_buf, 64); + av_hmac_init(hmac, key, keylen); if (gap <= 0) { - av_sha_update(sha, src, len); + av_hmac_update(hmac, src, len); } else { //skip 32 bytes used for storing digest - av_sha_update(sha, src, gap); - av_sha_update(sha, src + gap + 32, len - gap - 32); + av_hmac_update(hmac, src, gap); + av_hmac_update(hmac, src + gap + 32, len - gap - 32); } - av_sha_final(sha, hmac_buf + 64); - - for (i = 0; i < 64; i++) - hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad - av_sha_init(sha, 256); - av_sha_update(sha, hmac_buf, 64+32); - av_sha_final(sha, dst); + av_hmac_final(hmac, dst, 32); - av_free(sha); + av_hmac_free(hmac); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c index 2ac79dbf5ee..b399be423e3 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c @@ -119,7 +119,7 @@ int ff_h264_parse_sprop_parameter_sets(AVFormatContext *s, uint8_t *dest = av_realloc(*data_ptr, packet_size + sizeof(start_sequence) + *size_ptr + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!dest) { av_log(s, AV_LOG_ERROR, "Unable to allocate memory for extradata!\n"); @@ -132,7 +132,7 @@ int ff_h264_parse_sprop_parameter_sets(AVFormatContext *s, memcpy(dest + *size_ptr + sizeof(start_sequence), decoded_packet, packet_size); memset(dest + *size_ptr + sizeof(start_sequence) + - packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + packet_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); *size_ptr += sizeof(start_sequence) + packet_size; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_hevc.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_hevc.c index 51c2094882b..815a72c2b2a 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_hevc.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_hevc.c @@ -152,7 +152,7 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, codec->extradata_size = hevc_data->vps_size + hevc_data->sps_size + hevc_data->pps_size + hevc_data->sei_size; codec->extradata = av_malloc(codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!codec->extradata) { ret = AVERROR(ENOMEM); codec->extradata_size = 0; @@ -166,7 +166,7 @@ static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index, pos += hevc_data->pps_size; memcpy(codec->extradata + pos, hevc_data->sei, hevc_data->sei_size); pos += hevc_data->sei_size; - memset(codec->extradata + pos, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(codec->extradata + pos, 0, AV_INPUT_BUFFER_PADDING_SIZE); } av_freep(&hevc_data->vps); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_latm.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_latm.c index 7db92f60fa3..aebba5741df 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_latm.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_latm.c @@ -97,7 +97,7 @@ static int parse_fmtp_config(AVStream *st, const char *value) int audio_mux_version, same_time_framing, num_programs, num_layers; /* Pad this buffer, too, to avoid out of bounds reads with get_bits below */ - config = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); + config = av_mallocz(len + AV_INPUT_BUFFER_PADDING_SIZE); if (!config) return AVERROR(ENOMEM); ff_hex_to_data(config, value); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_qt.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_qt.c index ba701dc6cf3..e11303fe011 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_qt.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_qt.c @@ -174,14 +174,14 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt, if (qt->pkt.size > 0 && qt->timestamp == *timestamp) { int err; if ((err = av_reallocp(&qt->pkt.data, qt->pkt.size + alen + - FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { qt->pkt.size = 0; return err; } } else { av_freep(&qt->pkt.data); av_init_packet(&qt->pkt); - qt->pkt.data = av_realloc(NULL, alen + FF_INPUT_BUFFER_PADDING_SIZE); + qt->pkt.data = av_realloc(NULL, alen + AV_INPUT_BUFFER_PADDING_SIZE); if (!qt->pkt.data) return AVERROR(ENOMEM); qt->pkt.size = 0; @@ -198,7 +198,7 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt, qt->pkt.data = NULL; pkt->flags = keyframe ? AV_PKT_FLAG_KEY : 0; pkt->stream_index = st->index; - memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); return 0; } return AVERROR(EAGAIN); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c index eceb840580f..9ea3b193864 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c @@ -262,8 +262,8 @@ parse_packed_headers(const uint8_t * packed_headers, /* allocate extra space: * -- length/255 +2 for xiphlacing * -- one for the '2' marker - * -- FF_INPUT_BUFFER_PADDING_SIZE required */ - extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE; + * -- AV_INPUT_BUFFER_PADDING_SIZE required */ + extradata_alloc = length + length/255 + 3 + AV_INPUT_BUFFER_PADDING_SIZE; if (ff_alloc_extradata(codec, extradata_alloc)) { av_log(codec, AV_LOG_ERROR, "Out of memory\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c b/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c index 74f306eb96b..96e65efbaa9 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c @@ -58,7 +58,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, rtpctx->max_delay = s->max_delay; /* Copy other stream parameters. */ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; - rtpctx->flags |= s->flags & AVFMT_FLAG_MP4A_LATM; + rtpctx->flags |= s->flags & (AVFMT_FLAG_MP4A_LATM | AVFMT_FLAG_BITEXACT); /* Get the payload type from the codec */ if (st->id < RTP_PT_PRIVATE) diff --git a/chromium/third_party/ffmpeg/libavformat/rtpenc_jpeg.c b/chromium/third_party/ffmpeg/libavformat/rtpenc_jpeg.c index 7ee26c435e7..a6f2b32df4a 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpenc_jpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpenc_jpeg.c @@ -21,13 +21,14 @@ #include "libavcodec/bytestream.h" #include "libavcodec/mjpeg.h" +#include "libavcodec/jpegtables.h" #include "libavutil/intreadwrite.h" #include "rtpenc.h" void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size) { RTPMuxContext *s = s1->priv_data; - const uint8_t *qtables = NULL; + const uint8_t *qtables[4] = { NULL }; int nb_qtables = 0; uint8_t type; uint8_t w, h; @@ -63,24 +64,50 @@ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size) continue; if (buf[i + 1] == DQT) { - if (buf[i + 4]) + int tables, j; + if (buf[i + 4] & 0xF0) av_log(s1, AV_LOG_WARNING, "Only 8-bit precision is supported.\n"); /* a quantization table is 64 bytes long */ - nb_qtables = AV_RB16(&buf[i + 2]) / 65; - if (i + 4 + nb_qtables * 65 > size) { + tables = AV_RB16(&buf[i + 2]) / 65; + if (i + 5 + tables * 65 > size) { av_log(s1, AV_LOG_ERROR, "Too short JPEG header. Aborted!\n"); return; } + if (nb_qtables + tables > 4) { + av_log(s1, AV_LOG_ERROR, "Invalid number of quantisation tables\n"); + return; + } - qtables = &buf[i + 4]; + for (j = 0; j < tables; j++) + qtables[nb_qtables + j] = buf + i + 5 + j * 65; + nb_qtables += tables; } else if (buf[i + 1] == SOF0) { if (buf[i + 14] != 17 || buf[i + 17] != 17) { av_log(s1, AV_LOG_ERROR, "Only 1x1 chroma blocks are supported. Aborted!\n"); return; } + } else if (buf[i + 1] == DHT) { + if ( AV_RB16(&buf[i + 2]) < 418 + || i + 420 >= size + || buf[i + 4] != 0x00 + || buf[i + 33] != 0x01 + || buf[i + 62] != 0x10 + || buf[i + 241] != 0x11 + || memcmp(buf + i + 5, avpriv_mjpeg_bits_dc_luminance + 1, 16) + || memcmp(buf + i + 21, avpriv_mjpeg_val_dc, 12) + || memcmp(buf + i + 34, avpriv_mjpeg_bits_dc_chrominance + 1, 16) + || memcmp(buf + i + 50, avpriv_mjpeg_val_dc, 12) + || memcmp(buf + i + 63, avpriv_mjpeg_bits_ac_luminance + 1, 16) + || memcmp(buf + i + 79, avpriv_mjpeg_val_ac_luminance, 162) + || memcmp(buf + i + 242, avpriv_mjpeg_bits_ac_chrominance + 1, 16) + || memcmp(buf + i + 258, avpriv_mjpeg_val_ac_chrominance, 162)) { + av_log(s1, AV_LOG_ERROR, + "RFC 2435 requires standard Huffman tables for jpeg\n"); + return; + } } else if (buf[i + 1] == SOS) { /* SOS is last marker in the header */ i += AV_RB16(&buf[i + 2]) + 2; @@ -92,6 +119,10 @@ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size) break; } } + if (nb_qtables && nb_qtables != 2) + av_log(s1, AV_LOG_WARNING, + "RFC 2435 suggests two quantization tables, %d provided\n", + nb_qtables); /* skip JPEG header */ buf += i; @@ -130,7 +161,7 @@ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size) bytestream_put_be16(&p, 64 * nb_qtables); for (i = 0; i < nb_qtables; i++) - bytestream_put_buffer(&p, &qtables[65 * i + 1], 64); + bytestream_put_buffer(&p, qtables[i], 64); } /* copy payload data */ diff --git a/chromium/third_party/ffmpeg/libavformat/rtsp.c b/chromium/third_party/ffmpeg/libavformat/rtsp.c index 98bd4cbe9ab..9aa66d24a4b 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtsp.c +++ b/chromium/third_party/ffmpeg/libavformat/rtsp.c @@ -1136,6 +1136,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, unsigned char ch; const char *p; int ret, content_length, line_count = 0, request = 0; + int first_line = 1; unsigned char *content = NULL; start: @@ -1155,8 +1156,7 @@ start: return AVERROR_EOF; if (ch == '\n') break; - if (ch == '$') { - /* XXX: only parse it if first char on line ? */ + if (ch == '$' && first_line && q == buf) { if (return_on_interleaved_data) { return 1; } else @@ -1167,6 +1167,7 @@ start: } } *q = '\0'; + first_line = 0; av_log(s, AV_LOG_TRACE, "line='%s'\n", buf); diff --git a/chromium/third_party/ffmpeg/libavformat/samidec.c b/chromium/third_party/ffmpeg/libavformat/samidec.c index 948e1ed8b13..11c674ce19b 100644 --- a/chromium/third_party/ffmpeg/libavformat/samidec.c +++ b/chromium/third_party/ffmpeg/libavformat/samidec.c @@ -68,11 +68,17 @@ static int sami_read_header(AVFormatContext *s) while (!ff_text_eof(&tr)) { AVPacket *sub; const int64_t pos = ff_text_pos(&tr) - (c != 0); - int is_sync, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c); + int is_sync, is_body, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c); if (n == 0) break; + is_body = !av_strncasecmp(buf.str, "</BODY", 6); + if (is_body) { + av_bprint_clear(&buf); + break; + } + is_sync = !av_strncasecmp(buf.str, "<SYNC", 5); if (is_sync) got_first_sync_point = 1; @@ -99,7 +105,7 @@ static int sami_read_header(AVFormatContext *s) if (res < 0) goto end; - ff_subtitles_queue_finalize(&sami->q); + ff_subtitles_queue_finalize(s, &sami->q); end: av_bprint_finalize(&buf, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/sdp.c b/chromium/third_party/ffmpeg/libavformat/sdp.c index 4d621c7ffc9..45974b394fb 100644 --- a/chromium/third_party/ffmpeg/libavformat/sdp.c +++ b/chromium/third_party/ffmpeg/libavformat/sdp.c @@ -685,7 +685,7 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, const char *mode; uint64_t vad_option; - if (c->flags & CODEC_FLAG_QSCALE) + if (c->flags & AV_CODEC_FLAG_QSCALE) mode = "on"; else if (!av_opt_get_int(c, "vad", AV_OPT_FLAG_ENCODING_PARAM, &vad_option) && vad_option) mode = "vad"; diff --git a/chromium/third_party/ffmpeg/libavformat/segment.c b/chromium/third_party/ffmpeg/libavformat/segment.c index 42471bb1906..36417f21923 100644 --- a/chromium/third_party/ffmpeg/libavformat/segment.c +++ b/chromium/third_party/ffmpeg/libavformat/segment.c @@ -33,6 +33,7 @@ #include "internal.h" #include "libavutil/avassert.h" +#include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" @@ -113,6 +114,9 @@ typedef struct SegmentContext { int reference_stream_index; int break_non_keyframes; + int use_rename; + char temp_list_filename[1024]; + SegmentListEntry cur_entry; SegmentListEntry *segment_list_entries; SegmentListEntry *segment_list_entries_end; @@ -258,7 +262,8 @@ static int segment_list_open(AVFormatContext *s) SegmentContext *seg = s->priv_data; int ret; - ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE, + snprintf(seg->temp_list_filename, sizeof(seg->temp_list_filename), seg->use_rename ? "%s.tmp" : "%s", seg->list); + ret = avio_open2(&seg->list_pb, seg->temp_list_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list); @@ -347,6 +352,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) /* append new element */ memcpy(entry, &seg->cur_entry, sizeof(*entry)); + entry->filename = av_strdup(entry->filename); if (!seg->segment_list_entries) seg->segment_list_entries = seg->segment_list_entries_end = entry; else @@ -368,6 +374,8 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) if (seg->list_type == LIST_TYPE_M3U8 && is_last) avio_printf(seg->list_pb, "#EXT-X-ENDLIST\n"); avio_closep(&seg->list_pb); + if (seg->use_rename) + ff_rename(seg->temp_list_filename, seg->list, s); } else { segment_list_print_entry(seg->list_pb, seg->list_type, &seg->cur_entry, s); avio_flush(seg->list_pb); @@ -644,9 +652,13 @@ static int seg_write_header(AVFormatContext *s) else if (av_match_ext(seg->list, "ffcat,ffconcat")) seg->list_type = LIST_TYPE_FFCONCAT; else seg->list_type = LIST_TYPE_FLAT; } - if (!seg->list_size && seg->list_type != LIST_TYPE_M3U8) + if (!seg->list_size && seg->list_type != LIST_TYPE_M3U8) { if ((ret = segment_list_open(s)) < 0) goto fail; + } else { + const char *proto = avio_find_protocol_name(s->filename); + seg->use_rename = proto && !strcmp(proto, "file"); + } } if (seg->list_type == LIST_TYPE_EXT) av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n"); @@ -774,7 +786,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) } } - av_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d\n", + ff_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d\n", pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2timestr(pkt->duration, &st->time_base), pkt->flags & AV_PKT_FLAG_KEY, @@ -875,6 +887,7 @@ fail: av_opt_free(seg); av_freep(&seg->times); av_freep(&seg->frames); + av_freep(&seg->cur_entry.filename); cur = seg->segment_list_entries; while (cur) { diff --git a/chromium/third_party/ffmpeg/libavformat/spdifenc.c b/chromium/third_party/ffmpeg/libavformat/spdifenc.c index cdcff244212..b4608a1c7c5 100644 --- a/chromium/third_party/ffmpeg/libavformat/spdifenc.c +++ b/chromium/third_party/ffmpeg/libavformat/spdifenc.c @@ -525,7 +525,7 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) if (ctx->extra_bswap ^ (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)) { avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1); } else { - av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE); + av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + AV_INPUT_BUFFER_PADDING_SIZE); if (!ctx->buffer) return AVERROR(ENOMEM); ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1); diff --git a/chromium/third_party/ffmpeg/libavformat/srtdec.c b/chromium/third_party/ffmpeg/libavformat/srtdec.c index b35e50fc367..60d2f48517f 100644 --- a/chromium/third_party/ffmpeg/libavformat/srtdec.c +++ b/chromium/third_party/ffmpeg/libavformat/srtdec.c @@ -134,7 +134,7 @@ static int srt_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&srt->q); + ff_subtitles_queue_finalize(s, &srt->q); end: av_bprint_finalize(&buf, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/stldec.c b/chromium/third_party/ffmpeg/libavformat/stldec.c index b84c7e9eb0a..8b1f0a6d5bb 100644 --- a/chromium/third_party/ffmpeg/libavformat/stldec.c +++ b/chromium/third_party/ffmpeg/libavformat/stldec.c @@ -104,7 +104,7 @@ static int stl_read_header(AVFormatContext *s) sub->duration = duration; } } - ff_subtitles_queue_finalize(&stl->q); + ff_subtitles_queue_finalize(s, &stl->q); return 0; } static int stl_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/subtitles.c b/chromium/third_party/ffmpeg/libavformat/subtitles.c index 5bdbc8dc512..192043f9177 100644 --- a/chromium/third_party/ffmpeg/libavformat/subtitles.c +++ b/chromium/third_party/ffmpeg/libavformat/subtitles.c @@ -166,7 +166,34 @@ static int cmp_pkt_sub_pos_ts(const void *a, const void *b) return s1->pos > s2->pos ? 1 : -1; } -void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q) +static void drop_dups(void *log_ctx, FFDemuxSubtitlesQueue *q) +{ + int i, drop = 0; + + for (i = 1; i < q->nb_subs; i++) { + const int last_id = i - 1 - drop; + const AVPacket *last = &q->subs[last_id]; + + if (q->subs[i].pts == last->pts && + q->subs[i].duration == last->duration && + q->subs[i].stream_index == last->stream_index && + !strcmp(q->subs[i].data, last->data)) { + + av_free_packet(&q->subs[i]); + drop++; + } else if (drop) { + q->subs[last_id + 1] = q->subs[i]; + memset(&q->subs[i], 0, sizeof(q->subs[i])); // for safety + } + } + + if (drop) { + q->nb_subs -= drop; + av_log(log_ctx, AV_LOG_WARNING, "Dropping %d duplicated subtitle events\n", drop); + } +} + +void ff_subtitles_queue_finalize(void *log_ctx, FFDemuxSubtitlesQueue *q) { int i; @@ -176,6 +203,8 @@ void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q) for (i = 0; i < q->nb_subs; i++) if (q->subs[i].duration == -1 && i < q->nb_subs - 1) q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts; + + drop_dups(log_ctx, q); } int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/subtitles.h b/chromium/third_party/ffmpeg/libavformat/subtitles.h index 885285cc477..c70f6fffde6 100644 --- a/chromium/third_party/ffmpeg/libavformat/subtitles.h +++ b/chromium/third_party/ffmpeg/libavformat/subtitles.h @@ -119,9 +119,10 @@ AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, const uint8_t *event, size_t len, int merge); /** - * Set missing durations and sort subtitles by PTS, and then byte position. + * Set missing durations, sort subtitles by PTS (and then byte position), and + * drop duplicated events. */ -void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q); +void ff_subtitles_queue_finalize(void *log_ctx, FFDemuxSubtitlesQueue *q); /** * Generic read_packet() callback for subtitles demuxers using this queue diff --git a/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c b/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c index 6b38533a882..93db4ebf21a 100644 --- a/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c +++ b/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c @@ -86,7 +86,7 @@ static int subviewer1_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&subviewer1->q); + ff_subtitles_queue_finalize(s, &subviewer1->q); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/subviewerdec.c b/chromium/third_party/ffmpeg/libavformat/subviewerdec.c index f1b0fdf0a5c..d4b2fdf4565 100644 --- a/chromium/third_party/ffmpeg/libavformat/subviewerdec.c +++ b/chromium/third_party/ffmpeg/libavformat/subviewerdec.c @@ -153,7 +153,7 @@ static int subviewer_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&subviewer->q); + ff_subtitles_queue_finalize(s, &subviewer->q); end: av_bprint_finalize(&header, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/swfdec.c b/chromium/third_party/ffmpeg/libavformat/swfdec.c index d34d3d90dff..68cd8561fb5 100644 --- a/chromium/third_party/ffmpeg/libavformat/swfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/swfdec.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/imgutils.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavcodec/get_bits.h" #include "swf.h" @@ -67,7 +68,12 @@ static int swf_probe(AVProbeData *p) && AV_RB24(p->buf) != AV_RB24("FWS")) return 0; - init_get_bits8(&gb, p->buf + 3, p->buf_size - 3); + if ( AV_RB24(p->buf) == AV_RB24("CWS") + && p->buf[3] <= 20) + return AVPROBE_SCORE_MAX / 4 + 1; + + if (init_get_bits8(&gb, p->buf + 3, p->buf_size - 3) < 0) + return 0; skip_bits(&gb, 40); len = get_bits(&gb, 5); @@ -338,7 +344,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) out_len = colormapsize * colormapbpp + linesize * height; - av_dlog(s, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n", + ff_dlog(s, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n", ch_id, bmp_fmt, width, height, linesize, len, out_len, colormapsize); zbuf = av_malloc(len); @@ -407,10 +413,8 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) } if (st->codec->pix_fmt != AV_PIX_FMT_NONE && st->codec->pix_fmt != pix_fmt) { av_log(s, AV_LOG_ERROR, "pixel format change unsupported\n"); - res = AVERROR_PATCHWELCOME; - goto bitmap_end; - } - st->codec->pix_fmt = pix_fmt; + } else + st->codec->pix_fmt = pix_fmt; if (linesize * height > pkt->size) { res = AVERROR_INVALIDDATA; diff --git a/chromium/third_party/ffmpeg/libavformat/takdec.c b/chromium/third_party/ffmpeg/libavformat/takdec.c index 3eb1a8ec2d4..970ab4a8b49 100644 --- a/chromium/third_party/ffmpeg/libavformat/takdec.c +++ b/chromium/third_party/ffmpeg/libavformat/takdec.c @@ -82,10 +82,10 @@ static int tak_read_header(AVFormatContext *s) if (size <= 3) return AVERROR_INVALIDDATA; - buffer = av_malloc(size - 3 + FF_INPUT_BUFFER_PADDING_SIZE); + buffer = av_malloc(size - 3 + AV_INPUT_BUFFER_PADDING_SIZE); if (!buffer) return AVERROR(ENOMEM); - memset(buffer + size - 3, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(buffer + size - 3, 0, AV_INPUT_BUFFER_PADDING_SIZE); ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U); if (avio_read(pb, buffer, size - 3) != size - 3) { diff --git a/chromium/third_party/ffmpeg/libavformat/tcp.c b/chromium/third_party/ffmpeg/libavformat/tcp.c index f24cad2080d..e02c64b8001 100644 --- a/chromium/third_party/ffmpeg/libavformat/tcp.c +++ b/chromium/third_party/ffmpeg/libavformat/tcp.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "libavutil/avassert.h" #include "libavutil/parseutils.h" #include "libavutil/opt.h" #include "libavutil/time.h" @@ -44,7 +45,7 @@ typedef struct TCPContext { #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E }, { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { NULL } @@ -125,11 +126,16 @@ static int tcp_open(URLContext *h, const char *uri, int flags) goto fail; } - if (s->listen) { + if (s->listen == 2) { + // multi-client + if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) + goto fail1; + } else if (s->listen == 1) { + // single client if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, - s->listen_timeout, h)) < 0) { + s->listen_timeout, h)) < 0) goto fail1; - } + // Socket descriptor already closed here. Safe to overwrite to client one. fd = ret; } else { if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, @@ -163,6 +169,22 @@ static int tcp_open(URLContext *h, const char *uri, int flags) return ret; } +static int tcp_accept(URLContext *s, URLContext **c) +{ + TCPContext *sc = s->priv_data; + TCPContext *cc; + int ret; + av_assert0(sc->listen); + if ((ret = ffurl_alloc(c, s->filename, s->flags, &s->interrupt_callback)) < 0) + return ret; + cc = (*c)->priv_data; + ret = ff_accept(sc->fd, sc->listen_timeout, s); + if (ret < 0) + return ff_neterrno(); + cc->fd = ret; + return 0; +} + static int tcp_read(URLContext *h, uint8_t *buf, int size) { TCPContext *s = h->priv_data; @@ -223,6 +245,7 @@ static int tcp_get_file_handle(URLContext *h) URLProtocol ff_tcp_protocol = { .name = "tcp", .url_open = tcp_open, + .url_accept = tcp_accept, .url_read = tcp_read, .url_write = tcp_write, .url_close = tcp_close, diff --git a/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c b/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c index fb578ebc036..b6dc5170737 100644 --- a/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c @@ -34,7 +34,7 @@ typedef struct { static const AVOption tedcaptions_options[] = { { "start_time", "set the start time (offset) of the subtitles, in ms", - offsetof(TEDCaptionsDemuxer, start_time), FF_OPT_TYPE_INT64, + offsetof(TEDCaptionsDemuxer, start_time), AV_OPT_TYPE_INT64, { .i64 = 15000 }, INT64_MIN, INT64_MAX, AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM }, { NULL }, @@ -287,7 +287,7 @@ static av_cold int tedcaptions_read_header(AVFormatContext *avf) ff_subtitles_queue_clean(&tc->subs); return ret; } - ff_subtitles_queue_finalize(&tc->subs); + ff_subtitles_queue_finalize(avf, &tc->subs); for (i = 0; i < tc->subs.nb_subs; i++) tc->subs.subs[i].pts += tc->start_time; diff --git a/chromium/third_party/ffmpeg/libavformat/tee.c b/chromium/third_party/ffmpeg/libavformat/tee.c index e3d466a3eb7..c619eae5db1 100644 --- a/chromium/third_party/ffmpeg/libavformat/tee.c +++ b/chromium/third_party/ffmpeg/libavformat/tee.c @@ -396,7 +396,7 @@ static int filter_packet(void *log_ctx, AVPacket *pkt, &new_pkt.data, &new_pkt.size, pkt->data, pkt->size, pkt->flags & AV_PKT_FLAG_KEY); - if (ret == 0 && new_pkt.data != pkt->data && new_pkt.destruct) { + if (ret == 0 && new_pkt.data != pkt->data) { if ((ret = av_copy_packet(&new_pkt, pkt)) < 0) break; ret = 1; diff --git a/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c b/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c index 6388f37a8e0..4bf94485343 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c @@ -144,7 +144,7 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op if (ret < 0) av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); } -#if GNUTLS_VERSION_MAJOR >= 3 +#if GNUTLS_VERSION_NUMBER >= 0x030020 else gnutls_certificate_set_x509_system_trust(p->cred); #endif diff --git a/chromium/third_party/ffmpeg/libavformat/url.h b/chromium/third_party/ffmpeg/libavformat/url.h index 1a845b77e7c..391e3bca2af 100644 --- a/chromium/third_party/ffmpeg/libavformat/url.h +++ b/chromium/third_party/ffmpeg/libavformat/url.h @@ -58,6 +58,8 @@ typedef struct URLProtocol { * for those nested protocols. */ int (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options); + int (*url_accept)(URLContext *s, URLContext **c); + int (*url_handshake)(URLContext *c); /** * Read data from the protocol. @@ -90,6 +92,8 @@ typedef struct URLProtocol { int (*url_open_dir)(URLContext *h); int (*url_read_dir)(URLContext *h, AVIODirEntry **next); int (*url_close_dir)(URLContext *h); + int (*url_delete)(URLContext *h); + int (*url_move)(URLContext *h_src, URLContext *h_dst); } URLProtocol; /** @@ -138,6 +142,29 @@ int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); /** + * Accept an URLContext c on an URLContext s + * + * @param s server context + * @param c client context, must be unallocated. + * @return >= 0 on success, ff_neterrno() on failure. + */ +int ffurl_accept(URLContext *s, URLContext **c); + +/** + * Perform one step of the protocol handshake to accept a new client. + * See avio_handshake() for details. + * Implementations should try to return decreasing values. + * If the protocol uses an underlying protocol, the underlying handshake is + * usually the first step, and the return value can be: + * (largest value for this protocol) + (return value from other protocol) + * + * @param c the client context + * @return >= 0 on success or a negative value corresponding + * to an AVERROR code on failure + */ +int ffurl_handshake(URLContext *c); + +/** * Read up to size bytes from the resource accessed by h, and store * the read bytes in buf. * diff --git a/chromium/third_party/ffmpeg/libavformat/utils.c b/chromium/third_party/ffmpeg/libavformat/utils.c index caa15abbaed..24eacf39675 100644 --- a/chromium/third_party/ffmpeg/libavformat/utils.c +++ b/chromium/third_party/ffmpeg/libavformat/utils.c @@ -116,7 +116,10 @@ MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb) int64_t av_stream_get_end_pts(const AVStream *st) { - return st->pts.val; + if (st->priv_pts) { + return st->priv_pts->val; + } else + return AV_NOPTS_VALUE; } struct AVCodecParserContext *av_stream_get_parser(const AVStream *st) @@ -1262,12 +1265,6 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) { out_pkt.buf = pkt->buf; pkt->buf = NULL; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - out_pkt.destruct = pkt->destruct; - pkt->destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif } if ((ret = av_dup_packet(&out_pkt)) < 0) goto fail; @@ -1585,26 +1582,26 @@ int av_find_default_stream_index(AVFormatContext *s) int i; AVStream *st; int best_stream = 0; - int best_score = -1; + int best_score = INT_MIN; if (s->nb_streams <= 0) return -1; for (i = 0; i < s->nb_streams; i++) { int score = 0; st = s->streams[i]; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && - !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { - if (!st->codec->width && !st->codec->height && !st->codec_info_nb_frames) - score += 25; - else - score += 100; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + score -= 400; + if (st->codec->width && st->codec->height) + score += 50; + score+= 25; } if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if (!st->codec->sample_rate && !st->codec_info_nb_frames) - score += 12; - else + if (st->codec->sample_rate) score += 50; } + if (st->codec_info_nb_frames) + score += 12; if (st->discard != AVDISCARD_ALL) score += 200; @@ -1781,6 +1778,63 @@ int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, return m; } +void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance) +{ + int ist1, ist2; + int64_t pos_delta = 0; + int64_t skip = 0; + //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable + const char *proto = avio_find_protocol_name(s->filename); + + if (!proto) { + av_log(s, AV_LOG_INFO, + "Protocol name not provided, cannot determine if input is local or " + "a network protocol, buffers and access patterns cannot be configured " + "optimally without knowing the protocol\n"); + } + + if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache"))) + return; + + for (ist1 = 0; ist1 < s->nb_streams; ist1++) { + AVStream *st1 = s->streams[ist1]; + for (ist2 = 0; ist2 < s->nb_streams; ist2++) { + AVStream *st2 = s->streams[ist2]; + int i1, i2; + + if (ist1 == ist2) + continue; + + for (i1 = i2 = 0; i1 < st1->nb_index_entries; i1++) { + AVIndexEntry *e1 = &st1->index_entries[i1]; + int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q); + + skip = FFMAX(skip, e1->size); + for (; i2 < st2->nb_index_entries; i2++) { + AVIndexEntry *e2 = &st2->index_entries[i2]; + int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q); + if (e2_pts - e1_pts < time_tolerance) + continue; + pos_delta = FFMAX(pos_delta, e1->pos - e2->pos); + break; + } + } + } + } + + pos_delta *= 2; + /* XXX This could be adjusted depending on protocol*/ + if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) { + av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta); + ffio_set_buf_size(s->pb, pos_delta); + s->pb->short_seek_threshold = FFMAX(s->pb->short_seek_threshold, pos_delta/2); + } + + if (skip < (1<<23)) { + s->pb->short_seek_threshold = FFMAX(s->pb->short_seek_threshold, skip); + } +} + int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) { return ff_index_search_timestamp(st->index_entries, st->nb_index_entries, @@ -2665,7 +2719,7 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, ret >= 0 && (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) || (!st->codec_info_nb_frames && - st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { + (st->codec->codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)))) { got_picture = 0; switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: @@ -2865,14 +2919,14 @@ int ff_alloc_extradata(AVCodecContext *avctx, int size) { int ret; - if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) { + if (size < 0 || size >= INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { avctx->extradata = NULL; avctx->extradata_size = 0; return AVERROR(EINVAL); } - avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); if (avctx->extradata) { - memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(avctx->extradata + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); avctx->extradata_size = size; ret = 0; } else { @@ -3031,9 +3085,18 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) // new streams might appear, no options for those int orig_nb_streams = ic->nb_streams; int flush_codecs; +#if FF_API_PROBESIZE_32 int64_t max_analyze_duration = ic->max_analyze_duration2; +#else + int64_t max_analyze_duration = ic->max_analyze_duration; +#endif int64_t max_stream_analyze_duration; + int64_t max_subtitle_analyze_duration; +#if FF_API_PROBESIZE_32 int64_t probesize = ic->probesize2; +#else + int64_t probesize = ic->probesize; +#endif if (!max_analyze_duration) max_analyze_duration = ic->max_analyze_duration; @@ -3044,11 +3107,13 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN); max_stream_analyze_duration = max_analyze_duration; + max_subtitle_analyze_duration = max_analyze_duration; if (!max_analyze_duration) { max_stream_analyze_duration = max_analyze_duration = 5*AV_TIME_BASE; + max_subtitle_analyze_duration = 30*AV_TIME_BASE; if (!strcmp(ic->iformat->name, "flv")) - max_stream_analyze_duration = 30*AV_TIME_BASE; + max_stream_analyze_duration = 90*AV_TIME_BASE; } if (ic->pb) @@ -3264,6 +3329,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } if (st->codec_info_nb_frames>1) { int64_t t = 0; + int64_t limit; if (st->time_base.den > 0) t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q); @@ -3276,10 +3342,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) && st->info->fps_last_dts != AV_NOPTS_VALUE) t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q)); - if (t >= (analyzed_all_streams ? max_analyze_duration : max_stream_analyze_duration)) { - av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds\n", - max_analyze_duration, - t); + if (analyzed_all_streams) limit = max_analyze_duration; + else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) limit = max_subtitle_analyze_duration; + else limit = max_stream_analyze_duration; + + if (t >= limit) { + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds st:%d\n", + limit, + t, pkt->stream_index); if (ic->flags & AVFMT_FLAG_NOBUFFER) av_packet_unref(pkt); break; @@ -3308,7 +3378,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) * it takes longer and uses more memory. For MPEG-4, we need to * decompress for QuickTime. * - * If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at + * If AV_CODEC_CAP_CHANNEL_CONF is set this will force decoding of at * least one frame of codec data, this makes sure the codec initializes * the channel configuration and does not only trust the values from * the container. */ @@ -3603,6 +3673,7 @@ void ff_free_stream(AVFormatContext *s, AVStream *st) { av_freep(&st->info->duration_error); av_freep(&st->info); av_freep(&st->recommended_encoder_configuration); + av_freep(&st->priv_pts); av_freep(&s->streams[ --s->nb_streams ]); } @@ -4235,8 +4306,9 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, if (*spec <= '9' && *spec >= '0') /* opt:index */ return strtol(spec, NULL, 0) == st->index; else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || - *spec == 't') { /* opt:[vasdt] */ + *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ enum AVMediaType type; + int nopic = 0; switch (*spec++) { case 'v': type = AVMEDIA_TYPE_VIDEO; break; @@ -4244,15 +4316,20 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, case 's': type = AVMEDIA_TYPE_SUBTITLE; break; case 'd': type = AVMEDIA_TYPE_DATA; break; case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; + case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; default: av_assert0(0); } if (type != st->codec->codec_type) return 0; + if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + return 0; if (*spec++ == ':') { /* possibly followed by :index */ int i, index = strtol(spec, NULL, 0); for (i = 0; i < s->nb_streams; i++) - if (s->streams[i]->codec->codec_type == type && index-- == 0) - return i == st->index; + if (s->streams[i]->codec->codec_type == type && + !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && + index-- == 0) + return i == st->index; return 0; } return 1; diff --git a/chromium/third_party/ffmpeg/libavformat/version.h b/chromium/third_party/ffmpeg/libavformat/version.h index 99b71906ba7..18be8b26b61 100644 --- a/chromium/third_party/ffmpeg/libavformat/version.h +++ b/chromium/third_party/ffmpeg/libavformat/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" -#define LIBAVFORMAT_VERSION_MAJOR 56 -#define LIBAVFORMAT_VERSION_MINOR 37 +#define LIBAVFORMAT_VERSION_MAJOR 57 +#define LIBAVFORMAT_VERSION_MINOR 0 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -47,18 +47,26 @@ * FF_API_* defines may be placed below to indicate public API that will be * dropped at a future version bump. The defines themselves are not part of * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * */ #ifndef FF_API_LAVF_BITEXACT -#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 57) +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 58) #endif #ifndef FF_API_LAVF_FRAC -#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 57) +#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 58) #endif #ifndef FF_API_LAVF_CODEC_TB -#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 57) +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 58) #endif #ifndef FF_API_URL_FEOF -#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 57) +#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_PROBESIZE_32 +#define FF_API_PROBESIZE_32 (LIBAVFORMAT_VERSION_MAJOR < 58) #endif #ifndef FF_API_R_FRAME_RATE diff --git a/chromium/third_party/ffmpeg/libavformat/vplayerdec.c b/chromium/third_party/ffmpeg/libavformat/vplayerdec.c index 619ccfd4f06..860b7785c9c 100644 --- a/chromium/third_party/ffmpeg/libavformat/vplayerdec.c +++ b/chromium/third_party/ffmpeg/libavformat/vplayerdec.c @@ -90,7 +90,7 @@ static int vplayer_read_header(AVFormatContext *s) } } - ff_subtitles_queue_finalize(&vplayer->q); + ff_subtitles_queue_finalize(s, &vplayer->q); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/wavdec.c b/chromium/third_party/ffmpeg/libavformat/wavdec.c index 864185f989b..ef24e1672c7 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wavdec.c @@ -134,7 +134,7 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st) if (!*st) return AVERROR(ENOMEM); - ret = ff_get_wav_header(pb, (*st)->codec, size, wav->rifx); + ret = ff_get_wav_header(s, pb, (*st)->codec, size, wav->rifx); if (ret < 0) return ret; handle_stream_probing(*st); @@ -429,8 +429,29 @@ break_loop: avio_seek(pb, data_ofs, SEEK_SET); + if (data_size > (INT64_MAX>>3)) { + av_log(s, AV_LOG_WARNING, "Data size %"PRId64" is too large\n", data_size); + data_size = 0; + } + + if ( st->codec->bit_rate > 0 && data_size > 0 + && st->codec->sample_rate > 0 + && sample_count > 0 && st->codec->channels > 1 + && sample_count % st->codec->channels == 0) { + if (fabs(8.0 * data_size * st->codec->channels * st->codec->sample_rate / + sample_count /st->codec->bit_rate - 1.0) < 0.3) + sample_count /= st->codec->channels; + } + if ( data_size > 0 && sample_count && st->codec->channels - && data_size / sample_count / st->codec->channels > 8) { + && (data_size << 3) / sample_count / st->codec->channels > st->codec->bits_per_coded_sample + 1) { + av_log(s, AV_LOG_WARNING, "ignoring wrong sample_count %"PRId64"\n", sample_count); + sample_count = 0; + } + + /* G.729 hack (for Ticket4577) + * FIXME: Come up with cleaner, more general solution */ + if (st->codec->codec_id == AV_CODEC_ID_G729 && sample_count && (data_size << 3) > sample_count) { av_log(s, AV_LOG_WARNING, "ignoring wrong sample_count %"PRId64"\n", sample_count); sample_count = 0; } @@ -615,7 +636,7 @@ static int wav_read_seek(AVFormatContext *s, #define OFFSET(x) offsetof(WAVDemuxContext, x) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption demux_options[] = { - { "ignore_length", "Ignore length", OFFSET(ignore_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC }, + { "ignore_length", "Ignore length", OFFSET(ignore_length), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, { NULL }, }; @@ -689,7 +710,7 @@ static int w64_read_header(AVFormatContext *s) if (!memcmp(guid, ff_w64_guid_fmt, 16)) { /* subtract chunk header size - normal wav file doesn't count it */ - ret = ff_get_wav_header(pb, st->codec, size - 24, 0); + ret = ff_get_wav_header(s, pb, st->codec, size - 24, 0); if (ret < 0) return ret; avio_skip(pb, FFALIGN(size, INT64_C(8)) - size); diff --git a/chromium/third_party/ffmpeg/libavformat/wavenc.c b/chromium/third_party/ffmpeg/libavformat/wavenc.c index f89c91e8c73..0156f6e8a3b 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavenc.c +++ b/chromium/third_party/ffmpeg/libavformat/wavenc.c @@ -502,7 +502,7 @@ static int wav_write_trailer(AVFormatContext *s) #define OFFSET(x) offsetof(WAVMuxContext, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, + { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "write_peak", "Write Peak Envelope chunk.", OFFSET(write_peak), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, ENC, "peak" }, { "off", "Do not write peak chunk.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_OFF }, 0, 0, ENC, "peak" }, { "on", "Append peak chunk after wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ON }, 0, 0, ENC, "peak" }, diff --git a/chromium/third_party/ffmpeg/libavformat/webmdashenc.c b/chromium/third_party/ffmpeg/libavformat/webmdashenc.c index 76ea4237e2b..898e4641d37 100644 --- a/chromium/third_party/ffmpeg/libavformat/webmdashenc.c +++ b/chromium/third_party/ffmpeg/libavformat/webmdashenc.c @@ -392,10 +392,10 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) if (w->is_live) { AVDictionaryEntry *filename = av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0); - if (!filename || - (ret = parse_filename(filename->value, &representation_id, NULL, NULL))) { + if (!filename) + return AVERROR(EINVAL); + if (ret = parse_filename(filename->value, &representation_id, NULL, NULL)) return ret; - } } else { representation_id = av_asprintf("%d", w->representation_id++); if (!representation_id) return AVERROR(ENOMEM); diff --git a/chromium/third_party/ffmpeg/libavformat/webvttdec.c b/chromium/third_party/ffmpeg/libavformat/webvttdec.c index e457e8f6d21..43c2a639ad3 100644 --- a/chromium/third_party/ffmpeg/libavformat/webvttdec.c +++ b/chromium/third_party/ffmpeg/libavformat/webvttdec.c @@ -161,7 +161,7 @@ static int webvtt_read_header(AVFormatContext *s) SET_SIDE_DATA(settings, AV_PKT_DATA_WEBVTT_SETTINGS); } - ff_subtitles_queue_finalize(&webvtt->q); + ff_subtitles_queue_finalize(s, &webvtt->q); end: av_bprint_finalize(&cue, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/webvttenc.c b/chromium/third_party/ffmpeg/libavformat/webvttenc.c index b93993d55ce..c3865387186 100644 --- a/chromium/third_party/ffmpeg/libavformat/webvttenc.c +++ b/chromium/third_party/ffmpeg/libavformat/webvttenc.c @@ -46,8 +46,14 @@ static void webvtt_write_time(AVIOContext *pb, int64_t millisec) static int webvtt_write_header(AVFormatContext *ctx) { AVStream *s = ctx->streams[0]; + AVCodecContext *avctx = ctx->streams[0]->codec; AVIOContext *pb = ctx->pb; + if (ctx->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_WEBVTT) { + av_log(ctx, AV_LOG_ERROR, "Exactly one WebVTT stream is needed.\n"); + return AVERROR(EINVAL); + } + avpriv_set_pts_info(s, 64, 1, 1000); avio_printf(pb, "WEBVTT\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/wtvdec.c b/chromium/third_party/ffmpeg/libavformat/wtvdec.c index e226690283c..e8f6196a5ed 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wtvdec.c @@ -670,7 +670,7 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, if (!st) return NULL; if (!ff_guidcmp(formattype, ff_format_waveformatex)) { - int ret = ff_get_wav_header(pb, st->codec, size, 0); + int ret = ff_get_wav_header(s, pb, st->codec, size, 0); if (ret < 0) return NULL; } else { diff --git a/chromium/third_party/ffmpeg/libavformat/xwma.c b/chromium/third_party/ffmpeg/libavformat/xwma.c index 683d3d0d4d2..9edad7d75ac 100644 --- a/chromium/third_party/ffmpeg/libavformat/xwma.c +++ b/chromium/third_party/ffmpeg/libavformat/xwma.c @@ -75,7 +75,7 @@ static int xwma_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); - ret = ff_get_wav_header(pb, st->codec, size, 0); + ret = ff_get_wav_header(s, pb, st->codec, size, 0); if (ret < 0) return ret; st->need_parsing = AVSTREAM_PARSE_NONE; diff --git a/chromium/third_party/ffmpeg/libavformat/yop.c b/chromium/third_party/ffmpeg/libavformat/yop.c index 81b3cc2b32b..64779d4fb75 100644 --- a/chromium/third_party/ffmpeg/libavformat/yop.c +++ b/chromium/third_party/ffmpeg/libavformat/yop.c @@ -132,11 +132,6 @@ static int yop_read_packet(AVFormatContext *s, AVPacket *pkt) *pkt = yop->video_packet; yop->video_packet.data = NULL; yop->video_packet.buf = NULL; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - yop->video_packet.destruct = NULL; -FF_ENABLE_DEPRECATION_WARNINGS -#endif yop->video_packet.size = 0; pkt->data[0] = yop->odd_frame; pkt->flags |= AV_PKT_FLAG_KEY; diff --git a/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.h b/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.h index 750f4984076..eba7337fe6c 100644 --- a/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.h +++ b/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.h @@ -23,5 +23,6 @@ #define Y4M_MAGIC "YUV4MPEG2" #define Y4M_FRAME_MAGIC "FRAME" +#define Y4M_FRAME_MAGIC_LEN 6 #endif /* AVFORMAT_YUV4MPEG_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c b/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c index 7613c3cdc36..0db42f5933b 100644 --- a/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c +++ b/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c @@ -256,6 +256,12 @@ static int yuv4_read_header(AVFormatContext *s) st->sample_aspect_ratio = (AVRational){ aspectn, aspectd }; st->codec->chroma_sample_location = chroma_sample_location; st->codec->field_order = field_order; + s->packet_size = avpicture_get_size(st->codec->pix_fmt, width, height) + Y4M_FRAME_MAGIC_LEN; + if ((int) s->packet_size < 0) + return s->packet_size; + s->internal->data_offset = avio_tell(pb); + + st->duration = (avio_size(pb) - avio_tell(pb)) / s->packet_size; return 0; } @@ -264,8 +270,8 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) { int i; char header[MAX_FRAME_HEADER+1]; - int packet_size, width, height, ret; - AVStream *st = s->streams[0]; + int ret; + int64_t off = avio_tell(s->pb); for (i = 0; i < MAX_FRAME_HEADER; i++) { header[i] = avio_r8(s->pb); @@ -284,20 +290,22 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) return AVERROR_INVALIDDATA; - width = st->codec->width; - height = st->codec->height; - - packet_size = avpicture_get_size(st->codec->pix_fmt, width, height); - if (packet_size < 0) - return packet_size; - - ret = av_get_packet(s->pb, pkt, packet_size); + ret = av_get_packet(s->pb, pkt, s->packet_size - Y4M_FRAME_MAGIC_LEN); if (ret < 0) return ret; - else if (ret != packet_size) + else if (ret != s->packet_size - Y4M_FRAME_MAGIC_LEN) return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO); pkt->stream_index = 0; + pkt->pts = (off - s->internal->data_offset) / s->packet_size; + pkt->duration = 1; + return 0; +} + +static int yuv4_read_seek(AVFormatContext *s, int stream_index, + int64_t pts, int flags) +{ + avio_seek(s->pb, pts * s->packet_size + s->internal->data_offset, SEEK_SET); return 0; } @@ -316,5 +324,6 @@ AVInputFormat ff_yuv4mpegpipe_demuxer = { .read_probe = yuv4_probe, .read_header = yuv4_read_header, .read_packet = yuv4_read_packet, + .read_seek = yuv4_read_seek, .extensions = "y4m", }; diff --git a/chromium/third_party/ffmpeg/libavformat/yuv4mpegenc.c b/chromium/third_party/ffmpeg/libavformat/yuv4mpegenc.c index cc954fcc630..c15ea1de0cb 100644 --- a/chromium/third_party/ffmpeg/libavformat/yuv4mpegenc.c +++ b/chromium/third_party/ffmpeg/libavformat/yuv4mpegenc.c @@ -143,7 +143,6 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) int width, height, h_chroma_shift, v_chroma_shift; int i; char buf2[Y4M_LINE_MAX + 1]; - char buf1[20]; uint8_t *ptr, *ptr1, *ptr2; memcpy(&picture_tmp, pkt->data, sizeof(AVPicture)); @@ -163,8 +162,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) /* construct frame header */ - snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC); - avio_write(pb, buf1, strlen(buf1)); + avio_printf(s->pb, "%s\n", Y4M_FRAME_MAGIC); width = st->codec->width; height = st->codec->height; |