diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-29 10:46:47 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-02 12:02:10 +0000 |
commit | 99677208ff3b216fdfec551fbe548da5520cd6fb (patch) | |
tree | 476a4865c10320249360e859d8fdd3e01833b03a /chromium/third_party/ffmpeg/libavformat | |
parent | c30a6232df03e1efbd9f3b226777b07e087a1122 (diff) | |
download | qtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz |
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/ffmpeg/libavformat')
169 files changed, 5247 insertions, 3927 deletions
diff --git a/chromium/third_party/ffmpeg/libavformat/3dostr.c b/chromium/third_party/ffmpeg/libavformat/3dostr.c index 6c49f7589c4..3ec3c4393eb 100644 --- a/chromium/third_party/ffmpeg/libavformat/3dostr.c +++ b/chromium/third_party/ffmpeg/libavformat/3dostr.c @@ -110,15 +110,12 @@ static int threedostr_read_header(AVFormatContext *s) static int threedostr_read_packet(AVFormatContext *s, AVPacket *pkt) { - unsigned chunk, size, found_ssmp = 0; + unsigned chunk, size; AVStream *st = s->streams[0]; int64_t pos; int ret = 0; - while (!found_ssmp) { - if (avio_feof(s->pb)) - return AVERROR_EOF; - + while (!avio_feof(s->pb)) { pos = avio_tell(s->pb); chunk = avio_rl32(s->pb); size = avio_rb32(s->pb); @@ -143,9 +140,7 @@ static int threedostr_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pos = pos; pkt->stream_index = 0; pkt->duration = size / st->codecpar->channels; - size = 0; - found_ssmp = 1; - break; + return ret; default: av_log(s, AV_LOG_DEBUG, "skipping unknown chunk: %X\n", chunk); break; @@ -154,7 +149,7 @@ static int threedostr_read_packet(AVFormatContext *s, AVPacket *pkt) avio_skip(s->pb, size); } - return ret; + return AVERROR_EOF; } AVInputFormat ff_threedostr_demuxer = { diff --git a/chromium/third_party/ffmpeg/libavformat/4xm.c b/chromium/third_party/ffmpeg/libavformat/4xm.c index aea9226984e..6a227a0b0d2 100644 --- a/chromium/third_party/ffmpeg/libavformat/4xm.c +++ b/chromium/third_party/ffmpeg/libavformat/4xm.c @@ -59,8 +59,10 @@ #define GET_LIST_HEADER() \ fourcc_tag = avio_rl32(pb); \ size = avio_rl32(pb); \ - if (fourcc_tag != LIST_TAG) \ - return AVERROR_INVALIDDATA; \ + if (fourcc_tag != LIST_TAG) { \ + ret = AVERROR_INVALIDDATA; \ + goto fail; \ + } \ fourcc_tag = avio_rl32(pb); typedef struct AudioTrack { @@ -210,12 +212,13 @@ static int fourxm_read_header(AVFormatContext *s) unsigned int size; int header_size; FourxmDemuxContext *fourxm = s->priv_data; - unsigned char *header; + unsigned char *header = NULL; int i, ret; fourxm->track_count = 0; fourxm->tracks = NULL; fourxm->fps = (AVRational){1,1}; + fourxm->video_stream_index = -1; /* skip the first 3 32-bit numbers */ avio_skip(pb, 12); @@ -324,6 +327,8 @@ static int fourxm_read_packet(AVFormatContext *s, * and size */ if (size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 8) return AVERROR_INVALIDDATA; + if (fourxm->video_stream_index < 0) + return AVERROR_INVALIDDATA; if ((ret = av_new_packet(pkt, size + 8)) < 0) return ret; pkt->stream_index = fourxm->video_stream_index; diff --git a/chromium/third_party/ffmpeg/libavformat/Makefile b/chromium/third_party/ffmpeg/libavformat/Makefile index d4bed3c1137..cbb33fe37c1 100644 --- a/chromium/third_party/ffmpeg/libavformat/Makefile +++ b/chromium/third_party/ffmpeg/libavformat/Makefile @@ -94,6 +94,7 @@ OBJS-$(CONFIG_ANM_DEMUXER) += anm.o OBJS-$(CONFIG_APC_DEMUXER) += apc.o OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o OBJS-$(CONFIG_APM_DEMUXER) += apm.o +OBJS-$(CONFIG_APM_MUXER) += apm.o rawenc.o OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o OBJS-$(CONFIG_APNG_MUXER) += apngenc.o OBJS-$(CONFIG_APTX_DEMUXER) += aptxdec.o rawdec.o @@ -102,6 +103,7 @@ OBJS-$(CONFIG_APTX_HD_DEMUXER) += aptxdec.o rawdec.o OBJS-$(CONFIG_APTX_HD_MUXER) += rawenc.o OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o OBJS-$(CONFIG_ARGO_ASF_DEMUXER) += argo_asf.o +OBJS-$(CONFIG_ARGO_ASF_MUXER) += argo_asf.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 \ @@ -205,7 +207,7 @@ OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o OBJS-$(CONFIG_GSM_DEMUXER) += gsmdec.o OBJS-$(CONFIG_GSM_MUXER) += rawenc.o OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o -OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o audiointerleave.o +OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o OBJS-$(CONFIG_G722_DEMUXER) += g722.o rawdec.o OBJS-$(CONFIG_G722_MUXER) += rawenc.o OBJS-$(CONFIG_G723_1_DEMUXER) += g723_1.o @@ -285,6 +287,7 @@ OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o OBJS-$(CONFIG_KUX_DEMUXER) += flvdec.o OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o +OBJS-$(CONFIG_KVAG_MUXER) += kvag.o rawenc.o OBJS-$(CONFIG_LATM_MUXER) += latmenc.o rawenc.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o rawdec.o @@ -302,6 +305,7 @@ OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ av1.o avc.o hevc.o \ flacenc_header.o avlanguage.o \ vorbiscomment.o wv.o +OBJS-$(CONFIG_MCC_DEMUXER) += mccdec.o subtitles.o OBJS-$(CONFIG_MD5_MUXER) += hashenc.o OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o @@ -347,7 +351,7 @@ OBJS-$(CONFIG_MUSX_DEMUXER) += musx.o OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o -OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o avc.o +OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o avc.o OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o @@ -358,9 +362,9 @@ OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o isom.o OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o OBJS-$(CONFIG_AV1_DEMUXER) += av1dec.o +OBJS-$(CONFIG_OBU_DEMUXER) += av1dec.o OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparsecelt.o \ - oggparsedaala.o \ oggparsedirac.o \ oggparseflac.o \ oggparseogm.o \ @@ -428,6 +432,7 @@ OBJS-$(CONFIG_PCM_VIDC_DEMUXER) += pcmdec.o pcm.o OBJS-$(CONFIG_PCM_VIDC_MUXER) += pcmenc.o rawenc.o OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o +OBJS-$(CONFIG_PP_BNK_DEMUXER) += pp_bnk.o OBJS-$(CONFIG_PVA_DEMUXER) += pva.o OBJS-$(CONFIG_PVF_DEMUXER) += pvfdec.o pcm.o OBJS-$(CONFIG_QCP_DEMUXER) += qcp.o @@ -669,3 +674,4 @@ TOOLS = aviocat \ probetest \ seek_print \ sidxindex \ + venc_data_dump diff --git a/chromium/third_party/ffmpeg/libavformat/aacdec.c b/chromium/third_party/ffmpeg/libavformat/aacdec.c index ba3f5ccc6dd..a0aa112a8a2 100644 --- a/chromium/third_party/ffmpeg/libavformat/aacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/aacdec.c @@ -146,7 +146,7 @@ static int handle_id3(AVFormatContext *s, AVPacket *pkt) ffio_init_context(&ioctx, pkt->data, pkt->size, 0, NULL, NULL, NULL, NULL); ff_id3v2_read_dict(&ioctx, &metadata, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); - if ((ret = ff_id3v2_parse_priv_dict(&metadata, &id3v2_extra_meta)) < 0) + if ((ret = ff_id3v2_parse_priv_dict(&metadata, id3v2_extra_meta)) < 0) goto error; if (metadata) { diff --git a/chromium/third_party/ffmpeg/libavformat/aadec.c b/chromium/third_party/ffmpeg/libavformat/aadec.c index b9dd51ebfc3..63f8176a570 100644 --- a/chromium/third_party/ffmpeg/libavformat/aadec.c +++ b/chromium/third_party/ffmpeg/libavformat/aadec.c @@ -92,7 +92,7 @@ static int aa_read_header(AVFormatContext *s) 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) + if (toc_size > MAX_TOC_ENTRIES || toc_size < 2) return AVERROR_INVALIDDATA; for (i = 0; i < toc_size; i++) { // read TOC avio_skip(pb, 4); // TOC entry index diff --git a/chromium/third_party/ffmpeg/libavformat/adtsenc.c b/chromium/third_party/ffmpeg/libavformat/adtsenc.c index d937e2bea9c..9e285752eb5 100644 --- a/chromium/third_party/ffmpeg/libavformat/adtsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/adtsenc.c @@ -169,7 +169,7 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt) return 0; if (!par->extradata_size) { uint8_t *side_data; - int side_data_size = 0, ret; + int side_data_size, ret; side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size); diff --git a/chromium/third_party/ffmpeg/libavformat/aiffdec.c b/chromium/third_party/ffmpeg/libavformat/aiffdec.c index cb2f1b60fbe..c650e9074d5 100644 --- a/chromium/third_party/ffmpeg/libavformat/aiffdec.c +++ b/chromium/third_party/ffmpeg/libavformat/aiffdec.c @@ -261,8 +261,8 @@ static int aiff_read_header(AVFormatContext *s) position = avio_tell(pb); ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); if (id3v2_extra_meta) - if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0 || - (ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0) { + if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || + (ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) { ff_id3v2_free_extra_meta(&id3v2_extra_meta); return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/aiffenc.c b/chromium/third_party/ffmpeg/libavformat/aiffenc.c index 0145596bec8..88c45df3347 100644 --- a/chromium/third_party/ffmpeg/libavformat/aiffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/aiffenc.c @@ -49,7 +49,7 @@ static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff) AVIOContext *pb = s->pb; AVPacketList *pict_list = aiff->pict_list; - if (!s->metadata && !aiff->pict_list) + if (!s->metadata && !s->nb_chapters && !aiff->pict_list) return 0; avio_wl32(pb, MKTAG('I', 'D', '3', ' ')); diff --git a/chromium/third_party/ffmpeg/libavformat/allformats.c b/chromium/third_party/ffmpeg/libavformat/allformats.c index 39d2c352f57..0aa9dd71988 100644 --- a/chromium/third_party/ffmpeg/libavformat/allformats.c +++ b/chromium/third_party/ffmpeg/libavformat/allformats.c @@ -55,6 +55,7 @@ extern AVInputFormat ff_anm_demuxer; extern AVInputFormat ff_apc_demuxer; extern AVInputFormat ff_ape_demuxer; extern AVInputFormat ff_apm_demuxer; +extern AVOutputFormat ff_apm_muxer; extern AVInputFormat ff_apng_demuxer; extern AVOutputFormat ff_apng_muxer; extern AVInputFormat ff_aptx_demuxer; @@ -63,6 +64,7 @@ extern AVInputFormat ff_aptx_hd_demuxer; extern AVOutputFormat ff_aptx_hd_muxer; extern AVInputFormat ff_aqtitle_demuxer; extern AVInputFormat ff_argo_asf_demuxer; +extern AVOutputFormat ff_argo_asf_muxer; extern AVInputFormat ff_asf_demuxer; extern AVOutputFormat ff_asf_muxer; extern AVInputFormat ff_asf_o_demuxer; @@ -220,6 +222,7 @@ extern AVOutputFormat ff_jacosub_muxer; extern AVInputFormat ff_jv_demuxer; extern AVInputFormat ff_kux_demuxer; extern AVInputFormat ff_kvag_demuxer; +extern AVOutputFormat ff_kvag_muxer; extern AVOutputFormat ff_latm_muxer; extern AVInputFormat ff_lmlm4_demuxer; extern AVInputFormat ff_loas_demuxer; @@ -229,6 +232,7 @@ extern AVInputFormat ff_lvf_demuxer; extern AVInputFormat ff_lxf_demuxer; extern AVInputFormat ff_m4v_demuxer; extern AVOutputFormat ff_m4v_muxer; +extern AVInputFormat ff_mcc_demuxer; extern AVOutputFormat ff_md5_muxer; extern AVInputFormat ff_matroska_demuxer; extern AVOutputFormat ff_matroska_muxer; @@ -289,6 +293,7 @@ extern AVOutputFormat ff_null_muxer; extern AVInputFormat ff_nut_demuxer; extern AVOutputFormat ff_nut_muxer; extern AVInputFormat ff_nuv_demuxer; +extern AVInputFormat ff_obu_demuxer; extern AVOutputFormat ff_oga_muxer; extern AVInputFormat ff_ogg_demuxer; extern AVOutputFormat ff_ogg_muxer; @@ -341,6 +346,7 @@ extern AVInputFormat ff_pcm_u8_demuxer; extern AVOutputFormat ff_pcm_u8_muxer; extern AVInputFormat ff_pjs_demuxer; extern AVInputFormat ff_pmp_demuxer; +extern AVInputFormat ff_pp_bnk_demuxer; extern AVOutputFormat ff_psp_muxer; extern AVInputFormat ff_pva_demuxer; extern AVInputFormat ff_pvf_demuxer; @@ -485,6 +491,7 @@ extern AVInputFormat ff_image_pbm_pipe_demuxer; extern AVInputFormat ff_image_pcx_pipe_demuxer; extern AVInputFormat ff_image_pgmyuv_pipe_demuxer; extern AVInputFormat ff_image_pgm_pipe_demuxer; +extern AVInputFormat ff_image_pgx_pipe_demuxer; extern AVInputFormat ff_image_pictor_pipe_demuxer; extern AVInputFormat ff_image_png_pipe_demuxer; extern AVInputFormat ff_image_ppm_pipe_demuxer; diff --git a/chromium/third_party/ffmpeg/libavformat/ape.c b/chromium/third_party/ffmpeg/libavformat/ape.c index ed6752a4150..d92cb2867dd 100644 --- a/chromium/third_party/ffmpeg/libavformat/ape.c +++ b/chromium/third_party/ffmpeg/libavformat/ape.c @@ -83,6 +83,8 @@ typedef struct APEContext { uint8_t *bittable; } APEContext; +static int ape_read_close(AVFormatContext * s); + static int ape_probe(const AVProbeData * p) { int version = AV_RL16(p->buf+4); @@ -251,7 +253,7 @@ static int ape_read_header(AVFormatContext * s) avio_skip(pb, ape->wavheaderlength); } - if(!ape->totalframes){ + if(!ape->totalframes || pb->eof_reached){ av_log(s, AV_LOG_ERROR, "No frames in the file!\n"); return AVERROR(EINVAL); } @@ -281,19 +283,26 @@ static int ape_read_header(AVFormatContext * s) if (ape->seektablelength > 0) { ape->seektable = av_mallocz(ape->seektablelength); - if (!ape->seektable) - return AVERROR(ENOMEM); + if (!ape->seektable) { + ret = AVERROR(ENOMEM); + goto fail; + } for (i = 0; i < ape->seektablelength / sizeof(uint32_t) && !pb->eof_reached; i++) ape->seektable[i] = avio_rl32(pb); if (ape->fileversion < 3810) { ape->bittable = av_mallocz(ape->totalframes); - if (!ape->bittable) - return AVERROR(ENOMEM); + if (!ape->bittable) { + ret = AVERROR(ENOMEM); + goto fail; + } for (i = 0; i < ape->totalframes && !pb->eof_reached; i++) ape->bittable[i] = avio_r8(pb); } - if (pb->eof_reached) - av_log(s, AV_LOG_WARNING, "File truncated\n"); + if (pb->eof_reached) { + av_log(s, AV_LOG_ERROR, "File truncated\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } } ape->frames[0].pos = ape->firstframe; @@ -341,8 +350,10 @@ static int ape_read_header(AVFormatContext * s) /* now we are ready: build format streams */ st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); + if (!st) { + ret = AVERROR(ENOMEM); + goto fail; + } total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks; @@ -359,7 +370,7 @@ static int ape_read_header(AVFormatContext * s) avpriv_set_pts_info(st, 64, 1, ape->samplerate); if ((ret = ff_alloc_extradata(st->codecpar, APE_EXTRADATA_SIZE)) < 0) - return ret; + goto fail; AV_WL16(st->codecpar->extradata + 0, ape->fileversion); AV_WL16(st->codecpar->extradata + 2, ape->compressiontype); AV_WL16(st->codecpar->extradata + 4, ape->formatflags); @@ -378,6 +389,10 @@ static int ape_read_header(AVFormatContext * s) } return 0; +fail: + ape_read_close(s); + + return ret; } static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/apm.c b/chromium/third_party/ffmpeg/libavformat/apm.c index 9d2a856cc4c..38a0f6382a9 100644 --- a/chromium/third_party/ffmpeg/libavformat/apm.c +++ b/chromium/third_party/ffmpeg/libavformat/apm.c @@ -1,5 +1,5 @@ /* - * Rayman 2 APM Demuxer + * Rayman 2 APM (De)muxer * * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) * @@ -21,14 +21,18 @@ */ #include "avformat.h" #include "internal.h" -#include "riff.h" +#include "rawenc.h" +#include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #define APM_FILE_HEADER_SIZE 20 -#define APM_VS12_CHUNK_SIZE 76 +#define APM_FILE_EXTRADATA_SIZE 80 +#define APM_EXTRADATA_SIZE 28 + #define APM_MAX_READ_SIZE 4096 +#define APM_TAG_CODEC 0x2000 #define APM_TAG_VS12 MKTAG('v', 's', '1', '2') #define APM_TAG_DATA MKTAG('D', 'A', 'T', 'A') @@ -42,38 +46,45 @@ typedef struct APMState { int32_t saved_l; } APMState; -typedef struct APMVS12Chunk { +typedef struct APMExtraData { uint32_t magic; uint32_t file_size; uint32_t data_size; uint32_t unk1; uint32_t unk2; APMState state; - uint32_t pad[7]; -} APMVS12Chunk; + uint32_t unk3[7]; + uint32_t data; +} APMExtraData; -static void apm_parse_vs12(APMVS12Chunk *vs12, const uint8_t *buf) +#if CONFIG_APM_DEMUXER +static void apm_parse_extradata(APMExtraData *ext, const uint8_t *buf) { - vs12->magic = AV_RL32(buf + 0); - vs12->file_size = AV_RL32(buf + 4); - vs12->data_size = AV_RL32(buf + 8); - vs12->unk1 = AV_RL32(buf + 12); - vs12->unk2 = AV_RL32(buf + 16); - - vs12->state.has_saved = AV_RL32(buf + 20); - vs12->state.predictor_r = AV_RL32(buf + 24); - vs12->state.step_index_r = AV_RL32(buf + 28); - vs12->state.saved_r = AV_RL32(buf + 32); - vs12->state.predictor_l = AV_RL32(buf + 36); - vs12->state.step_index_l = AV_RL32(buf + 40); - vs12->state.saved_l = AV_RL32(buf + 44); - - for (int i = 0; i < FF_ARRAY_ELEMS(vs12->pad); i++) - vs12->pad[i] = AV_RL32(buf + 48 + (i * 4)); + ext->magic = AV_RL32(buf + 0); + ext->file_size = AV_RL32(buf + 4); + ext->data_size = AV_RL32(buf + 8); + ext->unk1 = AV_RL32(buf + 12); + ext->unk2 = AV_RL32(buf + 16); + + ext->state.has_saved = AV_RL32(buf + 20); + ext->state.predictor_r = AV_RL32(buf + 24); + ext->state.step_index_r = AV_RL32(buf + 28); + ext->state.saved_r = AV_RL32(buf + 32); + ext->state.predictor_l = AV_RL32(buf + 36); + ext->state.step_index_l = AV_RL32(buf + 40); + ext->state.saved_l = AV_RL32(buf + 44); + + for (int i = 0; i < FF_ARRAY_ELEMS(ext->unk3); i++) + ext->unk3[i] = AV_RL32(buf + 48 + (i * 4)); + + ext->data = AV_RL32(buf + 76); } static int apm_probe(const AVProbeData *p) { + if (AV_RL16(p->buf) != APM_TAG_CODEC) + return 0; + if (p->buf_size < 100) return 0; @@ -90,71 +101,82 @@ static int apm_read_header(AVFormatContext *s) { int64_t ret; AVStream *st; - APMVS12Chunk vs12; - uint8_t buf[APM_VS12_CHUNK_SIZE]; + APMExtraData extradata; + AVCodecParameters *par; + uint8_t buf[APM_FILE_EXTRADATA_SIZE]; if (!(st = avformat_new_stream(s, NULL))) return AVERROR(ENOMEM); - /* The header starts with a WAVEFORMATEX */ - if ((ret = ff_get_wav_header(s, s->pb, st->codecpar, APM_FILE_HEADER_SIZE, 0)) < 0) + /* + * This is 98% a WAVEFORMATEX, but there's something screwy with the extradata + * that ff_get_wav_header() can't (and shouldn't) handle properly. + */ + if (avio_rl16(s->pb) != APM_TAG_CODEC) + return AVERROR_INVALIDDATA; + + par = st->codecpar; + par->channels = avio_rl16(s->pb); + par->sample_rate = avio_rl32(s->pb); + + /* Skip the bitrate, it's usually wrong anyway. */ + if ((ret = avio_skip(s->pb, 4)) < 0) return ret; - if (st->codecpar->bits_per_coded_sample != 4) + par->block_align = avio_rl16(s->pb); + par->bits_per_coded_sample = avio_rl16(s->pb); + + if (avio_rl32(s->pb) != APM_FILE_EXTRADATA_SIZE) return AVERROR_INVALIDDATA; - if (st->codecpar->codec_tag != 0x2000) + /* 8 = bits per sample * max channels */ + if (par->sample_rate > (INT_MAX / 8)) return AVERROR_INVALIDDATA; - /* ff_get_wav_header() does most of the work, but we need to fix a few things. */ - st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_APM; - st->codecpar->codec_tag = 0; + if (par->bits_per_coded_sample != 4) + return AVERROR_INVALIDDATA; - if (st->codecpar->channels == 2) - st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; - else if (st->codecpar->channels == 1) - st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + if (par->channels == 2) + par->channel_layout = AV_CH_LAYOUT_STEREO; + else if (par->channels == 1) + par->channel_layout = AV_CH_LAYOUT_MONO; else return AVERROR_INVALIDDATA; - st->codecpar->format = AV_SAMPLE_FMT_S16; - st->codecpar->bits_per_raw_sample = 16; - st->codecpar->bit_rate = st->codecpar->channels * - st->codecpar->sample_rate * - st->codecpar->bits_per_coded_sample; + par->codec_type = AVMEDIA_TYPE_AUDIO; + par->codec_id = AV_CODEC_ID_ADPCM_IMA_APM; + par->format = AV_SAMPLE_FMT_S16; + par->bits_per_raw_sample = 16; + par->bit_rate = par->channels * + par->sample_rate * + par->bits_per_coded_sample; - if ((ret = avio_read(s->pb, buf, APM_VS12_CHUNK_SIZE)) < 0) + if ((ret = avio_read(s->pb, buf, APM_FILE_EXTRADATA_SIZE)) < 0) return ret; - else if (ret != APM_VS12_CHUNK_SIZE) + else if (ret != APM_FILE_EXTRADATA_SIZE) return AVERROR(EIO); - apm_parse_vs12(&vs12, buf); + apm_parse_extradata(&extradata, buf); - if (vs12.magic != APM_TAG_VS12) { + if (extradata.magic != APM_TAG_VS12 || extradata.data != APM_TAG_DATA) return AVERROR_INVALIDDATA; - } - if (vs12.state.has_saved) { + if (extradata.state.has_saved) { avpriv_request_sample(s, "Saved Samples"); return AVERROR_PATCHWELCOME; } - if (avio_rl32(s->pb) != APM_TAG_DATA) - return AVERROR_INVALIDDATA; - - if ((ret = ff_alloc_extradata(st->codecpar, 16)) < 0) + if ((ret = ff_alloc_extradata(par, APM_EXTRADATA_SIZE)) < 0) return ret; - AV_WL32(st->codecpar->extradata + 0, vs12.state.predictor_l); - AV_WL32(st->codecpar->extradata + 4, vs12.state.step_index_l); - AV_WL32(st->codecpar->extradata + 8, vs12.state.predictor_r); - AV_WL32(st->codecpar->extradata + 12, vs12.state.step_index_r); + /* Use the entire state as extradata. */ + memcpy(par->extradata, buf + 20, APM_EXTRADATA_SIZE); - avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + avpriv_set_pts_info(st, 64, 1, par->sample_rate); st->start_time = 0; - st->duration = vs12.data_size * - (8 / st->codecpar->bits_per_coded_sample) / - st->codecpar->channels; + st->duration = extradata.data_size * + (8 / par->bits_per_coded_sample) / + par->channels; return 0; } @@ -186,3 +208,110 @@ AVInputFormat ff_apm_demuxer = { .read_header = apm_read_header, .read_packet = apm_read_packet }; +#endif + +#if CONFIG_APM_MUXER +static int apm_write_init(AVFormatContext *s) +{ + AVCodecParameters *par; + + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "APM files have exactly one stream\n"); + return AVERROR(EINVAL); + } + + par = s->streams[0]->codecpar; + + if (par->codec_id != AV_CODEC_ID_ADPCM_IMA_APM) { + av_log(s, AV_LOG_ERROR, "%s codec not supported\n", + avcodec_get_name(par->codec_id)); + return AVERROR(EINVAL); + } + + if (par->channels > 2) { + av_log(s, AV_LOG_ERROR, "APM files only support up to 2 channels\n"); + return AVERROR(EINVAL); + } + + if (par->sample_rate > (INT_MAX / 8)) { + av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); + return AVERROR(EINVAL); + } + + if (par->extradata_size != APM_EXTRADATA_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid/missing extradata\n"); + return AVERROR(EINVAL); + } + + if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { + av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int apm_write_header(AVFormatContext *s) +{ + uint8_t buf[APM_FILE_EXTRADATA_SIZE] = { 0 }; + AVCodecParameters *par = s->streams[0]->codecpar; + + /* + * Bodge a WAVEFORMATEX manually, ff_put_wav_header() can't + * be used because of the extra 2 bytes. + */ + avio_wl16(s->pb, APM_TAG_CODEC); + avio_wl16(s->pb, par->channels); + avio_wl32(s->pb, par->sample_rate); + /* This is the wrong calculation, but it's what the orginal files have. */ + avio_wl32(s->pb, par->sample_rate * par->channels * 2); + avio_wl16(s->pb, par->block_align); + avio_wl16(s->pb, par->bits_per_coded_sample); + avio_wl32(s->pb, APM_FILE_EXTRADATA_SIZE); + + /* + * Build the extradata. Assume the codec's given us correct data. + * File and data sizes are fixed later. + */ + AV_WL32(buf + 0, APM_TAG_VS12); /* magic */ + AV_WL32(buf + 12, 0xFFFFFFFF); /* unk1 */ + memcpy( buf + 20, par->extradata, APM_EXTRADATA_SIZE); + AV_WL32(buf + 76, APM_TAG_DATA); /* data */ + + avio_write(s->pb, buf, APM_FILE_EXTRADATA_SIZE); + return 0; +} + +static int apm_write_trailer(AVFormatContext *s) +{ + int64_t file_size, data_size; + + file_size = avio_tell(s->pb); + data_size = file_size - (APM_FILE_HEADER_SIZE + APM_FILE_EXTRADATA_SIZE); + + if (file_size >= UINT32_MAX) { + av_log(s, AV_LOG_ERROR, + "Filesize %"PRId64" invalid for APM, output file will be broken\n", + file_size); + return AVERROR(ERANGE); + } + + avio_seek(s->pb, 24, SEEK_SET); + avio_wl32(s->pb, (uint32_t)file_size); + avio_wl32(s->pb, (uint32_t)data_size); + + return 0; +} + +AVOutputFormat ff_apm_muxer = { + .name = "apm", + .long_name = NULL_IF_CONFIG_SMALL("Ubisoft Rayman 2 APM"), + .extensions = "apm", + .audio_codec = AV_CODEC_ID_ADPCM_IMA_APM, + .video_codec = AV_CODEC_ID_NONE, + .init = apm_write_init, + .write_header = apm_write_header, + .write_packet = ff_raw_write_packet, + .write_trailer = apm_write_trailer +}; +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/apngenc.c b/chromium/third_party/ffmpeg/libavformat/apngenc.c index 88cd8054d6d..7ad6a923d5e 100644 --- a/chromium/third_party/ffmpeg/libavformat/apngenc.c +++ b/chromium/third_party/ffmpeg/libavformat/apngenc.c @@ -119,7 +119,7 @@ static int flush_packet(AVFormatContext *format_context, AVPacket *packet) AVIOContext *io_context = format_context->pb; AVStream *codec_stream = format_context->streams[0]; uint8_t *side_data = NULL; - int side_data_size = 0; + int side_data_size; av_assert0(apng->prev_packet); diff --git a/chromium/third_party/ffmpeg/libavformat/aqtitledec.c b/chromium/third_party/ffmpeg/libavformat/aqtitledec.c index 8cc82a8f39a..81630d73b09 100644 --- a/chromium/third_party/ffmpeg/libavformat/aqtitledec.c +++ b/chromium/third_party/ffmpeg/libavformat/aqtitledec.c @@ -81,11 +81,11 @@ static int aqt_read_header(AVFormatContext *s) if (!new_event) { sub = ff_subtitles_queue_insert(&aqt->q, "\n", 1, 1); if (!sub) - return AVERROR(ENOMEM); + goto fail; } sub = ff_subtitles_queue_insert(&aqt->q, line, strlen(line), !new_event); if (!sub) - return AVERROR(ENOMEM); + goto fail; if (new_event) { sub->pts = frame; sub->duration = -1; @@ -97,6 +97,9 @@ static int aqt_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &aqt->q); return 0; +fail: + ff_subtitles_queue_clean(&aqt->q); + return AVERROR(ENOMEM); } static int aqt_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/argo_asf.c b/chromium/third_party/ffmpeg/libavformat/argo_asf.c index 3339425244d..37ad2bf5e9f 100644 --- a/chromium/third_party/ffmpeg/libavformat/argo_asf.c +++ b/chromium/third_party/ffmpeg/libavformat/argo_asf.c @@ -1,5 +1,5 @@ /* - * Argonaut Games ASF demuxer + * Argonaut Games ASF (de)muxer * * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) * @@ -23,10 +23,12 @@ #include "internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/avassert.h" +#include "libavutil/opt.h" #define ASF_TAG MKTAG('A', 'S', 'F', '\0') #define ASF_FILE_HEADER_SIZE 24 #define ASF_CHUNK_HEADER_SIZE 20 +#define ASF_SAMPLE_COUNT 32 typedef struct ArgoASFFileHeader { uint32_t magic; /*< Magic Number, {'A', 'S', 'F', '\0'} */ @@ -39,7 +41,7 @@ typedef struct ArgoASFFileHeader { typedef struct ArgoASFChunkHeader { uint32_t num_blocks; /*< No. blocks in the chunk. */ - uint32_t num_samples; /*< No. samples per channel in a block. */ + uint32_t num_samples; /*< No. samples per channel in a block. Always 32. */ uint32_t unk1; /*< Unknown */ uint16_t sample_rate; /*< Sample rate. */ uint16_t unk2; /*< Unknown. */ @@ -62,6 +64,14 @@ typedef struct ArgoASFDemuxContext { uint32_t blocks_read; } ArgoASFDemuxContext; +typedef struct ArgoASFMuxContext { + const AVClass *class; + int version_major; + int version_minor; + const char *name; +} ArgoASFMuxContext; + +#if CONFIG_ARGO_ASF_DEMUXER static void argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf) { hdr->magic = AV_RL32(buf + 0); @@ -85,9 +95,12 @@ static void argo_asf_parse_chunk_header(ArgoASFChunkHeader *hdr, const uint8_t * /* * Known versions: - * 1.1: The sample files in /game-formats/brender/part2.zip + * 1.1: https://samples.ffmpeg.org/game-formats/brender/part2.zip + * FX Fighter * 1.2: Croc! Legend of the Gobbos * 2.1: Croc 2 + * The Emperor's New Groove + * Disney's Aladdin in Nasira's Revenge */ static int argo_asf_is_known_version(const ArgoASFFileHeader *hdr) { @@ -131,13 +144,6 @@ static int argo_asf_read_header(AVFormatContext *s) argo_asf_parse_file_header(&asf->fhdr, buf); - if (!argo_asf_is_known_version(&asf->fhdr)) { - avpriv_request_sample(s, "Version %hu.%hu", - asf->fhdr.version_major, asf->fhdr.version_minor - ); - return AVERROR_PATCHWELCOME; - } - if (asf->fhdr.num_chunks == 0) { return AVERROR_INVALIDDATA; } else if (asf->fhdr.num_chunks > 1) { @@ -158,6 +164,12 @@ static int argo_asf_read_header(AVFormatContext *s) argo_asf_parse_chunk_header(&asf->ckhdr, buf); + if (asf->ckhdr.num_samples != ASF_SAMPLE_COUNT) { + av_log(s, AV_LOG_ERROR, "Invalid sample count. Got %u, expected %d\n", + asf->ckhdr.num_samples, ASF_SAMPLE_COUNT); + return AVERROR_INVALIDDATA; + } + if ((asf->ckhdr.flags & ASF_CF_ALWAYS1) != ASF_CF_ALWAYS1 || (asf->ckhdr.flags & ASF_CF_ALWAYS0) != 0) { avpriv_request_sample(s, "Nonstandard flags (0x%08X)", asf->ckhdr.flags); return AVERROR_PATCHWELCOME; @@ -247,3 +259,186 @@ AVInputFormat ff_argo_asf_demuxer = { .read_header = argo_asf_read_header, .read_packet = argo_asf_read_packet }; +#endif + +#if CONFIG_ARGO_ASF_MUXER +static int argo_asf_write_init(AVFormatContext *s) +{ + const AVCodecParameters *par; + + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "ASF files have exactly one stream\n"); + return AVERROR(EINVAL); + } + + par = s->streams[0]->codecpar; + + if (par->codec_id != AV_CODEC_ID_ADPCM_ARGO) { + av_log(s, AV_LOG_ERROR, "%s codec not supported\n", + avcodec_get_name(par->codec_id)); + return AVERROR(EINVAL); + } + + if (par->channels > 2) { + av_log(s, AV_LOG_ERROR, "ASF files only support up to 2 channels\n"); + return AVERROR(EINVAL); + } + + if (par->sample_rate > UINT16_MAX) { + av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); + return AVERROR(EINVAL); + } + + if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { + av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static void argo_asf_write_file_header(const ArgoASFFileHeader *fhdr, AVIOContext *pb) +{ + avio_wl32( pb, fhdr->magic); + avio_wl16( pb, fhdr->version_major); + avio_wl16( pb, fhdr->version_minor); + avio_wl32( pb, fhdr->num_chunks); + avio_wl32( pb, fhdr->chunk_offset); + avio_write(pb, fhdr->name, sizeof(fhdr->name)); +} + +static void argo_asf_write_chunk_header(const ArgoASFChunkHeader *ckhdr, AVIOContext *pb) +{ + avio_wl32(pb, ckhdr->num_blocks); + avio_wl32(pb, ckhdr->num_samples); + avio_wl32(pb, ckhdr->unk1); + avio_wl16(pb, ckhdr->sample_rate); + avio_wl16(pb, ckhdr->unk2); + avio_wl32(pb, ckhdr->flags); +} + +static int argo_asf_write_header(AVFormatContext *s) +{ + const AVCodecParameters *par = s->streams[0]->codecpar; + ArgoASFMuxContext *ctx = s->priv_data; + ArgoASFFileHeader fhdr; + ArgoASFChunkHeader chdr; + + fhdr.magic = ASF_TAG; + fhdr.version_major = (uint16_t)ctx->version_major; + fhdr.version_minor = (uint16_t)ctx->version_minor; + fhdr.num_chunks = 1; + fhdr.chunk_offset = ASF_FILE_HEADER_SIZE; + /* + * If the user specified a name, use it as is. Otherwise take the + * basename and lop off the extension (if any). + */ + if (ctx->name) { + strncpy(fhdr.name, ctx->name, sizeof(fhdr.name)); + } else { + const char *start = av_basename(s->url); + const char *end = strrchr(start, '.'); + size_t len; + + if(end) + len = end - start; + else + len = strlen(start); + + memcpy(fhdr.name, start, FFMIN(len, sizeof(fhdr.name))); + } + + chdr.num_blocks = 0; + chdr.num_samples = ASF_SAMPLE_COUNT; + chdr.unk1 = 0; + chdr.sample_rate = par->sample_rate; + chdr.unk2 = ~0; + chdr.flags = ASF_CF_BITS_PER_SAMPLE | ASF_CF_ALWAYS1; + + if (par->channels == 2) + chdr.flags |= ASF_CF_STEREO; + + argo_asf_write_file_header(&fhdr, s->pb); + argo_asf_write_chunk_header(&chdr, s->pb); + return 0; +} + +static int argo_asf_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (pkt->size != 17 * s->streams[0]->codecpar->channels) + return AVERROR_INVALIDDATA; + + if (s->streams[0]->nb_frames >= UINT32_MAX) + return AVERROR_INVALIDDATA; + + avio_write(s->pb, pkt->data, pkt->size); + return 0; +} + +static int argo_asf_write_trailer(AVFormatContext *s) +{ + int64_t ret; + + if ((ret = avio_seek(s->pb, ASF_FILE_HEADER_SIZE, SEEK_SET) < 0)) + return ret; + + avio_wl32(s->pb, (uint32_t)s->streams[0]->nb_frames); + return 0; +} + +static const AVOption argo_asf_options[] = { + { + .name = "version_major", + .help = "override file major version", + .offset = offsetof(ArgoASFMuxContext, version_major), + .type = AV_OPT_TYPE_INT, + .default_val = {.i64 = 2}, + .min = 0, + .max = UINT16_MAX, + .flags = AV_OPT_FLAG_ENCODING_PARAM + }, + { + .name = "version_minor", + .help = "override file minor version", + .offset = offsetof(ArgoASFMuxContext, version_minor), + .type = AV_OPT_TYPE_INT, + .default_val = {.i64 = 1}, + .min = 0, + .max = UINT16_MAX, + .flags = AV_OPT_FLAG_ENCODING_PARAM + }, + { + .name = "name", + .help = "embedded file name (max 8 characters)", + .offset = offsetof(ArgoASFMuxContext, name), + .type = AV_OPT_TYPE_STRING, + .default_val = {.str = NULL}, + .flags = AV_OPT_FLAG_ENCODING_PARAM + }, + { NULL } +}; + +static const AVClass argo_asf_muxer_class = { + .class_name = "argo_asf_muxer", + .item_name = av_default_item_name, + .option = argo_asf_options, + .version = LIBAVUTIL_VERSION_INT +}; + +AVOutputFormat ff_argo_asf_muxer = { + .name = "argo_asf", + .long_name = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"), + /* + * NB: Can't do this as it conflicts with the actual ASF format. + * .extensions = "asf", + */ + .audio_codec = AV_CODEC_ID_ADPCM_ARGO, + .video_codec = AV_CODEC_ID_NONE, + .init = argo_asf_write_init, + .write_header = argo_asf_write_header, + .write_packet = argo_asf_write_packet, + .write_trailer = argo_asf_write_trailer, + .priv_class = &argo_asf_muxer_class, + .priv_data_size = sizeof(ArgoASFMuxContext) +}; +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/asfdec_f.c b/chromium/third_party/ffmpeg/libavformat/asfdec_f.c index f0cb353587d..e9ddca7151d 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfdec_f.c +++ b/chromium/third_party/ffmpeg/libavformat/asfdec_f.c @@ -308,8 +308,8 @@ static void get_id3_tag(AVFormatContext *s, int len) 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_parse_chapters(s, &id3v2_extra_meta); + ff_id3v2_parse_apic(s, id3v2_extra_meta); + ff_id3v2_parse_chapters(s, id3v2_extra_meta); } ff_id3v2_free_extra_meta(&id3v2_extra_meta); } diff --git a/chromium/third_party/ffmpeg/libavformat/asfdec_o.c b/chromium/third_party/ffmpeg/libavformat/asfdec_o.c index 7891b234455..1b10e47907a 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfdec_o.c +++ b/chromium/third_party/ffmpeg/libavformat/asfdec_o.c @@ -461,8 +461,8 @@ static void get_id3_tag(AVFormatContext *s, int len) 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_parse_chapters(s, &id3v2_extra_meta); + ff_id3v2_parse_apic(s, id3v2_extra_meta); + ff_id3v2_parse_chapters(s, id3v2_extra_meta); } ff_id3v2_free_extra_meta(&id3v2_extra_meta); } diff --git a/chromium/third_party/ffmpeg/libavformat/asfenc.c b/chromium/third_party/ffmpeg/libavformat/asfenc.c index 73afb13200b..8b24264c947 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/asfenc.c @@ -682,7 +682,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avio_wl16(pb, 40 + par->extradata_size); /* size */ /* BITMAPINFOHEADER header */ - ff_put_bmp_header(pb, par, 1, 0); + ff_put_bmp_header(pb, par, 1, 0, 0); } end_header(pb, hpos); } diff --git a/chromium/third_party/ffmpeg/libavformat/assdec.c b/chromium/third_party/ffmpeg/libavformat/assdec.c index f66b2966732..8fb9e8e501b 100644 --- a/chromium/third_party/ffmpeg/libavformat/assdec.c +++ b/chromium/third_party/ffmpeg/libavformat/assdec.c @@ -160,6 +160,8 @@ static int ass_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &ass->q); end: + if (res < 0) + ass_read_close(s); av_bprint_finalize(&header, NULL); av_bprint_finalize(&line, NULL); av_bprint_finalize(&rline, NULL); diff --git a/chromium/third_party/ffmpeg/libavformat/async.c b/chromium/third_party/ffmpeg/libavformat/async.c index 4e295b5e10f..a0bdfa2ee3a 100644 --- a/chromium/third_party/ffmpeg/libavformat/async.c +++ b/chromium/third_party/ffmpeg/libavformat/async.c @@ -293,7 +293,7 @@ cond_wakeup_background_fail: cond_wakeup_main_fail: pthread_mutex_destroy(&c->mutex); mutex_fail: - ffurl_close(c->inner); + ffurl_closep(&c->inner); url_fail: ring_destroy(&c->ring); fifo_fail: @@ -317,7 +317,7 @@ static int async_close(URLContext *h) pthread_cond_destroy(&c->cond_wakeup_background); pthread_cond_destroy(&c->cond_wakeup_main); pthread_mutex_destroy(&c->mutex); - ffurl_close(c->inner); + ffurl_closep(&c->inner); ring_destroy(&c->ring); return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/au.c b/chromium/third_party/ffmpeg/libavformat/au.c index 4afee85a948..c09f4da4c96 100644 --- a/chromium/third_party/ffmpeg/libavformat/au.c +++ b/chromium/third_party/ffmpeg/libavformat/au.c @@ -35,8 +35,6 @@ /* if we don't know the size in advance */ #define AU_UNKNOWN_SIZE ((uint32_t)(~0)) -/* the specification requires an annotation field of at least eight bytes */ -#define AU_DEFAULT_HEADER_SIZE (24+8) static const AVCodecTag codec_au_tags[] = { { AV_CODEC_ID_PCM_MULAW, 1 }, @@ -68,20 +66,20 @@ static int au_probe(const AVProbeData *p) static int au_read_annotation(AVFormatContext *s, int size) { - static const char * keys[] = { + static const char keys[][7] = { "title", "artist", "album", "track", "genre", - NULL }; + }; AVIOContext *pb = s->pb; enum { PARSE_KEY, PARSE_VALUE, PARSE_FINISHED } state = PARSE_KEY; char c; AVBPrint bprint; char * key = NULL; char * value = NULL; - int i; + int ret, i; av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); @@ -92,7 +90,9 @@ static int au_read_annotation(AVFormatContext *s, int size) if (c == '\0') { state = PARSE_FINISHED; } else if (c == '=') { - av_bprint_finalize(&bprint, &key); + ret = av_bprint_finalize(&bprint, &key); + if (ret < 0) + return ret; av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); state = PARSE_VALUE; } else { @@ -105,11 +105,11 @@ static int au_read_annotation(AVFormatContext *s, int size) av_log(s, AV_LOG_ERROR, "Memory error while parsing AU metadata.\n"); } else { av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); - for (i = 0; keys[i] != NULL && key != NULL; i++) { + for (i = 0; i < FF_ARRAY_ELEMS(keys); i++) { if (av_strcasecmp(keys[i], key) == 0) { av_dict_set(&(s->metadata), keys[i], value, AV_DICT_DONT_STRDUP_VAL); - av_freep(&key); value = NULL; + break; } } } @@ -143,6 +143,7 @@ static int au_read_header(AVFormatContext *s) int bps, ba = 0; enum AVCodecID codec; AVStream *st; + int ret; tag = avio_rl32(pb); if (tag != MKTAG('.', 's', 'n', 'd')) @@ -161,7 +162,9 @@ static int au_read_header(AVFormatContext *s) if (size > 24) { /* parse annotation field to get metadata */ - au_read_annotation(s, size - 24); + ret = au_read_annotation(s, size - 24); + if (ret < 0) + return ret; } codec = ff_codec_get_id(codec_au_tags, id); @@ -236,36 +239,31 @@ typedef struct AUContext { #include "rawenc.h" -static int au_get_annotations(AVFormatContext *s, char **buffer) +static int au_get_annotations(AVFormatContext *s, AVBPrint *annotations) { - static const char * keys[] = { + static const char keys[][7] = { "Title", "Artist", "Album", "Track", "Genre", - NULL }; - int i; + }; int cnt = 0; AVDictionary *m = s->metadata; AVDictionaryEntry *t = NULL; - AVBPrint bprint; - av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); - - for (i = 0; keys[i] != NULL; i++) { + for (int i = 0; i < FF_ARRAY_ELEMS(keys); i++) { t = av_dict_get(m, keys[i], NULL, 0); if (t != NULL) { if (cnt++) - av_bprint_chars(&bprint, '\n', 1); - av_bprint_append_data(&bprint, keys[i], strlen(keys[i])); - av_bprint_chars(&bprint, '=', 1); - av_bprint_append_data(&bprint, t->value, strlen(t->value)); + av_bprint_chars(annotations, '\n', 1); + av_bprintf(annotations, "%s=%s", keys[i], t->value); } } - /* pad with 0's */ - av_bprint_append_data(&bprint, "\0\0\0\0\0\0\0\0", 8); - return av_bprint_finalize(&bprint, buffer); + /* The specification requires the annotation field to be zero-terminated + * and its length to be a multiple of eight, so pad with 0's */ + av_bprint_chars(annotations, '\0', 8); + return av_bprint_is_complete(annotations) ? 0 : AVERROR(ENOMEM); } static int au_write_header(AVFormatContext *s) @@ -274,9 +272,7 @@ static int au_write_header(AVFormatContext *s) AUContext *au = s->priv_data; AVIOContext *pb = s->pb; AVCodecParameters *par = s->streams[0]->codecpar; - char *annotations = NULL; - - au->header_size = AU_DEFAULT_HEADER_SIZE; + AVBPrint annotations; if (s->nb_streams != 1) { av_log(s, AV_LOG_ERROR, "only one stream is supported\n"); @@ -289,30 +285,24 @@ static int au_write_header(AVFormatContext *s) return AVERROR(EINVAL); } - if (av_dict_count(s->metadata) > 0) { - ret = au_get_annotations(s, &annotations); - if (ret < 0) - return ret; - if (annotations != NULL) { - au->header_size = (24 + strlen(annotations) + 8) & ~7; - if (au->header_size < AU_DEFAULT_HEADER_SIZE) - au->header_size = AU_DEFAULT_HEADER_SIZE; - } - } + av_bprint_init(&annotations, 0, INT_MAX - 24); + ret = au_get_annotations(s, &annotations); + if (ret < 0) + goto fail; + au->header_size = 24 + annotations.len & ~7; + ffio_wfourcc(pb, ".snd"); /* magic number */ avio_wb32(pb, au->header_size); /* header size */ avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */ avio_wb32(pb, par->codec_tag); /* codec ID */ avio_wb32(pb, par->sample_rate); avio_wb32(pb, par->channels); - if (annotations != NULL) { - avio_write(pb, annotations, au->header_size - 24); - av_freep(&annotations); - } else { - avio_wb64(pb, 0); /* annotation field */ - } + avio_write(pb, annotations.str, annotations.len & ~7); - return 0; +fail: + av_bprint_finalize(&annotations, NULL); + + return ret; } static int au_write_trailer(AVFormatContext *s) diff --git a/chromium/third_party/ffmpeg/libavformat/audiointerleave.c b/chromium/third_party/ffmpeg/libavformat/audiointerleave.c deleted file mode 100644 index 36a32882427..00000000000 --- a/chromium/third_party/ffmpeg/libavformat/audiointerleave.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Audio Interleaving functions - * - * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 - */ - -#include "libavutil/fifo.h" -#include "libavutil/mathematics.h" -#include "avformat.h" -#include "audiointerleave.h" -#include "internal.h" - -void ff_audio_interleave_close(AVFormatContext *s) -{ - int i; - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - AudioInterleaveContext *aic = st->priv_data; - - if (aic && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) - av_fifo_freep(&aic->fifo); - } -} - -int ff_audio_interleave_init(AVFormatContext *s, - const int samples_per_frame, - AVRational time_base) -{ - int i; - - if (!time_base.num) { - av_log(s, AV_LOG_ERROR, "timebase not set for audio interleave\n"); - return AVERROR(EINVAL); - } - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - AudioInterleaveContext *aic = st->priv_data; - - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - int max_samples = samples_per_frame ? samples_per_frame : - av_rescale_rnd(st->codecpar->sample_rate, time_base.num, time_base.den, AV_ROUND_UP); - aic->sample_size = (st->codecpar->channels * - av_get_bits_per_sample(st->codecpar->codec_id)) / 8; - if (!aic->sample_size) { - av_log(s, AV_LOG_ERROR, "could not compute sample size\n"); - return AVERROR(EINVAL); - } - aic->samples_per_frame = samples_per_frame; - aic->time_base = time_base; - - if (!(aic->fifo = av_fifo_alloc_array(100, max_samples))) - return AVERROR(ENOMEM); - aic->fifo_size = 100 * max_samples; - } - } - - return 0; -} - -static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, - int stream_index, int flush) -{ - AVStream *st = s->streams[stream_index]; - AudioInterleaveContext *aic = st->priv_data; - int ret; - int nb_samples = aic->samples_per_frame ? aic->samples_per_frame : - (av_rescale_q(aic->n + 1, av_make_q(st->codecpar->sample_rate, 1), av_inv_q(aic->time_base)) - aic->nb_samples); - int frame_size = nb_samples * aic->sample_size; - int size = FFMIN(av_fifo_size(aic->fifo), frame_size); - if (!size || (!flush && size == av_fifo_size(aic->fifo))) - return 0; - - ret = av_new_packet(pkt, frame_size); - if (ret < 0) - return ret; - av_fifo_generic_read(aic->fifo, pkt->data, size, NULL); - - if (size < pkt->size) - memset(pkt->data + size, 0, pkt->size - size); - - pkt->dts = pkt->pts = aic->dts; - pkt->duration = av_rescale_q(nb_samples, st->time_base, aic->time_base); - pkt->stream_index = stream_index; - aic->dts += pkt->duration; - aic->nb_samples += nb_samples; - aic->n++; - - return pkt->size; -} - -int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush, - int (*get_packet)(AVFormatContext *, AVPacket *, AVPacket *, int), - int (*compare_ts)(AVFormatContext *, const AVPacket *, const AVPacket *)) -{ - int i, ret; - - if (pkt) { - AVStream *st = s->streams[pkt->stream_index]; - AudioInterleaveContext *aic = st->priv_data; - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - unsigned new_size = av_fifo_size(aic->fifo) + pkt->size; - if (new_size > aic->fifo_size) { - if (av_fifo_realloc2(aic->fifo, new_size) < 0) - return AVERROR(ENOMEM); - aic->fifo_size = new_size; - } - av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL); - } else { - // rewrite pts and dts to be decoded time line position - pkt->pts = pkt->dts = aic->dts; - aic->dts += pkt->duration; - if ((ret = ff_interleave_add_packet(s, pkt, compare_ts)) < 0) - return ret; - } - pkt = NULL; - } - - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - AVPacket new_pkt; - while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) { - if ((ret = ff_interleave_add_packet(s, &new_pkt, compare_ts)) < 0) - return ret; - } - if (ret < 0) - return ret; - } - } - - return get_packet(s, out, NULL, flush); -} diff --git a/chromium/third_party/ffmpeg/libavformat/audiointerleave.h b/chromium/third_party/ffmpeg/libavformat/audiointerleave.h deleted file mode 100644 index 0933310f4c2..00000000000 --- a/chromium/third_party/ffmpeg/libavformat/audiointerleave.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * audio interleaving prototypes and declarations - * - * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 - */ - -#ifndef AVFORMAT_AUDIOINTERLEAVE_H -#define AVFORMAT_AUDIOINTERLEAVE_H - -#include "libavutil/fifo.h" -#include "avformat.h" - -typedef struct AudioInterleaveContext { - AVFifoBuffer *fifo; - unsigned fifo_size; ///< size of currently allocated FIFO - int64_t n; ///< number of generated packets - int64_t nb_samples; ///< number of generated samples - uint64_t dts; ///< current dts - int sample_size; ///< size of one sample all channels included - int samples_per_frame; ///< samples per frame if fixed, 0 otherwise - AVRational time_base; ///< time base of output audio packets -} AudioInterleaveContext; - -int ff_audio_interleave_init(AVFormatContext *s, const int samples_per_frame, AVRational time_base); -void ff_audio_interleave_close(AVFormatContext *s); - -/** - * Rechunk audio PCM packets per AudioInterleaveContext->samples_per_frame - * and interleave them correctly. - * The first element of AVStream->priv_data must be AudioInterleaveContext - * when using this function. - * - * @param get_packet function will output a packet when streams are correctly interleaved. - * @param compare_ts function will compare AVPackets and decide interleaving order. - */ -int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush, - int (*get_packet)(AVFormatContext *, AVPacket *, AVPacket *, int), - int (*compare_ts)(AVFormatContext *, const AVPacket *, const AVPacket *)); - -#endif /* AVFORMAT_AUDIOINTERLEAVE_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/av1.c b/chromium/third_party/ffmpeg/libavformat/av1.c index 1e7a67d2f2b..0cbffb1fd8b 100644 --- a/chromium/third_party/ffmpeg/libavformat/av1.c +++ b/chromium/third_party/ffmpeg/libavformat/av1.c @@ -363,11 +363,11 @@ int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) { - AVIOContext *seq_pb = NULL, *meta_pb = NULL; + AVIOContext *meta_pb; AV1SequenceParameters seq_params; PutBitContext pbc; - uint8_t header[4]; - uint8_t *seq, *meta; + uint8_t header[4], *meta; + const uint8_t *seq; int64_t obu_size; int start_pos, type, temporal_id, spatial_id; int ret, nb_seq = 0, seq_size, meta_size; @@ -375,12 +375,9 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) if (size <= 0) return AVERROR_INVALIDDATA; - ret = avio_open_dyn_buf(&seq_pb); - if (ret < 0) - return ret; ret = avio_open_dyn_buf(&meta_pb); if (ret < 0) - goto fail; + return ret; while (size > 0) { int len = parse_obu_header(buf, size, &obu_size, &start_pos, @@ -401,7 +398,8 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) if (ret < 0) goto fail; - avio_write(seq_pb, buf, len); + seq = buf; + seq_size = len; break; case AV1_OBU_METADATA: if (!obu_size) { @@ -417,8 +415,7 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) buf += len; } - seq_size = avio_get_dyn_buf(seq_pb, &seq); - if (!seq_size) { + if (!nb_seq) { ret = AVERROR_INVALIDDATA; goto fail; } @@ -447,7 +444,6 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) avio_write(pb, meta, meta_size); fail: - ffio_free_dyn_buf(&seq_pb); ffio_free_dyn_buf(&meta_pb); return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/av1dec.c b/chromium/third_party/ffmpeg/libavformat/av1dec.c index 1be2fac1c10..0693e40ac1b 100644 --- a/chromium/third_party/ffmpeg/libavformat/av1dec.c +++ b/chromium/third_party/ffmpeg/libavformat/av1dec.c @@ -22,12 +22,77 @@ #include "config.h" #include "libavutil/common.h" +#include "libavutil/fifo.h" #include "libavutil/opt.h" #include "libavcodec/av1_parse.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" +//return < 0 if we need more data +static int get_score(int type, int *seq) +{ + switch (type) { + case AV1_OBU_SEQUENCE_HEADER: + *seq = 1; + return -1; + case AV1_OBU_FRAME: + case AV1_OBU_FRAME_HEADER: + return *seq ? AVPROBE_SCORE_EXTENSION + 1 : 0; + case AV1_OBU_METADATA: + case AV1_OBU_PADDING: + return -1; + default: + break; + } + return 0; +} + +static int read_header(AVFormatContext *s, const AVRational *framerate, AVBSFContext **bsf, void *logctx) +{ + const AVBitStreamFilter *filter = av_bsf_get_by_name("av1_frame_merge"); + AVStream *st; + int ret; + + if (!filter) { + av_log(logctx, AV_LOG_ERROR, "av1_frame_merge bitstream filter " + "not found. This is a bug, please report it.\n"); + return AVERROR_BUG; + } + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_AV1; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + + st->internal->avctx->framerate = *framerate; + // taken from rawvideo demuxers + avpriv_set_pts_info(st, 64, 1, 1200000); + + ret = av_bsf_alloc(filter, bsf); + if (ret < 0) + return ret; + + ret = avcodec_parameters_copy((*bsf)->par_in, st->codecpar); + if (ret < 0) { + av_bsf_free(bsf); + return ret; + } + + ret = av_bsf_init(*bsf); + if (ret < 0) + av_bsf_free(bsf); + + return ret; + +} + +#define DEC AV_OPT_FLAG_DECODING_PARAM + +#if CONFIG_AV1_DEMUXER typedef struct AnnexBContext { const AVClass *class; AVBSFContext *bsf; @@ -123,19 +188,9 @@ static int annexb_probe(const AVProbeData *p) return 0; cnt += obu_unit_size; - switch (type) { - case AV1_OBU_SEQUENCE_HEADER: - seq = 1; - break; - case AV1_OBU_FRAME: - case AV1_OBU_FRAME_HEADER: - return seq ? AVPROBE_SCORE_EXTENSION + 1 : 0; - case AV1_OBU_TILE_GROUP: - case AV1_OBU_TEMPORAL_DELIMITER: - return 0; - default: - break; - } + ret = get_score(type, &seq); + if (ret >= 0) + return ret; temporal_unit_size -= obu_unit_size + ret; frame_unit_size -= obu_unit_size + ret; @@ -147,43 +202,7 @@ static int annexb_probe(const AVProbeData *p) static int annexb_read_header(AVFormatContext *s) { AnnexBContext *c = s->priv_data; - const AVBitStreamFilter *filter = av_bsf_get_by_name("av1_frame_merge"); - AVStream *st; - int ret; - - if (!filter) { - av_log(c, AV_LOG_ERROR, "av1_frame_merge bitstream filter " - "not found. This is a bug, please report it.\n"); - return AVERROR_BUG; - } - - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->codecpar->codec_id = AV_CODEC_ID_AV1; - st->need_parsing = AVSTREAM_PARSE_HEADERS; - - st->internal->avctx->framerate = c->framerate; - // taken from rawvideo demuxers - avpriv_set_pts_info(st, 64, 1, 1200000); - - ret = av_bsf_alloc(filter, &c->bsf); - if (ret < 0) - return ret; - - ret = avcodec_parameters_copy(c->bsf->par_in, st->codecpar); - if (ret < 0) { - av_bsf_free(&c->bsf); - return ret; - } - - ret = av_bsf_init(c->bsf); - if (ret < 0) - av_bsf_free(&c->bsf); - - return ret; + return read_header(s, &c->framerate, &c->bsf, c); } static int annexb_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -252,11 +271,11 @@ static int annexb_read_close(AVFormatContext *s) } #define OFFSET(x) offsetof(AnnexBContext, x) -#define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption annexb_options[] = { { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC}, { NULL }, }; +#undef OFFSET static const AVClass annexb_demuxer_class = { .class_name = "AV1 Annex B demuxer", @@ -277,3 +296,205 @@ AVInputFormat ff_av1_demuxer = { .flags = AVFMT_GENERIC_INDEX, .priv_class = &annexb_demuxer_class, }; +#endif + +#if CONFIG_OBU_DEMUXER +typedef struct ObuContext { + const AVClass *class; + AVBSFContext *bsf; + AVRational framerate; + AVFifoBuffer *fifo; +} ObuContext; + +//For low overhead obu, we can't foresee the obu size before we parsed the header. +//So, we can't use parse_obu_header here, since it will check size <= buf_size +//see c27c7b49dc for more details +static int read_obu_with_size(const uint8_t *buf, int buf_size, int64_t *obu_size, int *type) +{ + GetBitContext gb; + int ret, extension_flag, start_pos; + int64_t size; + + ret = init_get_bits8(&gb, buf, FFMIN(buf_size, MAX_OBU_HEADER_SIZE)); + if (ret < 0) + return ret; + + if (get_bits1(&gb) != 0) // obu_forbidden_bit + return AVERROR_INVALIDDATA; + + *type = get_bits(&gb, 4); + extension_flag = get_bits1(&gb); + if (!get_bits1(&gb)) // has_size_flag + return AVERROR_INVALIDDATA; + skip_bits1(&gb); // obu_reserved_1bit + + if (extension_flag) { + get_bits(&gb, 3); // temporal_id + get_bits(&gb, 2); // spatial_id + skip_bits(&gb, 3); // extension_header_reserved_3bits + } + + *obu_size = leb128(&gb); + if (*obu_size > INT_MAX) + return AVERROR_INVALIDDATA; + + if (get_bits_left(&gb) < 0) + return AVERROR_INVALIDDATA; + + start_pos = get_bits_count(&gb) / 8; + + size = *obu_size + start_pos; + if (size > INT_MAX) + return AVERROR_INVALIDDATA; + return size; +} + +static int obu_probe(const AVProbeData *p) +{ + int64_t obu_size; + int seq = 0; + int ret, type, cnt; + + // Check that the first OBU is a Temporal Delimiter. + cnt = read_obu_with_size(p->buf, p->buf_size, &obu_size, &type); + if (cnt < 0 || type != AV1_OBU_TEMPORAL_DELIMITER || obu_size != 0) + return 0; + + while (1) { + ret = read_obu_with_size(p->buf + cnt, p->buf_size - cnt, &obu_size, &type); + if (ret < 0 || obu_size <= 0) + return 0; + cnt += ret; + + ret = get_score(type, &seq); + if (ret >= 0) + return ret; + } + return 0; +} + +static int obu_read_header(AVFormatContext *s) +{ + ObuContext *c = s->priv_data; + c->fifo = av_fifo_alloc(MAX_OBU_HEADER_SIZE); + if (!c->fifo) + return AVERROR(ENOMEM); + return read_header(s, &c->framerate, &c->bsf, c); +} + +static int obu_prefetch(AVFormatContext *s, uint8_t* dest) +{ + ObuContext *c = s->priv_data; + int size = av_fifo_space(c->fifo); + av_fifo_generic_write(c->fifo, s->pb, size, + (int (*)(void*, void*, int))avio_read); + size = av_fifo_size(c->fifo); + if (size > 0) { + av_fifo_generic_peek(c->fifo, dest, size, NULL); + } + return size; +} + +static int obu_read_data(AVFormatContext *s, AVPacket *pkt, int len) +{ + int size, left; + ObuContext *c = s->priv_data; + int ret = av_new_packet(pkt, len); + if (ret < 0) { + av_log(c, AV_LOG_ERROR, "Failed to allocate packet for obu\n"); + return ret; + } + size = FFMIN(av_fifo_size(c->fifo), len); + av_fifo_generic_read(c->fifo, pkt->data, size, NULL); + left = len - size; + if (left > 0) { + ret = avio_read(s->pb, pkt->data + size, left); + if (ret != left) { + av_log(c, AV_LOG_ERROR, "Failed to read %d frome file\n", left); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } + } + return 0; +} + +static int obu_get_packet(AVFormatContext *s, AVPacket *pkt) +{ + ObuContext *c = s->priv_data; + int64_t obu_size; + int ret, type; + uint8_t header[MAX_OBU_HEADER_SIZE]; + + ret = obu_prefetch(s, header); + if (!ret) + return 0; + + ret = read_obu_with_size(header, ret, &obu_size, &type); + if (ret < 0) { + av_log(c, AV_LOG_ERROR, "Failed to read obu\n"); + return ret; + } + return obu_read_data(s, pkt, ret); +} + +static int obu_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + ObuContext *c = s->priv_data; + int ret; + + while (1) { + ret = obu_get_packet(s, pkt); + if (ret < 0) + return ret; + ret = av_bsf_send_packet(c->bsf, pkt); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to send packet to " + "av1_frame_merge filter\n"); + return ret; + } + ret = av_bsf_receive_packet(c->bsf, pkt); + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + av_log(s, AV_LOG_ERROR, "av1_frame_merge filter failed to " + "send output packet\n"); + if (ret != AVERROR(EAGAIN)) + break; + } + + return ret; +} + +static int obu_read_close(AVFormatContext *s) +{ + ObuContext *c = s->priv_data; + + av_fifo_freep(&c->fifo); + av_bsf_free(&c->bsf); + return 0; +} + +#define OFFSET(x) offsetof(ObuContext, x) +static const AVOption obu_options[] = { + { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC}, + { NULL }, +}; +#undef OFFSET + +static const AVClass obu_demuxer_class = { + .class_name = "AV1 low overhead OBU demuxer", + .item_name = av_default_item_name, + .option = obu_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_obu_demuxer = { + .name = "obu", + .long_name = NULL_IF_CONFIG_SMALL("AV1 low overhead OBU"), + .priv_data_size = sizeof(ObuContext), + .read_probe = obu_probe, + .read_header = obu_read_header, + .read_packet = obu_read_packet, + .read_close = obu_read_close, + .extensions = "obu", + .flags = AVFMT_GENERIC_INDEX, + .priv_class = &obu_demuxer_class, +}; +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/avc.c b/chromium/third_party/ffmpeg/libavformat/avc.c index cd15ac3cdb1..b5e29213881 100644 --- a/chromium/third_party/ffmpeg/libavformat/avc.c +++ b/chromium/third_party/ffmpeg/libavformat/avc.c @@ -27,7 +27,7 @@ #include "avc.h" #include "avio_internal.h" -static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p, const uint8_t *end) +static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end) { const uint8_t *a = p + 4 - ((intptr_t)p & 3); @@ -65,7 +65,7 @@ static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p, const uin } const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){ - const uint8_t *out= ff_avc_find_startcode_internal(p, end); + const uint8_t *out = avc_find_startcode_internal(p, end); if(p<out && out<end && !out[-1]) out--; return out; } @@ -196,18 +196,17 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) avio_write(pb, pps, pps_size); if (sps[3] != 66 && sps[3] != 77 && sps[3] != 88) { - H264SequenceParameterSet *seq = ff_avc_decode_sps(sps + 3, sps_size - 3); - if (!seq) { - ret = AVERROR(ENOMEM); + H264SPS seq; + ret = ff_avc_decode_sps(&seq, sps + 3, sps_size - 3); + if (ret < 0) goto fail; - } - avio_w8(pb, 0xfc | seq->chroma_format_idc); /* 6 bits reserved (111111) + chroma_format_idc */ - avio_w8(pb, 0xf8 | (seq->bit_depth_luma - 8)); /* 5 bits reserved (11111) + bit_depth_luma_minus8 */ - avio_w8(pb, 0xf8 | (seq->bit_depth_chroma - 8)); /* 5 bits reserved (11111) + bit_depth_chroma_minus8 */ + + avio_w8(pb, 0xfc | seq.chroma_format_idc); /* 6 bits reserved (111111) + chroma_format_idc */ + avio_w8(pb, 0xf8 | (seq.bit_depth_luma - 8)); /* 5 bits reserved (11111) + bit_depth_luma_minus8 */ + avio_w8(pb, 0xf8 | (seq.bit_depth_chroma - 8)); /* 5 bits reserved (11111) + bit_depth_chroma_minus8 */ avio_w8(pb, nb_sps_ext); /* number of sps ext */ if (nb_sps_ext) avio_write(pb, sps_ext, sps_ext_size); - av_free(seq); } fail: @@ -332,27 +331,24 @@ static inline int get_se_golomb(GetBitContext *gb) { return ((v >> 1) ^ sign) - sign; } -H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *buf, int buf_size) +int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size) { int i, j, ret, rbsp_size, aspect_ratio_idc, pic_order_cnt_type; int num_ref_frames_in_pic_order_cnt_cycle; int delta_scale, lastScale = 8, nextScale = 8; int sizeOfScalingList; - H264SequenceParameterSet *sps = NULL; GetBitContext gb; uint8_t *rbsp_buf; rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0); if (!rbsp_buf) - return NULL; + return AVERROR(ENOMEM); ret = init_get_bits8(&gb, rbsp_buf, rbsp_size); if (ret < 0) goto end; - sps = av_mallocz(sizeof(*sps)); - if (!sps) - goto end; + memset(sps, 0, sizeof(*sps)); sps->profile_idc = get_bits(&gb, 8); sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag @@ -448,7 +444,8 @@ H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *buf, int buf_size) sps->sar.den = 1; } + ret = 0; end: av_free(rbsp_buf); - return sps; + return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/avc.h b/chromium/third_party/ffmpeg/libavformat/avc.h index 5286d19d890..9792b77913d 100644 --- a/chromium/third_party/ffmpeg/libavformat/avc.h +++ b/chromium/third_party/ffmpeg/libavformat/avc.h @@ -46,8 +46,8 @@ typedef struct { uint8_t bit_depth_chroma; uint8_t frame_mbs_only_flag; AVRational sar; -} H264SequenceParameterSet; +} H264SPS; -H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *src, int src_len); +int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size); #endif /* AVFORMAT_AVC_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/avformat.h b/chromium/third_party/ffmpeg/libavformat/avformat.h index 39b99b44818..e91e7f1d33b 100644 --- a/chromium/third_party/ffmpeg/libavformat/avformat.h +++ b/chromium/third_party/ffmpeg/libavformat/avformat.h @@ -1120,7 +1120,6 @@ typedef struct AVStream { * -1 -> probing finished * 0 -> no probing requested * rest -> perform probing with request_probe being the minimum score to accept. - * NOT PART OF PUBLIC API */ int request_probe; /** @@ -1166,7 +1165,6 @@ typedef struct AVStream { /** * Timestamp offset added to timestamps before muxing - * NOT PART OF PUBLIC API */ int64_t mux_ts_offset; @@ -2191,7 +2189,8 @@ uint8_t *av_stream_new_side_data(AVStream *stream, * * @param stream stream * @param type desired side information type - * @param size pointer for side information size to store (optional) + * @param size If supplied, *size will be set to the size of the side data + * or to zero if the desired side data is not present. * @return pointer to data if present or NULL otherwise */ uint8_t *av_stream_get_side_data(const AVStream *stream, diff --git a/chromium/third_party/ffmpeg/libavformat/avienc.c b/chromium/third_party/ffmpeg/libavformat/avienc.c index 297d5b8964a..1b2cb529b90 100644 --- a/chromium/third_party/ffmpeg/libavformat/avienc.c +++ b/chromium/third_party/ffmpeg/libavformat/avienc.c @@ -72,6 +72,7 @@ typedef struct AVIContext { int reserve_index_space; int master_index_max_size; int write_channel_mask; + int flipped_raw_rgb; } AVIContext; typedef struct AVIStream { @@ -449,7 +450,7 @@ static int avi_write_header(AVFormatContext *s) && par->bits_per_coded_sample == 15) par->bits_per_coded_sample = 16; avist->pal_offset = avio_tell(pb) + 40; - ff_put_bmp_header(pb, par, 0, 0); + ff_put_bmp_header(pb, par, 0, 0, avi->flipped_raw_rgb); pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi, par->bits_per_coded_sample); if ( !par->codec_tag @@ -993,6 +994,7 @@ static void avi_deinit(AVFormatContext *s) static const AVOption options[] = { { "reserve_index_space", "reserve space (in bytes) at the beginning of the file for each stream index", OFFSET(reserve_index_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, ENC }, { "write_channel_mask", "write channel mask into wave format header", OFFSET(write_channel_mask), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC }, + { "flipped_raw_rgb", "Raw RGB bitmaps are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/avio.c b/chromium/third_party/ffmpeg/libavformat/avio.c index 237966c3030..3886ed7a90f 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.c +++ b/chromium/third_party/ffmpeg/libavformat/avio.c @@ -67,7 +67,10 @@ const AVClass ffurl_context_class = { .option = options, .version = LIBAVUTIL_VERSION_INT, .child_next = urlcontext_child_next, +#if FF_API_CHILD_CLASS_NEXT .child_class_next = ff_urlcontext_child_class_next, +#endif + .child_class_iterate = ff_urlcontext_child_class_iterate, }; /*@}*/ diff --git a/chromium/third_party/ffmpeg/libavformat/aviobuf.c b/chromium/third_party/ffmpeg/libavformat/aviobuf.c index 85c01c938af..a77517d7121 100644 --- a/chromium/third_party/ffmpeg/libavformat/aviobuf.c +++ b/chromium/third_party/ffmpeg/libavformat/aviobuf.c @@ -48,10 +48,19 @@ static void *ff_avio_child_next(void *obj, void *prev) return prev ? NULL : s->opaque; } +#if FF_API_CHILD_CLASS_NEXT static const AVClass *ff_avio_child_class_next(const AVClass *prev) { return prev ? NULL : &ffurl_context_class; } +#endif + +static const AVClass *child_class_iterate(void **iter) +{ + const AVClass *c = *iter ? NULL : &ffurl_context_class; + *iter = (void*)(uintptr_t)c; + return c; +} #define OFFSET(x) offsetof(AVIOContext,x) #define E AV_OPT_FLAG_ENCODING_PARAM @@ -67,7 +76,10 @@ const AVClass ff_avio_class = { .version = LIBAVUTIL_VERSION_INT, .option = ff_avio_options, .child_next = ff_avio_child_next, +#if FF_API_CHILD_CLASS_NEXT .child_class_next = ff_avio_child_class_next, +#endif + .child_class_iterate = child_class_iterate, }; static void fill_buffer(AVIOContext *s); @@ -432,26 +444,6 @@ PUT_STR16(be, 1) #undef PUT_STR16 -int ff_get_v_length(uint64_t val) -{ - int i = 1; - - while (val >>= 7) - i++; - - return i; -} - -void ff_put_v(AVIOContext *bc, uint64_t val) -{ - int i = ff_get_v_length(val); - - while (--i > 0) - avio_w8(bc, 128 | (uint8_t)(val >> (7*i))); - - avio_w8(bc, val & 127); -} - void avio_wl64(AVIOContext *s, uint64_t val) { avio_wl32(s, (uint32_t)(val & 0xffffffff)); @@ -716,7 +708,7 @@ int avio_read_partial(AVIOContext *s, unsigned char *buf, int size) int len; if (size < 0) - return -1; + return AVERROR(EINVAL); if (s->read_packet && s->write_flag) { len = read_packet_wrapper(s, buf, size); @@ -1292,22 +1284,21 @@ typedef struct DynBuffer { static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) { DynBuffer *d = opaque; - unsigned new_size, new_allocated_size; + unsigned new_size; /* reallocate buffer if needed */ - new_size = d->pos + buf_size; - new_allocated_size = d->allocated_size; - if (new_size < d->pos || new_size > INT_MAX/2) - return -1; - while (new_size > new_allocated_size) { - if (!new_allocated_size) - new_allocated_size = new_size; - else + new_size = (unsigned)d->pos + buf_size; + if (new_size < d->pos || new_size > INT_MAX) + return AVERROR(ERANGE); + if (new_size > d->allocated_size) { + unsigned new_allocated_size = d->allocated_size ? d->allocated_size + : new_size; + int err; + while (new_size > new_allocated_size) new_allocated_size += new_allocated_size / 2 + 1; - } - if (new_allocated_size > d->allocated_size) { - int err; + new_allocated_size = FFMIN(new_allocated_size, INT_MAX); + if ((err = av_reallocp(&d->buffer, new_allocated_size)) < 0) { d->allocated_size = 0; d->size = 0; @@ -1345,8 +1336,10 @@ static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence) offset += d->pos; else if (whence == SEEK_END) offset += d->size; - if (offset < 0 || offset > 0x7fffffffLL) - return -1; + if (offset < 0) + return AVERROR(EINVAL); + if (offset > INT_MAX) + return AVERROR(ERANGE); d->pos = offset; return 0; } @@ -1357,7 +1350,7 @@ static int url_open_dyn_buf_internal(AVIOContext **s, int max_packet_size) unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024; if (sizeof(DynBuffer) + io_buffer_size < io_buffer_size) - return -1; + return AVERROR(ERANGE); d = av_mallocz(sizeof(DynBuffer) + io_buffer_size); if (!d) return AVERROR(ENOMEM); @@ -1381,7 +1374,7 @@ int avio_open_dyn_buf(AVIOContext **s) int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) { if (max_packet_size <= 0) - return -1; + return AVERROR(EINVAL); return url_open_dyn_buf_internal(s, max_packet_size); } @@ -1389,13 +1382,13 @@ int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { DynBuffer *d; - if (!s || s->error) { + if (!s) { *pbuffer = NULL; return 0; } d = s->opaque; - if (!d->size) { + if (!s->error && !d->size) { *pbuffer = d->io_buffer; return FFMAX(s->buf_ptr, s->buf_ptr_max) - s->buffer; } diff --git a/chromium/third_party/ffmpeg/libavformat/cache.c b/chromium/third_party/ffmpeg/libavformat/cache.c index 09e5d5f832d..1e19dafc6a5 100644 --- a/chromium/third_party/ffmpeg/libavformat/cache.c +++ b/chromium/third_party/ffmpeg/libavformat/cache.c @@ -310,7 +310,7 @@ static int cache_close(URLContext *h) av_log(h, AV_LOG_ERROR, "Could not delete %s.\n", c->filename); av_freep(&c->filename); } - ffurl_close(c->inner); + ffurl_closep(&c->inner); av_tree_enumerate(c->root, NULL, NULL, enu_free); av_tree_destroy(c->root); diff --git a/chromium/third_party/ffmpeg/libavformat/concat.c b/chromium/third_party/ffmpeg/libavformat/concat.c index ea3bc1dfde8..418405dd50b 100644 --- a/chromium/third_party/ffmpeg/libavformat/concat.c +++ b/chromium/third_party/ffmpeg/libavformat/concat.c @@ -49,7 +49,7 @@ static av_cold int concat_close(URLContext *h) struct concat_nodes *nodes = data->nodes; for (i = 0; i != data->length; i++) - err |= ffurl_close(nodes[i].uc); + err |= ffurl_closep(&nodes[i].uc); av_freep(&data->nodes); @@ -75,7 +75,6 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) if (uri[i] == *AV_CAT_SEPARATOR) { /* integer overflow */ if (++len == UINT_MAX / sizeof(*nodes)) { - av_freep(&h->priv_data); return AVERROR(ENAMETOOLONG); } } diff --git a/chromium/third_party/ffmpeg/libavformat/concatdec.c b/chromium/third_party/ffmpeg/libavformat/concatdec.c index 2173911ce45..4b56b61404f 100644 --- a/chromium/third_party/ffmpeg/libavformat/concatdec.c +++ b/chromium/third_party/ffmpeg/libavformat/concatdec.c @@ -626,17 +626,16 @@ 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)); 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))) { + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, + packed_metadata, metadata_len); + if (ret < 0) { av_freep(&packed_metadata); - return AVERROR(ENOMEM); + return ret; } - memcpy(metadata, packed_metadata, metadata_len); - av_freep(&packed_metadata); } if (cat->cur_file->duration == AV_NOPTS_VALUE && st->cur_dts != AV_NOPTS_VALUE) { @@ -647,7 +646,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) } pkt->stream_index = cs->out_stream_index; - return ret; + return 0; } static void rescale_interval(AVRational tb_in, AVRational tb_out, diff --git a/chromium/third_party/ffmpeg/libavformat/crypto.c b/chromium/third_party/ffmpeg/libavformat/crypto.c index 9a48f2e6f51..1d4514e0f27 100644 --- a/chromium/third_party/ffmpeg/libavformat/crypto.c +++ b/chromium/third_party/ffmpeg/libavformat/crypto.c @@ -252,21 +252,17 @@ static int64_t crypto_seek(URLContext *h, int64_t pos, int whence) case SEEK_CUR: pos = pos + c->position; break; - case SEEK_END: { - int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE ); + case SEEK_END: + newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE ); if (newpos < 0) { av_log(h, AV_LOG_ERROR, "Crypto: seek_end - can't get file size (pos=%lld)\r\n", (long long int)pos); return newpos; } pos = newpos - pos; - } - break; - case AVSEEK_SIZE: { - int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE ); - return newpos; - } break; + case AVSEEK_SIZE: + return ffurl_seek( c->hd, pos, AVSEEK_SIZE ); default: av_log(h, AV_LOG_ERROR, "Crypto: no support for seek where 'whence' is %d\r\n", whence); @@ -385,8 +381,7 @@ static int crypto_close(URLContext *h) ret = ffurl_write(c->hd, out_buf, BLOCKSIZE); } - if (c->hd) - ffurl_close(c->hd); + ffurl_closep(&c->hd); av_freep(&c->aes_decrypt); av_freep(&c->aes_encrypt); av_freep(&c->write_buf); diff --git a/chromium/third_party/ffmpeg/libavformat/dashdec.c b/chromium/third_party/ffmpeg/libavformat/dashdec.c index 5ba7feb245e..c5a5ff607bf 100644 --- a/chromium/third_party/ffmpeg/libavformat/dashdec.c +++ b/chromium/third_party/ffmpeg/libavformat/dashdec.c @@ -29,6 +29,8 @@ #include "dash.h" #define INITIAL_BUFFER_SIZE 32768 +#define MAX_MANIFEST_SIZE 50 * 1024 +#define DEFAULT_MANIFEST_SIZE 8 * 1024 struct fragment { int64_t url_offset; @@ -590,7 +592,7 @@ static struct fragment * get_Fragment(char *range) char *str_end_offset; char *str_offset = av_strtok(range, "-", &str_end_offset); seg->url_offset = strtoll(str_offset, NULL, 10); - seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset; + seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset + 1; } return seg; @@ -1220,7 +1222,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) int close_in = 0; uint8_t *new_url = NULL; int64_t filesize = 0; - char *buffer = NULL; + AVBPrint buf; AVDictionary *opts = NULL; xmlDoc *doc = NULL; xmlNodePtr root_element = NULL; @@ -1254,24 +1256,23 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) } filesize = avio_size(in); - if (filesize <= 0) { - filesize = 8 * 1024; + if (filesize > MAX_MANIFEST_SIZE) { + av_log(s, AV_LOG_ERROR, "Manifest too large: %"PRId64"\n", filesize); + return AVERROR_INVALIDDATA; } - buffer = av_mallocz(filesize); - if (!buffer) { - av_free(c->base_url); - return AVERROR(ENOMEM); - } + av_bprint_init(&buf, (filesize > 0) ? filesize + 1 : DEFAULT_MANIFEST_SIZE, AV_BPRINT_SIZE_UNLIMITED); - filesize = avio_read(in, buffer, filesize); - if (filesize <= 0) { - av_log(s, AV_LOG_ERROR, "Unable to read to offset '%s'\n", url); - ret = AVERROR_INVALIDDATA; + if ((ret = avio_read_to_bprint(in, &buf, MAX_MANIFEST_SIZE)) < 0 || + !avio_feof(in) || + (filesize = buf.len) == 0) { + av_log(s, AV_LOG_ERROR, "Unable to read to manifest '%s'\n", url); + if (ret == 0) + ret = AVERROR_INVALIDDATA; } else { LIBXML_TEST_VERSION - doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0); + doc = xmlReadMemory(buf.str, filesize, c->base_url, NULL, 0); root_element = xmlDocGetRootElement(doc); node = root_element; @@ -1394,7 +1395,7 @@ cleanup: } av_free(new_url); - av_free(buffer); + av_bprint_finalize(&buf, NULL); if (close_in) { avio_close(in); } @@ -1942,6 +1943,7 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO; pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4; pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE; + pls->ctx->interrupt_callback = s->interrupt_callback; ret = av_probe_input_buffer(&pls->pb, &in_fmt, "", NULL, 0, 0); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Error when loading first fragment, playlist %d\n", (int)pls->rep_idx); @@ -2000,6 +2002,20 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p st->id = i; avcodec_parameters_copy(st->codecpar, ist->codecpar); avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); + + // copy disposition + st->disposition = ist->disposition; + + // copy side data + for (int i = 0; i < ist->nb_side_data; i++) { + const AVPacketSideData *sd_src = &ist->side_data[i]; + uint8_t *dst_data; + + dst_data = av_stream_new_side_data(st, sd_src->type, sd_src->size); + if (!dst_data) + return AVERROR(ENOMEM); + memcpy(dst_data, sd_src->data, sd_src->size); + } } return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/dashenc.c b/chromium/third_party/ffmpeg/libavformat/dashenc.c index 9f837857925..dc3306a56a2 100644 --- a/chromium/third_party/ffmpeg/libavformat/dashenc.c +++ b/chromium/third_party/ffmpeg/libavformat/dashenc.c @@ -115,6 +115,7 @@ typedef struct OutputStream { int64_t last_dts, last_pts; int last_flags; int bit_rate; + int first_segment_bit_rate; SegmentType segment_type; /* segment type selected for this particular stream */ const char *format_name; const char *extension_name; @@ -171,6 +172,7 @@ typedef struct DASHContext { const char *user_agent; AVDictionary *http_opts; int hls_playlist; + const char *hls_master_name; int http_persistent; int master_playlist_created; AVIOContext *mpd_out; @@ -196,6 +198,7 @@ typedef struct DASHContext { int target_latency_refid; AVRational min_playback_rate; AVRational max_playback_rate; + int64_t update_period; } DASHContext; static struct codec_string { @@ -839,8 +842,12 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind continue; if (os->bit_rate > 0) - snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", - os->bit_rate); + snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", os->bit_rate); + else if (final) { + int average_bit_rate = os->pos * 8 * AV_TIME_BASE / c->total_duration; + snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", average_bit_rate); + } else if (os->first_segment_bit_rate > 0) + snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", os->first_segment_bit_rate); if (as->media_type == AVMEDIA_TYPE_VIDEO) { avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"", @@ -1178,6 +1185,8 @@ static int write_manifest(AVFormatContext *s, int final) char now_str[100]; if (c->use_template && !c->use_timeline) update_period = 500; + if (c->update_period) + update_period = c->update_period; avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period); if (!c->ldash) avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE); @@ -1261,9 +1270,9 @@ static int write_manifest(AVFormatContext *s, int final) return 0; if (*c->dirname) - snprintf(filename_hls, sizeof(filename_hls), "%smaster.m3u8", c->dirname); + snprintf(filename_hls, sizeof(filename_hls), "%s%s", c->dirname, c->hls_master_name); else - snprintf(filename_hls, sizeof(filename_hls), "master.m3u8"); + snprintf(filename_hls, sizeof(filename_hls), "%s", c->hls_master_name); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls); @@ -1304,7 +1313,13 @@ static int write_manifest(AVFormatContext *s, int final) OutputStream *os = &c->streams[i]; char *agroup = NULL; char *codec_str_ptr = NULL; - int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead; + int stream_bitrate = os->muxer_overhead; + if (os->bit_rate > 0) + stream_bitrate += os->bit_rate; + else if (final) + stream_bitrate += os->pos * 8 * AV_TIME_BASE / c->total_duration; + else if (os->first_segment_bit_rate > 0) + stream_bitrate += os->first_segment_bit_rate; if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) continue; if (os->segment_type != SEGMENT_TYPE_MP4) @@ -1731,7 +1746,7 @@ static int add_segment(OutputStream *os, const char *file, Segment *seg; if (os->nb_segments >= os->segments_size) { os->segments_size = (os->segments_size + 1) * 2; - if ((err = av_reallocp(&os->segments, sizeof(*os->segments) * + if ((err = av_reallocp_array(&os->segments, sizeof(*os->segments), os->segments_size)) < 0) { os->segments_size = 0; os->nb_segments = 0; @@ -1850,28 +1865,20 @@ static void dashenc_delete_file(AVFormatContext *s, char *filename) { static int dashenc_delete_segment_file(AVFormatContext *s, const char* file) { DASHContext *c = s->priv_data; - size_t dirname_len, file_len; - char filename[1024]; - - dirname_len = strlen(c->dirname); - if (dirname_len >= sizeof(filename)) { - av_log(s, AV_LOG_WARNING, "Cannot delete segments as the directory path is too long: %"PRIu64" characters: %s\n", - (uint64_t)dirname_len, c->dirname); - return AVERROR(ENAMETOOLONG); - } + AVBPrint buf; - memcpy(filename, c->dirname, dirname_len); + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); - file_len = strlen(file); - if ((dirname_len + file_len) >= sizeof(filename)) { - av_log(s, AV_LOG_WARNING, "Cannot delete segments as the path is too long: %"PRIu64" characters: %s%s\n", - (uint64_t)(dirname_len + file_len), c->dirname, file); - return AVERROR(ENAMETOOLONG); + av_bprintf(&buf, "%s%s", c->dirname, file); + if (!av_bprint_is_complete(&buf)) { + av_bprint_finalize(&buf, NULL); + av_log(s, AV_LOG_WARNING, "Out of memory for filename\n"); + return AVERROR(ENOMEM); } - memcpy(filename + dirname_len, file, file_len + 1); // include the terminating zero - dashenc_delete_file(s, filename); + dashenc_delete_file(s, buf.str); + av_bprint_finalize(&buf, NULL); return 0; } @@ -1916,6 +1923,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) OutputStream *os = &c->streams[i]; AVStream *st = s->streams[i]; int range_length, index_length = 0; + int64_t duration; if (!os->packets_written) continue; @@ -1955,25 +1963,17 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } } - os->last_duration = FFMAX(os->last_duration, av_rescale_q(os->max_pts - os->start_pts, - st->time_base, - AV_TIME_BASE_Q)); + duration = av_rescale_q(os->max_pts - os->start_pts, st->time_base, AV_TIME_BASE_Q); + os->last_duration = FFMAX(os->last_duration, duration); if (!os->muxer_overhead && os->max_pts > os->start_pts) os->muxer_overhead = ((int64_t) (range_length - os->total_pkt_size) * - 8 * AV_TIME_BASE) / - av_rescale_q(os->max_pts - os->start_pts, - st->time_base, AV_TIME_BASE_Q); + 8 * AV_TIME_BASE) / duration; os->total_pkt_size = 0; os->total_pkt_duration = 0; - if (!os->bit_rate) { - // calculate average bitrate of first segment - int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts, - st->time_base, - AV_TIME_BASE_Q); - if (bitrate >= 0) - os->bit_rate = bitrate; + if (!os->bit_rate && !os->first_segment_bit_rate) { + os->first_segment_bit_rate = (int64_t) range_length * 8 * AV_TIME_BASE / duration; } add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index); av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); @@ -2149,22 +2149,22 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) av_compare_ts(elapsed_duration, st->time_base, seg_end_duration, AV_TIME_BASE_Q) >= 0) { if (!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - c->last_duration = av_rescale_q(pkt->pts - os->start_pts, - st->time_base, - AV_TIME_BASE_Q); - c->total_duration = av_rescale_q(pkt->pts - os->first_pts, - st->time_base, - AV_TIME_BASE_Q); - - if ((!c->use_timeline || !c->use_template) && os->last_duration) { - if (c->last_duration < os->last_duration*9/10 || - c->last_duration > os->last_duration*11/10) { - av_log(s, AV_LOG_WARNING, - "Segment durations differ too much, enable use_timeline " - "and use_template, or keep a stricter keyframe interval\n"); + c->last_duration = av_rescale_q(pkt->pts - os->start_pts, + st->time_base, + AV_TIME_BASE_Q); + c->total_duration = av_rescale_q(pkt->pts - os->first_pts, + st->time_base, + AV_TIME_BASE_Q); + + if ((!c->use_timeline || !c->use_template) && os->last_duration) { + if (c->last_duration < os->last_duration*9/10 || + c->last_duration > os->last_duration*11/10) { + av_log(s, AV_LOG_WARNING, + "Segment durations differ too much, enable use_timeline " + "and use_template, or keep a stricter keyframe interval\n"); + } } } - } if (c->write_prft && os->producer_reference_time.wallclock && !os->producer_reference_time_str[0]) format_date(os->producer_reference_time_str, @@ -2304,7 +2304,7 @@ static int dash_write_trailer(AVFormatContext *s) if (c->hls_playlist && c->master_playlist_created) { char filename[1024]; - snprintf(filename, sizeof(filename), "%smaster.m3u8", c->dirname); + snprintf(filename, sizeof(filename), "%s%s", c->dirname, c->hls_master_name); dashenc_delete_file(s, filename); } } @@ -2361,6 +2361,7 @@ static const AVOption options[] = { { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "hls_master_name", "HLS master playlist name", OFFSET(hls_master_name), AV_OPT_TYPE_STRING, {.str = "master.m3u8"}, 0, 0, E }, { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, @@ -2382,6 +2383,7 @@ static const AVOption options[] = { { "target_latency", "Set desired target latency for Low-latency dash", OFFSET(target_latency), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E }, { "min_playback_rate", "Set desired minimum playback rate", OFFSET(min_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, { "max_playback_rate", "Set desired maximum playback rate", OFFSET(max_playback_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 }, 0.5, 1.5, E }, + { "update_period", "Set the mpd update interval", OFFSET(update_period), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E}, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/daudenc.c b/chromium/third_party/ffmpeg/libavformat/daudenc.c index 15a5afdfc96..b489659a80b 100644 --- a/chromium/third_party/ffmpeg/libavformat/daudenc.c +++ b/chromium/third_party/ffmpeg/libavformat/daudenc.c @@ -21,11 +21,11 @@ #include "avformat.h" -static int daud_write_header(struct AVFormatContext *s) +static int daud_init(struct AVFormatContext *s) { AVCodecParameters *par = s->streams[0]->codecpar; if (par->channels!=6 || par->sample_rate!=96000) - return -1; + return AVERROR(EINVAL); return 0; } @@ -34,7 +34,7 @@ static int daud_write_packet(struct AVFormatContext *s, AVPacket *pkt) if (pkt->size > 65535) { av_log(s, AV_LOG_ERROR, "Packet size too large for s302m. (%d > 65535)\n", pkt->size); - return -1; + return AVERROR_INVALIDDATA; } avio_wb16(s->pb, pkt->size); avio_wb16(s->pb, 0x8010); // unknown @@ -48,7 +48,7 @@ AVOutputFormat ff_daud_muxer = { .extensions = "302", .audio_codec = AV_CODEC_ID_PCM_S24DAUD, .video_codec = AV_CODEC_ID_NONE, - .write_header = daud_write_header, + .init = daud_init, .write_packet = daud_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; diff --git a/chromium/third_party/ffmpeg/libavformat/dsfdec.c b/chromium/third_party/ffmpeg/libavformat/dsfdec.c index 52cddab2c8b..c9740cf28f6 100644 --- a/chromium/third_party/ffmpeg/libavformat/dsfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/dsfdec.c @@ -56,8 +56,8 @@ static void read_id3(AVFormatContext *s, uint64_t id3pos) ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); if (id3v2_extra_meta) { - ff_id3v2_parse_apic(s, &id3v2_extra_meta); - ff_id3v2_parse_chapters(s, &id3v2_extra_meta); + ff_id3v2_parse_apic(s, id3v2_extra_meta); + ff_id3v2_parse_chapters(s, id3v2_extra_meta); } ff_id3v2_free_extra_meta(&id3v2_extra_meta); } diff --git a/chromium/third_party/ffmpeg/libavformat/dump.c b/chromium/third_party/ffmpeg/libavformat/dump.c index 5e9a03185f1..6d29d85d1fb 100644 --- a/chromium/third_party/ffmpeg/libavformat/dump.c +++ b/chromium/third_party/ffmpeg/libavformat/dump.c @@ -34,6 +34,7 @@ #include "libavutil/replaygain.h" #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" +#include "libavutil/timecode.h" #include "avformat.h" @@ -131,10 +132,10 @@ static void print_fps(double d, const char *postfix) av_log(NULL, AV_LOG_INFO, "%1.0fk %s", d / 1000, postfix); } -static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) +static void dump_metadata(void *ctx, const AVDictionary *m, const char *indent) { if (m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0))) { - AVDictionaryEntry *tag = NULL; + const AVDictionaryEntry *tag = NULL; av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent); while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) @@ -158,7 +159,7 @@ static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) } /* param change side data*/ -static void dump_paramchange(void *ctx, AVPacketSideData *sd) +static void dump_paramchange(void *ctx, const AVPacketSideData *sd) { int size = sd->size; const uint8_t *data = sd->data; @@ -211,7 +212,7 @@ static void dump_paramchange(void *ctx, AVPacketSideData *sd) return; fail: - av_log(ctx, AV_LOG_ERROR, "unknown param"); + av_log(ctx, AV_LOG_ERROR, "unknown param\n"); } /* replaygain side data*/ @@ -235,15 +236,15 @@ static void print_peak(void *ctx, const char *str, uint32_t peak) av_log(ctx, AV_LOG_INFO, ", "); } -static void dump_replaygain(void *ctx, AVPacketSideData *sd) +static void dump_replaygain(void *ctx, const AVPacketSideData *sd) { - AVReplayGain *rg; + const AVReplayGain *rg; if (sd->size < sizeof(*rg)) { - av_log(ctx, AV_LOG_ERROR, "invalid data"); + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); return; } - rg = (AVReplayGain*)sd->data; + rg = (const AVReplayGain *)sd->data; print_gain(ctx, "track gain", rg->track_gain); print_peak(ctx, "track peak", rg->track_peak); @@ -251,16 +252,16 @@ static void dump_replaygain(void *ctx, AVPacketSideData *sd) print_peak(ctx, "album peak", rg->album_peak); } -static void dump_stereo3d(void *ctx, AVPacketSideData *sd) +static void dump_stereo3d(void *ctx, const AVPacketSideData *sd) { - AVStereo3D *stereo; + const AVStereo3D *stereo; if (sd->size < sizeof(*stereo)) { - av_log(ctx, AV_LOG_ERROR, "invalid data"); + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); return; } - stereo = (AVStereo3D *)sd->data; + stereo = (const AVStereo3D *)sd->data; av_log(ctx, AV_LOG_INFO, "%s", av_stereo3d_type_name(stereo->type)); @@ -268,12 +269,12 @@ static void dump_stereo3d(void *ctx, AVPacketSideData *sd) av_log(ctx, AV_LOG_INFO, " (inverted)"); } -static void dump_audioservicetype(void *ctx, AVPacketSideData *sd) +static void dump_audioservicetype(void *ctx, const AVPacketSideData *sd) { - enum AVAudioServiceType *ast = (enum AVAudioServiceType *)sd->data; + const enum AVAudioServiceType *ast = (const enum AVAudioServiceType *)sd->data; if (sd->size < sizeof(*ast)) { - av_log(ctx, AV_LOG_ERROR, "invalid data"); + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); return; } @@ -311,12 +312,12 @@ static void dump_audioservicetype(void *ctx, AVPacketSideData *sd) } } -static void dump_cpb(void *ctx, AVPacketSideData *sd) +static void dump_cpb(void *ctx, const AVPacketSideData *sd) { - AVCPBProperties *cpb = (AVCPBProperties *)sd->data; + const AVCPBProperties *cpb = (const AVCPBProperties *)sd->data; if (sd->size < sizeof(*cpb)) { - av_log(ctx, AV_LOG_ERROR, "invalid data"); + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); return; } @@ -334,8 +335,10 @@ static void dump_cpb(void *ctx, AVPacketSideData *sd) av_log(ctx, AV_LOG_INFO, "vbv_delay: %"PRIu64"", cpb->vbv_delay); } -static void dump_mastering_display_metadata(void *ctx, AVPacketSideData* sd) { - AVMasteringDisplayMetadata* metadata = (AVMasteringDisplayMetadata*)sd->data; +static void dump_mastering_display_metadata(void *ctx, const AVPacketSideData *sd) +{ + const AVMasteringDisplayMetadata *metadata = + (const AVMasteringDisplayMetadata *)sd->data; av_log(ctx, AV_LOG_INFO, "Mastering Display Metadata, " "has_primaries:%d has_luminance:%d " "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f) " @@ -351,21 +354,23 @@ static void dump_mastering_display_metadata(void *ctx, AVPacketSideData* sd) { av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance)); } -static void dump_content_light_metadata(void *ctx, AVPacketSideData* sd) +static void dump_content_light_metadata(void *ctx, const AVPacketSideData *sd) { - AVContentLightMetadata* metadata = (AVContentLightMetadata*)sd->data; + const AVContentLightMetadata *metadata = + (const AVContentLightMetadata *)sd->data; av_log(ctx, AV_LOG_INFO, "Content Light Level Metadata, " "MaxCLL=%d, MaxFALL=%d", metadata->MaxCLL, metadata->MaxFALL); } -static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData *sd) +static void dump_spherical(void *ctx, const AVCodecParameters *par, + const AVPacketSideData *sd) { - AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; + const AVSphericalMapping *spherical = (const AVSphericalMapping *)sd->data; double yaw, pitch, roll; if (sd->size < sizeof(*spherical)) { - av_log(ctx, AV_LOG_ERROR, "invalid data"); + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); return; } @@ -388,9 +393,10 @@ static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData * } } -static void dump_dovi_conf(void *ctx, AVPacketSideData* sd) +static void dump_dovi_conf(void *ctx, const AVPacketSideData *sd) { - AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; + const AVDOVIDecoderConfigurationRecord *dovi = + (const AVDOVIDecoderConfigurationRecord *)sd->data; av_log(ctx, AV_LOG_INFO, "version: %d.%d, profile: %d, level: %d, " "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d", @@ -402,7 +408,23 @@ static void dump_dovi_conf(void *ctx, AVPacketSideData* sd) dovi->dv_bl_signal_compatibility_id); } -static void dump_sidedata(void *ctx, AVStream *st, const char *indent) +static void dump_s12m_timecode(void *ctx, const AVPacketSideData *sd) +{ + const uint32_t *tc = (const uint32_t *)sd->data; + + if ((sd->size != sizeof(uint32_t) * 4) || (tc[0] > 3)) { + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); + return; + } + + for (int j = 1; j <= tc[0]; j++) { + char tcbuf[AV_TIMECODE_STR_SIZE]; + av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0); + av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] ? ", " : ""); + } +} + +static void dump_sidedata(void *ctx, const AVStream *st, const char *indent) { int i; @@ -410,10 +432,10 @@ static void dump_sidedata(void *ctx, AVStream *st, const char *indent) av_log(ctx, AV_LOG_INFO, "%sSide data:\n", indent); for (i = 0; i < st->nb_side_data; i++) { - AVPacketSideData sd = st->side_data[i]; + const AVPacketSideData *sd = &st->side_data[i]; av_log(ctx, AV_LOG_INFO, "%s ", indent); - switch (sd.type) { + switch (sd->type) { case AV_PKT_DATA_PALETTE: av_log(ctx, AV_LOG_INFO, "palette"); break; @@ -422,55 +444,59 @@ static void dump_sidedata(void *ctx, AVStream *st, const char *indent) break; case AV_PKT_DATA_PARAM_CHANGE: av_log(ctx, AV_LOG_INFO, "paramchange: "); - dump_paramchange(ctx, &sd); + dump_paramchange(ctx, sd); break; case AV_PKT_DATA_H263_MB_INFO: av_log(ctx, AV_LOG_INFO, "H.263 macroblock info"); break; case AV_PKT_DATA_REPLAYGAIN: av_log(ctx, AV_LOG_INFO, "replaygain: "); - dump_replaygain(ctx, &sd); + dump_replaygain(ctx, sd); break; case AV_PKT_DATA_DISPLAYMATRIX: av_log(ctx, AV_LOG_INFO, "displaymatrix: rotation of %.2f degrees", - av_display_rotation_get((int32_t *)sd.data)); + av_display_rotation_get((const int32_t *)sd->data)); break; case AV_PKT_DATA_STEREO3D: av_log(ctx, AV_LOG_INFO, "stereo3d: "); - dump_stereo3d(ctx, &sd); + dump_stereo3d(ctx, sd); break; case AV_PKT_DATA_AUDIO_SERVICE_TYPE: av_log(ctx, AV_LOG_INFO, "audio service type: "); - dump_audioservicetype(ctx, &sd); + dump_audioservicetype(ctx, sd); break; case AV_PKT_DATA_QUALITY_STATS: av_log(ctx, AV_LOG_INFO, "quality factor: %"PRId32", pict_type: %c", - AV_RL32(sd.data), av_get_picture_type_char(sd.data[4])); + AV_RL32(sd->data), av_get_picture_type_char(sd->data[4])); break; case AV_PKT_DATA_CPB_PROPERTIES: av_log(ctx, AV_LOG_INFO, "cpb: "); - dump_cpb(ctx, &sd); + dump_cpb(ctx, sd); break; case AV_PKT_DATA_MASTERING_DISPLAY_METADATA: - dump_mastering_display_metadata(ctx, &sd); + dump_mastering_display_metadata(ctx, sd); break; case AV_PKT_DATA_SPHERICAL: av_log(ctx, AV_LOG_INFO, "spherical: "); - dump_spherical(ctx, st->codecpar, &sd); + dump_spherical(ctx, st->codecpar, sd); break; case AV_PKT_DATA_CONTENT_LIGHT_LEVEL: - dump_content_light_metadata(ctx, &sd); + dump_content_light_metadata(ctx, sd); break; case AV_PKT_DATA_ICC_PROFILE: av_log(ctx, AV_LOG_INFO, "ICC Profile"); break; case AV_PKT_DATA_DOVI_CONF: av_log(ctx, AV_LOG_INFO, "DOVI configuration record: "); - dump_dovi_conf(ctx, &sd); + dump_dovi_conf(ctx, sd); + break; + case AV_PKT_DATA_S12M_TIMECODE: + av_log(ctx, AV_LOG_INFO, "SMPTE ST 12-1:2014: "); + dump_s12m_timecode(ctx, sd); break; default: av_log(ctx, AV_LOG_INFO, - "unknown side data type %d (%d bytes)", sd.type, sd.size); + "unknown side data type %d (%d bytes)", sd->type, sd->size); break; } @@ -479,14 +505,14 @@ static void dump_sidedata(void *ctx, AVStream *st, const char *indent) } /* "user interface" functions */ -static void dump_stream_format(AVFormatContext *ic, int i, +static void dump_stream_format(const AVFormatContext *ic, int i, int index, int is_output) { char buf[256]; int flags = (is_output ? ic->oformat->flags : ic->iformat->flags); - AVStream *st = ic->streams[i]; - AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); - char *separator = ic->dump_separator; + const AVStream *st = ic->streams[i]; + const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); + const char *separator = ic->dump_separator; AVCodecContext *avctx; int ret; @@ -500,6 +526,8 @@ static void dump_stream_format(AVFormatContext *ic, int i, return; } +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS // Fields which are missing from AVCodecParameters need to be taken from the AVCodecContext avctx->properties = st->codec->properties; avctx->codec = st->codec->codec; @@ -507,6 +535,8 @@ static void dump_stream_format(AVFormatContext *ic, int i, avctx->qmax = st->codec->qmax; avctx->coded_width = st->codec->coded_width; avctx->coded_height = st->codec->coded_height; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (separator) av_opt_set(avctx, "dump_separator", separator, 0); @@ -541,7 +571,13 @@ static void dump_stream_format(AVFormatContext *ic, int i, int fps = st->avg_frame_rate.den && st->avg_frame_rate.num; int tbr = st->r_frame_rate.den && st->r_frame_rate.num; int tbn = st->time_base.den && st->time_base.num; +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS int tbc = st->codec->time_base.den && st->codec->time_base.num; +FF_ENABLE_DEPRECATION_WARNINGS +#else + int tbc = 0; +#endif if (fps || tbr || tbn || tbc) av_log(NULL, AV_LOG_INFO, "%s", separator); @@ -552,8 +588,12 @@ static void dump_stream_format(AVFormatContext *ic, int i, print_fps(av_q2d(st->r_frame_rate), tbn || tbc ? "tbr, " : "tbr"); if (tbn) print_fps(1 / av_q2d(st->time_base), tbc ? "tbn, " : "tbn"); +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS if (tbc) print_fps(1 / av_q2d(st->codec->time_base), "tbc"); +FF_ENABLE_DEPRECATION_WARNINGS +#endif } if (st->disposition & AV_DISPOSITION_DEFAULT) @@ -615,7 +655,7 @@ void av_dump_format(AVFormatContext *ic, int index, if (!is_output) { av_log(NULL, AV_LOG_INFO, " Duration: "); if (ic->duration != AV_NOPTS_VALUE) { - int hours, mins, secs, us; + int64_t hours, mins, secs, us; int64_t duration = ic->duration + (ic->duration <= INT64_MAX - 5000 ? 5000 : 0); secs = duration / AV_TIME_BASE; us = duration % AV_TIME_BASE; @@ -623,7 +663,7 @@ void av_dump_format(AVFormatContext *ic, int index, secs %= 60; hours = mins / 60; mins %= 60; - av_log(NULL, AV_LOG_INFO, "%02d:%02d:%02d.%02d", hours, mins, secs, + av_log(NULL, AV_LOG_INFO, "%02"PRId64":%02"PRId64":%02"PRId64".%02"PRId64"", hours, mins, secs, (100 * us) / AV_TIME_BASE); } else { av_log(NULL, AV_LOG_INFO, "N/A"); @@ -647,7 +687,7 @@ void av_dump_format(AVFormatContext *ic, int index, } for (i = 0; i < ic->nb_chapters; i++) { - AVChapter *ch = ic->chapters[i]; + const AVChapter *ch = ic->chapters[i]; av_log(NULL, AV_LOG_INFO, " Chapter #%d:%d: ", index, i); av_log(NULL, AV_LOG_INFO, "start %f, ", ch->start * av_q2d(ch->time_base)); @@ -660,17 +700,18 @@ void av_dump_format(AVFormatContext *ic, int index, if (ic->nb_programs) { int j, k, total = 0; for (j = 0; j < ic->nb_programs; j++) { - AVDictionaryEntry *name = av_dict_get(ic->programs[j]->metadata, - "name", NULL, 0); - av_log(NULL, AV_LOG_INFO, " Program %d %s\n", ic->programs[j]->id, + const AVProgram *program = ic->programs[j]; + const AVDictionaryEntry *name = av_dict_get(program->metadata, + "name", NULL, 0); + av_log(NULL, AV_LOG_INFO, " Program %d %s\n", program->id, name ? name->value : ""); - dump_metadata(NULL, ic->programs[j]->metadata, " "); - for (k = 0; k < ic->programs[j]->nb_stream_indexes; k++) { - dump_stream_format(ic, ic->programs[j]->stream_index[k], + dump_metadata(NULL, program->metadata, " "); + for (k = 0; k < program->nb_stream_indexes; k++) { + dump_stream_format(ic, program->stream_index[k], index, is_output); - printed[ic->programs[j]->stream_index[k]] = 1; + printed[program->stream_index[k]] = 1; } - total += ic->programs[j]->nb_stream_indexes; + total += program->nb_stream_indexes; } if (total < ic->nb_streams) av_log(NULL, AV_LOG_INFO, " No Program\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/dv.c b/chromium/third_party/ffmpeg/libavformat/dv.c index e99422d4b59..d25641daac0 100644 --- a/chromium/third_party/ffmpeg/libavformat/dv.c +++ b/chromium/third_party/ffmpeg/libavformat/dv.c @@ -321,6 +321,21 @@ static int dv_extract_timecode(DVDemuxContext* c, const uint8_t* frame, char *tc /* The following 3 functions constitute our interface to the world */ +static int dv_init_demux(AVFormatContext *s, DVDemuxContext *c) +{ + c->vst = avformat_new_stream(s, NULL); + if (!c->vst) + return AVERROR(ENOMEM); + + c->fctx = s; + c->vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + c->vst->codecpar->codec_id = AV_CODEC_ID_DVVIDEO; + c->vst->codecpar->bit_rate = 25000000; + c->vst->start_time = 0; + + return 0; +} + DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s) { DVDemuxContext *c; @@ -329,18 +344,11 @@ DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s) if (!c) return NULL; - c->vst = avformat_new_stream(s, NULL); - if (!c->vst) { + if (dv_init_demux(s, c)) { av_free(c); return NULL; } - c->fctx = s; - c->vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - c->vst->codecpar->codec_id = AV_CODEC_ID_DVVIDEO; - c->vst->codecpar->bit_rate = 25000000; - c->vst->start_time = 0; - return c; } @@ -452,7 +460,7 @@ void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset) ************************************************************/ typedef struct RawDVContext { - DVDemuxContext *dv_demux; + DVDemuxContext dv_demux; uint8_t buf[DV_MAX_FRAME_SIZE]; } RawDVContext; @@ -462,31 +470,26 @@ static int dv_read_timecode(AVFormatContext *s) { int64_t pos = avio_tell(s->pb); // Read 3 DIF blocks: Header block and 2 Subcode blocks. - int partial_frame_size = 3 * 80; - uint8_t *partial_frame = av_mallocz(sizeof(*partial_frame) * - partial_frame_size); - +#define PARTIAL_FRAME_SIZE (3 * 80) + uint8_t partial_frame[PARTIAL_FRAME_SIZE]; RawDVContext *c = s->priv_data; - if (!partial_frame) - return AVERROR(ENOMEM); - ret = avio_read(s->pb, partial_frame, partial_frame_size); + ret = avio_read(s->pb, partial_frame, PARTIAL_FRAME_SIZE); if (ret < 0) goto finish; - if (ret < partial_frame_size) { + if (ret < PARTIAL_FRAME_SIZE) { ret = -1; goto finish; } - ret = dv_extract_timecode(c->dv_demux, partial_frame, timecode); + ret = dv_extract_timecode(&c->dv_demux, partial_frame, timecode); if (ret) av_dict_set(&s->metadata, "timecode", timecode, 0); else av_log(s, AV_LOG_ERROR, "Detected timecode is invalid\n"); finish: - av_free(partial_frame); avio_seek(s->pb, pos, SEEK_SET); return ret; } @@ -497,16 +500,14 @@ static int dv_read_header(AVFormatContext *s) RawDVContext *c = s->priv_data; int ret; - c->dv_demux = avpriv_dv_init_demux(s); - if (!c->dv_demux) - return AVERROR(ENOMEM); + if ((ret = dv_init_demux(s, &c->dv_demux)) < 0) + return ret; state = avio_rb32(s->pb); while ((state & 0xffffff7f) != 0x1f07003f) { if (avio_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "Cannot find DV header.\n"); - ret = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } if (state == 0x003f0700 || state == 0xff3f0700) marker_pos = avio_tell(s->pb); @@ -521,33 +522,26 @@ static int dv_read_header(AVFormatContext *s) if (avio_read(s->pb, c->buf + 4, DV_PROFILE_BYTES - 4) != DV_PROFILE_BYTES - 4 || avio_seek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0) { - ret = AVERROR(EIO); - goto fail; + return AVERROR(EIO); } - c->dv_demux->sys = av_dv_frame_profile(c->dv_demux->sys, + c->dv_demux.sys = av_dv_frame_profile(c->dv_demux.sys, c->buf, DV_PROFILE_BYTES); - if (!c->dv_demux->sys) { + if (!c->dv_demux.sys) { av_log(s, AV_LOG_ERROR, "Can't determine profile of DV input stream.\n"); - ret = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } - s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size, + s->bit_rate = av_rescale_q(c->dv_demux.sys->frame_size, (AVRational) { 8, 1 }, - c->dv_demux->sys->time_base); + c->dv_demux.sys->time_base); if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) dv_read_timecode(s); return 0; - -fail: - av_freep(&c->dv_demux); - - return ret; } static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -555,14 +549,14 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) int size; RawDVContext *c = s->priv_data; - size = avpriv_dv_get_packet(c->dv_demux, 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) + if (!c->dv_demux.sys) return AVERROR(EIO); - size = c->dv_demux->sys->frame_size; + size = c->dv_demux.sys->frame_size; ret = avio_read(s->pb, c->buf, size); if (ret < 0) { return ret; @@ -570,7 +564,7 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EIO); } - size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size, pos); + size = avpriv_dv_produce_packet(&c->dv_demux, pkt, c->buf, size, pos); } return size; @@ -580,7 +574,7 @@ static int dv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { RawDVContext *r = s->priv_data; - DVDemuxContext *c = r->dv_demux; + DVDemuxContext *c = &r->dv_demux; int64_t offset = dv_frame_offset(s, c, timestamp, flags); if (avio_seek(s->pb, offset, SEEK_SET) < 0) @@ -590,13 +584,6 @@ static int dv_read_seek(AVFormatContext *s, int stream_index, return 0; } -static int dv_read_close(AVFormatContext *s) -{ - RawDVContext *c = s->priv_data; - av_freep(&c->dv_demux); - return 0; -} - static int dv_probe(const AVProbeData *p) { unsigned marker_pos = 0; @@ -646,7 +633,6 @@ AVInputFormat ff_dv_demuxer = { .read_probe = dv_probe, .read_header = dv_read_header, .read_packet = dv_read_packet, - .read_close = dv_read_close, .read_seek = dv_read_seek, .extensions = "dv,dif", }; diff --git a/chromium/third_party/ffmpeg/libavformat/dvenc.c b/chromium/third_party/ffmpeg/libavformat/dvenc.c index c71e532771e..b04d6044d76 100644 --- a/chromium/third_party/ffmpeg/libavformat/dvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/dvenc.c @@ -406,9 +406,10 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt) fsize = dv_assemble_frame(s, s->priv_data, s->streams[pkt->stream_index], pkt->data, pkt->size, &frame); - if (fsize > 0) { - avio_write(s->pb, frame, fsize); + if (fsize < 0) { + return fsize; } + avio_write(s->pb, frame, fsize); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/fifo.c b/chromium/third_party/ffmpeg/libavformat/fifo.c index d11dc6626c7..17748e94ce5 100644 --- a/chromium/third_party/ffmpeg/libavformat/fifo.c +++ b/chromium/third_party/ffmpeg/libavformat/fifo.c @@ -19,6 +19,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdatomic.h> + #include "libavutil/avassert.h" #include "libavutil/opt.h" #include "libavutil/time.h" @@ -77,6 +79,9 @@ typedef struct FifoContext { /* Value > 0 signals queue overflow */ volatile uint8_t overflow_flag; + atomic_int_least64_t queue_duration; + int64_t last_sent_dts; + int64_t timeshift; } FifoContext; typedef struct FifoThreadContext { @@ -98,9 +103,12 @@ typedef struct FifoThreadContext { * so finalization by calling write_trailer and ff_io_close must be done * before exiting / reinitialization of underlying muxer */ uint8_t header_written; + + int64_t last_received_dts; } FifoThreadContext; typedef enum FifoMessageType { + FIFO_NOOP, FIFO_WRITE_HEADER, FIFO_WRITE_PACKET, FIFO_FLUSH_OUTPUT @@ -159,6 +167,15 @@ static int fifo_thread_flush_output(FifoThreadContext *ctx) return av_write_frame(avf2, NULL); } +static int64_t next_duration(AVFormatContext *avf, AVPacket *pkt, int64_t *last_dts) +{ + AVStream *st = avf->streams[pkt->stream_index]; + int64_t dts = av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q); + int64_t duration = (*last_dts == AV_NOPTS_VALUE ? 0 : dts - *last_dts); + *last_dts = dts; + return duration; +} + static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt) { AVFormatContext *avf = ctx->avf; @@ -167,6 +184,9 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt) AVRational src_tb, dst_tb; int ret, s_idx; + if (fifo->timeshift && pkt->dts != AV_NOPTS_VALUE) + atomic_fetch_sub_explicit(&fifo->queue_duration, next_duration(avf, pkt, &ctx->last_received_dts), memory_order_relaxed); + if (ctx->drop_until_keyframe) { if (pkt->flags & AV_PKT_FLAG_KEY) { ctx->drop_until_keyframe = 0; @@ -209,6 +229,9 @@ static int fifo_thread_dispatch_message(FifoThreadContext *ctx, FifoMessage *msg { int ret = AVERROR(EINVAL); + if (msg->type == FIFO_NOOP) + return 0; + if (!ctx->header_written) { ret = fifo_thread_write_header(ctx); if (ret < 0) @@ -390,12 +413,13 @@ static void *fifo_consumer_thread(void *data) AVFormatContext *avf = data; FifoContext *fifo = avf->priv_data; AVThreadMessageQueue *queue = fifo->queue; - FifoMessage msg = {FIFO_WRITE_HEADER, {0}}; + FifoMessage msg = {fifo->timeshift ? FIFO_NOOP : FIFO_WRITE_HEADER, {0}}; int ret; FifoThreadContext fifo_thread_ctx; memset(&fifo_thread_ctx, 0, sizeof(FifoThreadContext)); fifo_thread_ctx.avf = avf; + fifo_thread_ctx.last_received_dts = AV_NOPTS_VALUE; while (1) { uint8_t just_flushed = 0; @@ -429,6 +453,10 @@ static void *fifo_consumer_thread(void *data) if (just_flushed) av_log(avf, AV_LOG_INFO, "FIFO queue flushed\n"); + if (fifo->timeshift) + while (atomic_load_explicit(&fifo->queue_duration, memory_order_relaxed) < fifo->timeshift) + av_usleep(10000); + ret = av_thread_message_queue_recv(queue, &msg, 0); if (ret < 0) { av_thread_message_queue_set_err_send(queue, ret); @@ -488,6 +516,8 @@ static int fifo_init(AVFormatContext *avf) " only when drop_pkts_on_overflow is also turned on\n"); return AVERROR(EINVAL); } + atomic_init(&fifo->queue_duration, 0); + fifo->last_sent_dts = AV_NOPTS_VALUE; oformat = av_guess_format(fifo->format, avf->url, NULL); if (!oformat) { @@ -563,6 +593,9 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket *pkt) goto fail; } + if (fifo->timeshift && pkt->dts != AV_NOPTS_VALUE) + atomic_fetch_add_explicit(&fifo->queue_duration, next_duration(avf, pkt, &fifo->last_sent_dts), memory_order_relaxed); + return ret; fail: if (pkt) @@ -576,6 +609,27 @@ static int fifo_write_trailer(AVFormatContext *avf) int ret; av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF); + if (fifo->timeshift) { + int64_t now = av_gettime_relative(); + int64_t elapsed = 0; + FifoMessage msg = {FIFO_NOOP}; + do { + int64_t delay = av_gettime_relative() - now; + if (delay < 0) { // Discontinuity? + delay = 10000; + now = av_gettime_relative(); + } else { + now += delay; + } + atomic_fetch_add_explicit(&fifo->queue_duration, delay, memory_order_relaxed); + elapsed += delay; + if (elapsed > fifo->timeshift) + break; + av_usleep(10000); + ret = av_thread_message_queue_send(fifo->queue, &msg, AV_THREAD_MESSAGE_NONBLOCK); + } while (ret >= 0 || ret == AVERROR(EAGAIN)); + atomic_store(&fifo->queue_duration, INT64_MAX); + } ret = pthread_join(fifo->writer_thread, NULL); if (ret < 0) { @@ -630,6 +684,9 @@ static const AVOption options[] = { {"recover_any_error", "Attempt recovery regardless of type of the error", OFFSET(recover_any_error), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + {"timeshift", "Delay fifo output", OFFSET(timeshift), + AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM}, + {NULL}, }; diff --git a/chromium/third_party/ffmpeg/libavformat/flac_picture.c b/chromium/third_party/ffmpeg/libavformat/flac_picture.c index 81ddf80465b..53e24b28b74 100644 --- a/chromium/third_party/ffmpeg/libavformat/flac_picture.c +++ b/chromium/third_party/ffmpeg/libavformat/flac_picture.c @@ -27,7 +27,9 @@ #include "id3v2.h" #include "internal.h" -int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) +#define MAX_TRUNC_PICTURE_SIZE (500 * 1024 * 1024) + +int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size, int truncate_workaround) { const CodecMime *mime = ff_id3v2_mime_tags; enum AVCodecID id = AV_CODEC_ID_NONE; @@ -36,7 +38,8 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) GetByteContext g; AVStream *st; int width, height, ret = 0; - unsigned int len, type; + unsigned int type; + uint32_t len, left, trunclen = 0; if (buf_size < 34) { av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); @@ -114,16 +117,44 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) /* picture data */ len = bytestream2_get_be32u(&g); - if (len <= 0 || len > bytestream2_get_bytes_left(&g)) { - av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR_INVALIDDATA; - goto fail; + + left = bytestream2_get_bytes_left(&g); + if (len <= 0 || len > left) { + if (len > MAX_TRUNC_PICTURE_SIZE || len >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { + av_log(s, AV_LOG_ERROR, "Attached picture metadata block too big %u\n", len); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR_INVALIDDATA; + goto fail; + } + + // Workaround bug for flac muxers that writs truncated metadata picture block size if + // the picture size do not fit in 24 bits. lavf flacenc used to have the issue and based + // on existing broken files other unknown flac muxers seems to truncate also. + if (truncate_workaround && + s->strict_std_compliance <= FF_COMPLIANCE_NORMAL && + len > left && (len & 0xffffff) == left) { + av_log(s, AV_LOG_INFO, "Correcting truncated metadata picture size from %u to %u\n", left, len); + trunclen = len - left; + } else { + av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR_INVALIDDATA; + goto fail; + } } if (!(data = av_buffer_alloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) { RETURN_ERROR(AVERROR(ENOMEM)); } - bytestream2_get_bufferu(&g, data->data, len); + + if (trunclen == 0) { + bytestream2_get_bufferu(&g, data->data, len); + } else { + // If truncation was detected copy all data from block and read missing bytes + // not included in the block size + bytestream2_get_bufferu(&g, data->data, left); + if (avio_read(s->pb, data->data + len - trunclen, trunclen) < trunclen) + RETURN_ERROR(AVERROR_INVALIDDATA); + } memset(data->data + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (AV_RB64(data->data) == PNGSIG) diff --git a/chromium/third_party/ffmpeg/libavformat/flac_picture.h b/chromium/third_party/ffmpeg/libavformat/flac_picture.h index 4374b6f4f60..61fd0c88065 100644 --- a/chromium/third_party/ffmpeg/libavformat/flac_picture.h +++ b/chromium/third_party/ffmpeg/libavformat/flac_picture.h @@ -26,6 +26,6 @@ #define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0) -int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size); +int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size, int truncate_workaround); #endif /* AVFORMAT_FLAC_PICTURE_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/flacdec.c b/chromium/third_party/ffmpeg/libavformat/flacdec.c index cb516fb1f3e..79c05f14bf7 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flacdec.c @@ -146,7 +146,7 @@ static int flac_read_header(AVFormatContext *s) } av_freep(&buffer); } else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) { - ret = ff_flac_parse_picture(s, buffer, metadata_size); + ret = ff_flac_parse_picture(s, buffer, metadata_size, 1); av_freep(&buffer); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Error parsing attached picture.\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/flacenc.c b/chromium/third_party/ffmpeg/libavformat/flacenc.c index a043274df60..b947a3b067b 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacenc.c +++ b/chromium/third_party/ffmpeg/libavformat/flacenc.c @@ -29,7 +29,6 @@ #include "id3v2.h" #include "internal.h" #include "vorbiscomment.h" -#include "libavcodec/bytestream.h" typedef struct FlacMuxerContext { @@ -62,25 +61,16 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, { const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; int64_t len; - uint8_t *p, *p0; ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); len = ff_vorbiscomment_length(*m, vendor, NULL, 0); if (len >= ((1<<24) - 4)) return AVERROR(EINVAL); - p0 = av_malloc(len+4); - if (!p0) - return AVERROR(ENOMEM); - p = p0; - - bytestream_put_byte(&p, last_block ? 0x84 : 0x04); - bytestream_put_be24(&p, len); - ff_vorbiscomment_write(&p, m, vendor, NULL, 0); - - avio_write(pb, p0, len+4); - av_freep(&p0); - p = NULL; + + avio_w8(pb, last_block ? 0x84 : 0x04); + avio_wb24(pb, len); + ff_vorbiscomment_write(pb, *m, vendor, NULL, 0); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/flvdec.c b/chromium/third_party/ffmpeg/libavformat/flvdec.c index 7c3e5b06c6f..08622739f31 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flvdec.c @@ -514,8 +514,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, if (key && (ioc->seekable & AVIO_SEEKABLE_NORMAL) && !strcmp(KEYFRAMES_TAG, key) && depth == 1) - if (parse_keyframes_index(s, ioc, - max_pos) < 0) + if (parse_keyframes_index(s, ioc, max_pos) < 0) av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); else add_keyframes_index(s); @@ -732,8 +731,7 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) astream = stream; if (flv->last_keyframe_stream_index == -1) flv->last_keyframe_stream_index = i; - } - else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) dstream = stream; } @@ -1058,8 +1056,7 @@ retry: if (type == 0 && dts == 0 || type < 0) { if (type < 0 && flv->validate_count && flv->validate_index[0].pos > next && - flv->validate_index[0].pos - 4 < 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; } @@ -1120,7 +1117,6 @@ skip: st = create_stream(s, stream_types[stream_type]); if (!st) return AVERROR(ENOMEM); - } av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard); @@ -1133,10 +1129,9 @@ skip: stream_type == FLV_STREAM_TYPE_AUDIO)) av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); - if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) - ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) - || st->discard >= AVDISCARD_ALL - ) { + if ((st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO)) || + (st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && stream_type == FLV_STREAM_TYPE_VIDEO)) || + st->discard >= AVDISCARD_ALL) { avio_seek(s->pb, next, SEEK_SET); ret = FFERROR_REDO; goto leave; @@ -1283,12 +1278,11 @@ retry_duration: pkt->stream_index = st->index; pkt->pos = pos; if (flv->new_extradata[stream_type]) { - uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, - flv->new_extradata_size[stream_type]); - if (side) { - memcpy(side, flv->new_extradata[stream_type], - flv->new_extradata_size[stream_type]); - av_freep(&flv->new_extradata[stream_type]); + int ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + flv->new_extradata[stream_type], + flv->new_extradata_size[stream_type]); + if (ret >= 0) { + flv->new_extradata[stream_type] = NULL; flv->new_extradata_size[stream_type] = 0; } } @@ -1300,10 +1294,10 @@ retry_duration: ff_add_param_change(pkt, channels, 0, sample_rate, 0, 0); } - if ( stream_type == FLV_STREAM_TYPE_AUDIO || - ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) || - stream_type == FLV_STREAM_TYPE_SUBTITLE || - stream_type == FLV_STREAM_TYPE_DATA) + if (stream_type == FLV_STREAM_TYPE_AUDIO || + (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || + stream_type == FLV_STREAM_TYPE_SUBTITLE || + stream_type == FLV_STREAM_TYPE_DATA) pkt->flags |= AV_PKT_FLAG_KEY; leave: diff --git a/chromium/third_party/ffmpeg/libavformat/flvenc.c b/chromium/third_party/ffmpeg/libavformat/flvenc.c index 5cf3ce8a1ab..1cfcdc63922 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/flvenc.c @@ -902,7 +902,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { - int side_size = 0; + int side_size; uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { ret = ff_alloc_extradata(par, side_size); diff --git a/chromium/third_party/ffmpeg/libavformat/ftp.c b/chromium/third_party/ffmpeg/libavformat/ftp.c index e3d194da580..caeea429209 100644 --- a/chromium/third_party/ffmpeg/libavformat/ftp.c +++ b/chromium/third_party/ffmpeg/libavformat/ftp.c @@ -333,15 +333,15 @@ static int ftp_passive_mode(FTPContext *s) *end = '\0'; /* skip ip */ if (!av_strtok(start, ",", &end)) goto fail; - if (!av_strtok(end, ",", &end)) goto fail; - if (!av_strtok(end, ",", &end)) goto fail; - if (!av_strtok(end, ",", &end)) goto fail; + if (!av_strtok(NULL, ",", &end)) goto fail; + if (!av_strtok(NULL, ",", &end)) goto fail; + if (!av_strtok(NULL, ",", &end)) goto fail; /* parse port number */ - start = av_strtok(end, ",", &end); + start = av_strtok(NULL, ",", &end); if (!start) goto fail; s->server_data_port = atoi(start) * 256; - start = av_strtok(end, ",", &end); + start = av_strtok(NULL, ",", &end); if (!start) goto fail; s->server_data_port += atoi(start); ff_dlog(s, "Server data port: %d\n", s->server_data_port); @@ -963,8 +963,10 @@ static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next) static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next) { char *fact, *value; + char *saveptr = NULL, *p = mlsd; ff_dlog(NULL, "%s\n", mlsd); - while(fact = av_strtok(mlsd, ";", &mlsd)) { + while(fact = av_strtok(p, ";", &saveptr)) { + p = NULL; if (fact[0] == ' ') { next->name = av_strdup(&fact[1]); continue; diff --git a/chromium/third_party/ffmpeg/libavformat/gifdec.c b/chromium/third_party/ffmpeg/libavformat/gifdec.c index a31644c2a88..d617de5f41a 100644 --- a/chromium/third_party/ffmpeg/libavformat/gifdec.c +++ b/chromium/third_party/ffmpeg/libavformat/gifdec.c @@ -144,7 +144,7 @@ static int gif_read_header(AVFormatContext *s) AVBPrint bp; int block_size; - av_bprint_init(&bp, 0, -1); + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); while ((block_size = avio_r8(pb)) != 0) { avio_read_to_bprint(pb, &bp, block_size); } diff --git a/chromium/third_party/ffmpeg/libavformat/gopher.c b/chromium/third_party/ffmpeg/libavformat/gopher.c index 3070b24caf2..8b6d14a1f77 100644 --- a/chromium/third_party/ffmpeg/libavformat/gopher.c +++ b/chromium/third_party/ffmpeg/libavformat/gopher.c @@ -68,10 +68,7 @@ static int gopher_connect(URLContext *h, const char *path) static int gopher_close(URLContext *h) { GopherContext *s = h->priv_data; - if (s->hd) { - ffurl_close(s->hd); - s->hd = NULL; - } + ffurl_closep(&s->hd); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/gxfenc.c b/chromium/third_party/ffmpeg/libavformat/gxfenc.c index e7536a6a7eb..6d4df894f63 100644 --- a/chromium/third_party/ffmpeg/libavformat/gxfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/gxfenc.c @@ -27,8 +27,8 @@ #include "avformat.h" #include "internal.h" #include "gxf.h" -#include "audiointerleave.h" +#define GXF_SAMPLES_PER_FRAME 32768 #define GXF_AUDIO_PACKET_SIZE 65536 #define GXF_TIMECODE(c, d, h, m, s, f) \ @@ -44,7 +44,7 @@ typedef struct GXFTimecode{ } GXFTimecode; typedef struct GXFStreamContext { - AudioInterleaveContext aic; + int64_t pkt_cnt; uint32_t track_type; uint32_t sample_size; uint32_t sample_rate; @@ -663,8 +663,6 @@ static int gxf_write_umf_packet(AVFormatContext *s) return updatePacketSize(pb, pos); } -static const int GXF_samples_per_frame = 32768; - static void gxf_init_timecode_track(GXFStreamContext *sc, GXFStreamContext *vsc) { if (!vsc) @@ -736,6 +734,9 @@ static int gxf_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "only mono tracks are allowed\n"); return -1; } + ret = ff_stream_add_bitstream_filter(st, "pcm_rechunk", "n="AV_STRINGIFY(GXF_SAMPLES_PER_FRAME)); + if (ret < 0) + return ret; sc->track_type = 2; sc->sample_rate = st->codecpar->sample_rate; avpriv_set_pts_info(st, 64, 1, sc->sample_rate); @@ -818,9 +819,6 @@ static int gxf_write_header(AVFormatContext *s) sc->order = s->nb_streams - st->index; } - if (ff_audio_interleave_init(s, GXF_samples_per_frame, (AVRational){ 1, 48000 }) < 0) - return -1; - if (tcr && vsc) gxf_init_timecode(s, &gxf->tc, tcr->value, vsc->fields); @@ -877,8 +875,6 @@ static void gxf_deinit(AVFormatContext *s) { GXFContext *gxf = s->priv_data; - ff_audio_interleave_close(s); - av_freep(&gxf->flt_entries); av_freep(&gxf->map_offsets); } @@ -1014,10 +1010,19 @@ static int gxf_compare_field_nb(AVFormatContext *s, const AVPacket *next, static int gxf_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) { - if (pkt && s->streams[pkt->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - pkt->duration = 2; // enforce 2 fields - return ff_audio_rechunk_interleave(s, out, pkt, flush, - ff_interleave_packet_per_dts, gxf_compare_field_nb); + int ret; + if (pkt) { + AVStream *st = s->streams[pkt->stream_index]; + GXFStreamContext *sc = st->priv_data; + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + pkt->pts = pkt->dts = sc->pkt_cnt * 2; // enforce 2 fields + else + pkt->pts = pkt->dts = sc->pkt_cnt * GXF_SAMPLES_PER_FRAME; + sc->pkt_cnt++; + if ((ret = ff_interleave_add_packet(s, pkt, gxf_compare_field_nb)) < 0) + return ret; + } + return ff_interleave_packet_per_dts(s, out, NULL, flush); } AVOutputFormat ff_gxf_muxer = { diff --git a/chromium/third_party/ffmpeg/libavformat/hdsenc.c b/chromium/third_party/ffmpeg/libavformat/hdsenc.c index 46f0026bce9..353a45f6df2 100644 --- a/chromium/third_party/ffmpeg/libavformat/hdsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hdsenc.c @@ -317,21 +317,18 @@ static int hds_write_header(AVFormatContext *s) ff_const59 AVOutputFormat *oformat; if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { - ret = AVERROR(errno); av_log(s, AV_LOG_ERROR , "Failed to create directory %s\n", s->url); - goto fail; + return AVERROR(errno); } oformat = av_guess_format("flv", NULL, NULL); if (!oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; + return AVERROR_MUXER_NOT_FOUND; } c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams)); if (!c->streams) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } for (i = 0; i < s->nb_streams; i++) { @@ -341,8 +338,7 @@ static int hds_write_header(AVFormatContext *s) if (!st->codecpar->bit_rate) { av_log(s, AV_LOG_ERROR, "No bit rate set for stream %d\n", i); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (os->has_video) { @@ -358,8 +354,7 @@ static int hds_write_header(AVFormatContext *s) os->has_audio = 1; } else { av_log(s, AV_LOG_ERROR, "Unsupported stream type in stream %d\n", i); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } os->bitrate += s->streams[i]->codecpar->bit_rate; @@ -367,8 +362,7 @@ static int hds_write_header(AVFormatContext *s) os->first_stream = i; ctx = avformat_alloc_context(); if (!ctx) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } os->ctx = ctx; ctx->oformat = oformat; @@ -379,8 +373,7 @@ static int hds_write_header(AVFormatContext *s) AVIO_FLAG_WRITE, os, NULL, hds_write, NULL); if (!ctx->pb) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } } else { ctx = os->ctx; @@ -388,8 +381,7 @@ static int hds_write_header(AVFormatContext *s) s->streams[i]->id = c->nb_streams; if (!(st = avformat_new_stream(ctx, NULL))) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); st->codecpar->codec_tag = 0; @@ -403,7 +395,7 @@ static int hds_write_header(AVFormatContext *s) OutputStream *os = &c->streams[i]; int j; if ((ret = avformat_write_header(os->ctx, NULL)) < 0) { - goto fail; + return ret; } os->ctx_inited = 1; avio_flush(os->ctx->pb); @@ -414,7 +406,7 @@ static int hds_write_header(AVFormatContext *s) "%s/stream%d_temp", s->url, i); ret = init_file(s, os, 0); if (ret < 0) - goto fail; + return ret; if (!os->has_video && c->min_frag_duration <= 0) { av_log(s, AV_LOG_WARNING, @@ -425,9 +417,6 @@ static int hds_write_header(AVFormatContext *s) } ret = write_manifest(s, 0); -fail: - if (ret) - hds_free(s); return ret; } @@ -557,7 +546,6 @@ static int hds_write_trailer(AVFormatContext *s) rmdir(s->url); } - hds_free(s); return 0; } @@ -588,5 +576,6 @@ AVOutputFormat ff_hds_muxer = { .write_header = hds_write_header, .write_packet = hds_write_packet, .write_trailer = hds_write_trailer, + .deinit = hds_free, .priv_class = &hds_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/hevc.c b/chromium/third_party/ffmpeg/libavformat/hevc.c index f621cb2f198..94eb3a9cb11 100644 --- a/chromium/third_party/ffmpeg/libavformat/hevc.c +++ b/chromium/third_party/ffmpeg/libavformat/hevc.c @@ -1068,29 +1068,27 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, int size, int ps_array_completeness) { - int ret = 0; - uint8_t *buf, *end, *start = NULL; HEVCDecoderConfigurationRecord hvcc; - - hvcc_init(&hvcc); + uint8_t *buf, *end, *start; + int ret; if (size < 6) { /* We can't write a valid hvcC from the provided data */ - ret = AVERROR_INVALIDDATA; - goto end; + return AVERROR_INVALIDDATA; } else if (*data == 1) { /* Data is already hvcC-formatted */ avio_write(pb, data, size); - goto end; + return 0; } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) { /* Not a valid Annex B start code prefix */ - ret = AVERROR_INVALIDDATA; - goto end; + return AVERROR_INVALIDDATA; } ret = ff_avc_parse_nal_units_buf(data, &start, &size); if (ret < 0) - goto end; + return ret; + + hvcc_init(&hvcc); buf = start; end = start + size; diff --git a/chromium/third_party/ffmpeg/libavformat/hls.c b/chromium/third_party/ffmpeg/libavformat/hls.c index fc45719d1c0..84f0a5f3238 100644 --- a/chromium/third_party/ffmpeg/libavformat/hls.c +++ b/chromium/third_party/ffmpeg/libavformat/hls.c @@ -311,6 +311,8 @@ static struct playlist *new_playlist(HLSContext *c, const char *url, return NULL; reset_packet(&pls->pkt); ff_make_absolute_url(pls->url, sizeof(pls->url), base, url); + if (!pls->url[0]) + return NULL; pls->seek_timestamp = AV_NOPTS_VALUE; pls->is_id3_timestamped = -1; @@ -416,6 +418,10 @@ static struct segment *new_init_section(struct playlist *pls, ptr = info->uri; } else { ff_make_absolute_url(tmp_str, sizeof(tmp_str), url_base, info->uri); + if (!tmp_str[0]) { + av_free(sec); + return NULL; + } } sec->url = av_strdup(ptr); if (!sec->url) { @@ -841,6 +847,11 @@ static int parse_playlist(HLSContext *c, const char *url, if (key_type != KEY_NONE) { ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); + if (!tmp_str[0]) { + av_free(cur_init_section); + ret = AVERROR_INVALIDDATA; + goto fail; + } cur_init_section->key = av_strdup(tmp_str); if (!cur_init_section->key) { av_free(cur_init_section); @@ -883,8 +894,6 @@ static int parse_playlist(HLSContext *c, const char *url, ret = AVERROR(ENOMEM); goto fail; } - seg->duration = duration; - seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { @@ -895,6 +904,11 @@ static int parse_playlist(HLSContext *c, const char *url, if (key_type != KEY_NONE) { ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); + if (!tmp_str[0]) { + ret = AVERROR_INVALIDDATA; + av_free(seg); + goto fail; + } seg->key = av_strdup(tmp_str); if (!seg->key) { av_free(seg); @@ -906,6 +920,13 @@ static int parse_playlist(HLSContext *c, const char *url, } ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line); + if (!tmp_str[0]) { + ret = AVERROR_INVALIDDATA; + if (seg->key) + av_free(seg->key); + av_free(seg); + goto fail; + } seg->url = av_strdup(tmp_str); if (!seg->url) { av_free(seg->key); @@ -914,6 +935,13 @@ static int parse_playlist(HLSContext *c, const char *url, goto fail; } + if (duration < 0.001 * AV_TIME_BASE) { + av_log(c->ctx, AV_LOG_WARNING, "Cannot get correct #EXTINF value of segment %s," + " set to default value to 1ms.\n", seg->url); + duration = 0.001 * AV_TIME_BASE; + } + seg->duration = duration; + seg->key_type = key_type; dynarray_add(&pls->segments, &pls->n_segments, seg); is_segment = 0; @@ -1004,7 +1032,7 @@ static void parse_id3(AVFormatContext *s, AVIOContext *pb, ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); for (meta = *extra_meta; meta; meta = meta->next) { if (!strcmp(meta->tag, "PRIV")) { - ID3v2ExtraMetaPRIV *priv = meta->data; + ID3v2ExtraMetaPRIV *priv = &meta->data.priv; if (priv->datasize == 8 && !strcmp(priv->owner, id3_priv_owner_ts)) { /* 33-bit MPEG timestamp */ int64_t ts = AV_RB64(priv->data); @@ -1015,7 +1043,7 @@ static void parse_id3(AVFormatContext *s, AVIOContext *pb, av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts); } } else if (!strcmp(meta->tag, "APIC") && apic) - *apic = meta->data; + *apic = &meta->data.apic; } } @@ -1070,12 +1098,12 @@ static void handle_id3(AVIOContext *pb, struct playlist *pls) /* get picture attachment and set text metadata */ if (pls->ctx->nb_streams) - ff_id3v2_parse_apic(pls->ctx, &extra_meta); + ff_id3v2_parse_apic(pls->ctx, extra_meta); else /* demuxer not yet opened, defer picture attachment */ pls->id3_deferred_extra = extra_meta; - ff_id3v2_parse_priv_dict(&metadata, &extra_meta); + ff_id3v2_parse_priv_dict(&metadata, extra_meta); av_dict_copy(&pls->ctx->metadata, metadata, 0); pls->id3_initial = metadata; @@ -1263,7 +1291,7 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, * as would be expected. Wrong offset received from the server will not be * noticed without the call, though. */ - if (ret == 0 && !is_http && seg->key_type == KEY_NONE && seg->url_offset) { + if (ret == 0 && !is_http && seg->url_offset) { int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET); if (seekret < 0) { av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url); @@ -1740,6 +1768,20 @@ static int set_stream_info_from_input_stream(AVStream *st, struct playlist *pls, else avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); + // copy disposition + st->disposition = ist->disposition; + + // copy side data + for (int i = 0; i < ist->nb_side_data; i++) { + const AVPacketSideData *sd_src = &ist->side_data[i]; + uint8_t *dst_data; + + dst_data = av_stream_new_side_data(st, sd_src->type, sd_src->size); + if (!dst_data) + return AVERROR(ENOMEM); + memcpy(dst_data, sd_src->data, sd_src->size); + } + st->internal->need_context_update = 1; return 0; @@ -1904,6 +1946,7 @@ static int hls_read_header(AVFormatContext *s) /* Open the demuxer for each playlist */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; + char *url; ff_const59 AVInputFormat *in_fmt = NULL; if (!(pls->ctx = avformat_alloc_context())) { @@ -1941,8 +1984,10 @@ static int hls_read_header(AVFormatContext *s) read_data, NULL, NULL); pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4; pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE; - ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url, - NULL, 0, 0); + pls->ctx->interrupt_callback = s->interrupt_callback; + url = av_strdup(pls->segments[0]->url); + ret = av_probe_input_buffer(&pls->pb, &in_fmt, url, NULL, 0, 0); + av_free(url); if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If @@ -1965,11 +2010,10 @@ static int hls_read_header(AVFormatContext *s) goto fail; if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) { - ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra); + ff_id3v2_parse_apic(pls->ctx, pls->id3_deferred_extra); avformat_queue_attached_pictures(pls->ctx); - ff_id3v2_parse_priv(pls->ctx, &pls->id3_deferred_extra); + ff_id3v2_parse_priv(pls->ctx, pls->id3_deferred_extra); ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); - pls->id3_deferred_extra = NULL; } if (pls->is_id3_timestamped == -1) diff --git a/chromium/third_party/ffmpeg/libavformat/hlsenc.c b/chromium/third_party/ffmpeg/libavformat/hlsenc.c index d75684741f9..cb31d6aed7c 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsenc.c @@ -41,6 +41,7 @@ #include "libavutil/random_seed.h" #include "libavutil/opt.h" #include "libavutil/log.h" +#include "libavutil/time.h" #include "libavutil/time_internal.h" #include "avformat.h" @@ -56,6 +57,8 @@ typedef enum { HLS_START_SEQUENCE_AS_START_NUMBER = 0, HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH = 1, HLS_START_SEQUENCE_AS_FORMATTED_DATETIME = 2, // YYYYMMDDhhmmss + HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH = 3, + HLS_START_SEQUENCE_LAST, // unused } StartSequenceSourceType; typedef enum { @@ -66,6 +69,7 @@ typedef enum { #define KEYSIZE 16 #define LINE_BUFFER_SIZE MAX_URL_SIZE #define HLS_MICROSECOND_UNIT 1000000 +#define BUFSIZE (16 * 1024) #define POSTFIX_PATTERN "_%d" typedef struct HLSSegment { @@ -116,6 +120,7 @@ typedef struct VariantStream { ff_const59 AVOutputFormat *oformat; ff_const59 AVOutputFormat *vtt_oformat; AVIOContext *out; + AVIOContext *out_single_file; int packets_written; int init_range_length; uint8_t *temp_buffer; @@ -146,6 +151,7 @@ typedef struct VariantStream { HLSSegment *last_segment; HLSSegment *old_segments; + char *basename_tmp; char *basename; char *vtt_basename; char *vtt_m3u8_name; @@ -157,24 +163,30 @@ typedef struct VariantStream { char *fmp4_init_filename; char *base_output_dirname; + int encrypt_started; + + char key_file[LINE_BUFFER_SIZE + 1]; + char key_uri[LINE_BUFFER_SIZE + 1]; + char key_string[KEYSIZE*2 + 1]; + char iv_string[KEYSIZE*2 + 1]; + AVStream **streams; char codec_attr[128]; CodecAttributeStatus attr_status; unsigned int nb_streams; int m3u8_created; /* status of media play-list creation */ int is_default; /* default status of audio group */ - char *language; /* audio lauguage name */ - char *agroup; /* audio group name */ - char *sgroup; /* subtitle group name */ - char *ccgroup; /* closed caption group name */ - char *baseurl; - char *varname; // variant name + const char *language; /* audio lauguage name */ + const char *agroup; /* audio group name */ + const char *sgroup; /* subtitle group name */ + const char *ccgroup; /* closed caption group name */ + const char *varname; /* variant name */ } VariantStream; typedef struct ClosedCaptionsStream { - char *ccgroup; /* closed caption group name */ - char *instreamid; /* closed captions INSTREAM-ID */ - char *language; /* closed captions langauge */ + const char *ccgroup; /* closed caption group name */ + const char *instreamid; /* closed captions INSTREAM-ID */ + const char *language; /* closed captions langauge */ } ClosedCaptionsStream; typedef struct HLSContext { @@ -356,11 +368,11 @@ fail: static int replace_str_data_in_filename(char **s, const char *filename, char placeholder, const char *datastring) { const char *p; - char *new_filename; char c; int addchar_count; int found_count = 0; AVBPrint buf; + int ret; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); @@ -386,22 +398,21 @@ static int replace_str_data_in_filename(char **s, const char *filename, char pla } if (!av_bprint_is_complete(&buf)) { av_bprint_finalize(&buf, NULL); - return -1; + return AVERROR(ENOMEM); } - if (av_bprint_finalize(&buf, &new_filename) < 0 || !new_filename) - return -1; - *s = new_filename; + if ((ret = av_bprint_finalize(&buf, s)) < 0) + return ret; return found_count; } static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number) { const char *p; - char *new_filename; char c; int nd, addchar_count; int found_count = 0; AVBPrint buf; + int ret; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); @@ -435,11 +446,10 @@ static int replace_int_data_in_filename(char **s, const char *filename, char pla } if (!av_bprint_is_complete(&buf)) { av_bprint_finalize(&buf, NULL); - return -1; + return AVERROR(ENOMEM); } - if (av_bprint_finalize(&buf, &new_filename) < 0 || !new_filename) - return -1; - *s = new_filename; + if ((ret = av_bprint_finalize(&buf, s)) < 0) + return ret; return found_count; } @@ -515,10 +525,10 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, int ret = 0; int segment_cnt = 0; AVBPrint path; - char *dirname = NULL; + const char *dirname = NULL; char *dirname_r = NULL; char *dirname_repl = NULL; - char *vtt_dirname = NULL; + const char *vtt_dirname = NULL; char *vtt_dirname_r = NULL; const char *proto = NULL; @@ -549,7 +559,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, if (segment && !hls->use_localtime_mkdir) { dirname_r = hls->segment_filename ? av_strdup(hls->segment_filename): av_strdup(vs->avf->url); - dirname = (char*)av_dirname(dirname_r); + dirname = av_dirname(dirname_r); } /* if %v is present in the file's directory @@ -588,7 +598,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, if ((segment->sub_filename[0] != '\0')) { vtt_dirname_r = av_strdup(vs->vtt_avf->url); - vtt_dirname = (char*)av_dirname(vtt_dirname_r); + vtt_dirname = av_dirname(vtt_dirname_r); av_bprint_clear(&path); av_bprintf(&path, "%s%c%s", vtt_dirname, SEPARATOR, @@ -705,7 +715,7 @@ static int do_encrypt(AVFormatContext *s, VariantStream *vs) } -static int hls_encryption_start(AVFormatContext *s) +static int hls_encryption_start(AVFormatContext *s, VariantStream *vs) { HLSContext *hls = s->priv_data; int ret; @@ -722,44 +732,44 @@ static int hls_encryption_start(AVFormatContext *s) return ret; } - ff_get_line(pb, hls->key_uri, sizeof(hls->key_uri)); - hls->key_uri[strcspn(hls->key_uri, "\r\n")] = '\0'; + ff_get_line(pb, vs->key_uri, sizeof(vs->key_uri)); + vs->key_uri[strcspn(vs->key_uri, "\r\n")] = '\0'; - ff_get_line(pb, hls->key_file, sizeof(hls->key_file)); - hls->key_file[strcspn(hls->key_file, "\r\n")] = '\0'; + ff_get_line(pb, vs->key_file, sizeof(vs->key_file)); + vs->key_file[strcspn(vs->key_file, "\r\n")] = '\0'; - ff_get_line(pb, hls->iv_string, sizeof(hls->iv_string)); - hls->iv_string[strcspn(hls->iv_string, "\r\n")] = '\0'; + ff_get_line(pb, vs->iv_string, sizeof(vs->iv_string)); + vs->iv_string[strcspn(vs->iv_string, "\r\n")] = '\0'; ff_format_io_close(s, &pb); - if (!*hls->key_uri) { + if (!*vs->key_uri) { av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n"); return AVERROR(EINVAL); } - if (!*hls->key_file) { + if (!*vs->key_file) { av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n"); return AVERROR(EINVAL); } set_http_options(s, &options, hls); - ret = s->io_open(s, &pb, hls->key_file, AVIO_FLAG_READ, &options); + ret = s->io_open(s, &pb, vs->key_file, AVIO_FLAG_READ, &options); av_dict_free(&options); if (ret < 0) { - av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", hls->key_file); + av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", vs->key_file); return ret; } ret = avio_read(pb, key, sizeof(key)); ff_format_io_close(s, &pb); if (ret != sizeof(key)) { - av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", hls->key_file); + av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", vs->key_file); if (ret >= 0 || ret == AVERROR_EOF) ret = AVERROR(EINVAL); return ret; } - ff_data_to_hex(hls->key_string, key, sizeof(key), 0); + ff_data_to_hex(vs->key_string, key, sizeof(key), 0); return 0; } @@ -783,7 +793,6 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) if (!oc->url) return AVERROR(ENOMEM); - oc->oformat = vs->oformat; oc->interrupt_callback = s->interrupt_callback; oc->max_delay = s->max_delay; oc->opaque = s->opaque; @@ -797,7 +806,6 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) if (ret < 0) return ret; vtt_oc = vs->vtt_avf; - vtt_oc->oformat = vs->vtt_oformat; av_dict_copy(&vtt_oc->metadata, s->metadata, 0); } @@ -825,7 +833,6 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) av_dict_copy(&st->metadata, vs->streams[i]->metadata, 0); } - vs->packets_written = 1; vs->start_pos = 0; vs->new_start = 1; @@ -840,9 +847,6 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) } } - vs->packets_written = 0; - vs->init_range_length = 0; - if ((ret = avio_open_dyn_buf(&oc->pb)) < 0) return ret; @@ -1081,8 +1085,8 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, } if (hls->key_info_file || hls->encrypt) { - av_strlcpy(en->key_uri, hls->key_uri, sizeof(en->key_uri)); - av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string)); + av_strlcpy(en->key_uri, vs->key_uri, sizeof(en->key_uri)); + av_strlcpy(en->iv_string, vs->iv_string, sizeof(en->iv_string)); } if (!vs->segments) @@ -1170,9 +1174,9 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs ptr += strlen("URI=\""); end = av_stristr(ptr, ","); if (end) { - av_strlcpy(hls->key_uri, ptr, end - ptr); + av_strlcpy(vs->key_uri, ptr, end - ptr); } else { - av_strlcpy(hls->key_uri, ptr, sizeof(hls->key_uri)); + av_strlcpy(vs->key_uri, ptr, sizeof(vs->key_uri)); } } @@ -1181,9 +1185,9 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs ptr += strlen("IV=0x"); end = av_stristr(ptr, ","); if (end) { - av_strlcpy(hls->iv_string, ptr, end - ptr); + av_strlcpy(vs->iv_string, ptr, end - ptr); } else { - av_strlcpy(hls->iv_string, ptr, sizeof(hls->iv_string)); + av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string)); } } @@ -1287,8 +1291,8 @@ static int create_master_playlist(AVFormatContext *s, int ret, bandwidth; const char *m3u8_rel_name = NULL; const char *vtt_m3u8_rel_name = NULL; - char *ccgroup; - char *sgroup = NULL; + const char *ccgroup; + const char *sgroup = NULL; ClosedCaptionsStream *ccs; const char *proto = avio_find_protocol_name(hls->master_m3u8_url); int is_file_proto = proto && !strcmp(proto, "file"); @@ -1496,7 +1500,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) ff_hls_write_playlist_header(byterange_mode ? hls->m3u8_out : vs->out, hls->version, hls->allowcache, target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY); - if ((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ) { + if ((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0) { avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "#EXT-X-DISCONTINUITY\n"); vs->discontinuity_set = 1; } @@ -1521,7 +1525,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) ret = ff_hls_write_file_entry(byterange_mode ? hls->m3u8_out : vs->out, en->discont, byterange_mode, en->duration, hls->flags & HLS_ROUND_DURATIONS, - en->size, en->pos, vs->baseurl, + en->size, en->pos, hls->baseurl, en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY); if (ret < 0) { av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); @@ -1543,7 +1547,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) for (en = vs->segments; en; en = en->next) { ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode, en->duration, 0, en->size, en->pos, - vs->baseurl, en->sub_filename, NULL, 0, 0, 0); + hls->baseurl, en->sub_filename, NULL, 0, 0, 0); if (ret < 0) { av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } @@ -1632,6 +1636,8 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) if (c->use_localtime_mkdir) { const char *dir; char *fn_copy = av_strdup(oc->url); + if (!fn_copy) + return AVERROR(ENOMEM); dir = av_dirname(fn_copy); if (ff_mkdir_p(dir) == -1 && errno != EEXIST) { av_log(oc, AV_LOG_ERROR, "Could not create directory %s with use_localtime_mkdir\n", dir); @@ -1654,7 +1660,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) } ff_format_set_url(oc, filename); } - if ( vs->vtt_basename) { + if (vs->vtt_basename) { char *filename = NULL; if (replace_int_data_in_filename(&filename, #if FF_API_HLS_WRAP @@ -1669,7 +1675,6 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) ff_format_set_url(vtt_oc, filename); } } - vs->number++; proto = avio_find_protocol_name(oc->url); use_temp_file = proto && !strcmp(proto, "file") && (c->flags & HLS_TEMP_FILE); @@ -1692,21 +1697,27 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) " ignoring -hls_enc\n"); } - if (!c->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { + if (!vs->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { if (c->key_info_file) { - if ((err = hls_encryption_start(s)) < 0) + if ((err = hls_encryption_start(s, vs)) < 0) goto fail; } else { - if ((err = do_encrypt(s, vs)) < 0) - goto fail; + if (!c->encrypt_started) { + if ((err = do_encrypt(s, vs)) < 0) + goto fail; + c->encrypt_started = 1; + } + av_strlcpy(vs->key_uri, c->key_uri, sizeof(vs->key_uri)); + av_strlcpy(vs->key_string, c->key_string, sizeof(vs->key_string)); + av_strlcpy(vs->iv_string, c->iv_string, sizeof(vs->iv_string)); } - c->encrypt_started = 1; + vs->encrypt_started = 1; } - err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string)); + err = av_strlcpy(iv_string, vs->iv_string, sizeof(iv_string)); if (!err) { snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence); - memset(c->iv_string, 0, sizeof(c->iv_string)); - memcpy(c->iv_string, iv_string, sizeof(iv_string)); + memset(vs->iv_string, 0, sizeof(vs->iv_string)); + memcpy(vs->iv_string, iv_string, sizeof(iv_string)); } } if (c->segment_type != SEGMENT_TYPE_FMP4) { @@ -1714,12 +1725,34 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0); } if (c->flags & HLS_SINGLE_FILE) { + if (c->key_info_file || c->encrypt) { + av_dict_set(&options, "encryption_key", vs->key_string, 0); + av_dict_set(&options, "encryption_iv", vs->iv_string, 0); + + /* Write temp file with cryption content */ + av_freep(&vs->basename_tmp); + vs->basename_tmp = av_asprintf("crypto:%s.tmp", oc->url); + + /* append temp file content into single file */ + av_freep(&vs->basename); + vs->basename = av_asprintf("%s", oc->url); + } else { + vs->basename_tmp = vs->basename; + } set_http_options(s, &options, c); - if ((err = hlsenc_io_open(s, &vs->out, oc->url, &options)) < 0) { + if (!vs->out_single_file) + if ((err = hlsenc_io_open(s, &vs->out_single_file, vs->basename, &options)) < 0) { + if (c->ignore_io_errors) + err = 0; + goto fail; + } + + if ((err = hlsenc_io_open(s, &vs->out, vs->basename_tmp, &options)) < 0) { if (c->ignore_io_errors) err = 0; goto fail; } + } } if (vs->vtt_basename) { @@ -1786,12 +1819,12 @@ static int validate_name(int nb_vs, const char *fn) char *fn_dup = NULL; int ret = 0; - if (!fn) { - ret = AVERROR(EINVAL); - goto fail; - } + if (!fn) + return AVERROR(EINVAL); fn_dup = av_strdup(fn); + if (!fn_dup) + return AVERROR(ENOMEM); filename = av_basename(fn); subdir_name = av_dirname(fn_dup); @@ -1821,14 +1854,12 @@ static int format_name(const char *buf, char **s, int index, const char *varname int ret = 0; orig_buf_dup = av_strdup(buf); - if (!orig_buf_dup) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!orig_buf_dup) + return AVERROR(ENOMEM); if (!av_stristr(buf, "%v")) { *s = orig_buf_dup; - return ret; + return 0; } if (!varname) { @@ -1864,7 +1895,7 @@ fail: static int get_nth_codec_stream_index(AVFormatContext *s, enum AVMediaType codec_type, - int stream_id) + int64_t stream_id) { unsigned int stream_index, cnt; if (stream_id < 0 || stream_id > s->nb_streams - 1) @@ -1935,10 +1966,13 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) return AVERROR(EINVAL); q = varstr; - while (q < varstr + strlen(varstr)) { + while (1) { if (!av_strncasecmp(q, "a:", 2) || !av_strncasecmp(q, "v:", 2) || !av_strncasecmp(q, "s:", 2)) vs->nb_streams++; + q = strchr(q, ','); + if (!q) + break; q++; } vs->streams = av_mallocz(sizeof(AVStream *) * vs->nb_streams); @@ -1947,12 +1981,11 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) nb_streams = 0; while (keyval = av_strtok(varstr, ",", &saveptr2)) { + int64_t num; + char *end; varstr = NULL; if (av_strstart(keyval, "language:", &val)) { - av_free(vs->language); - vs->language = av_strdup(val); - if (!vs->language) - return AVERROR(ENOMEM); + vs->language = val; continue; } else if (av_strstart(keyval, "default:", &val)) { vs->is_default = (!av_strncasecmp(val, "YES", strlen("YES")) || @@ -1960,28 +1993,16 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) hls->has_default_key = 1; continue; } else if (av_strstart(keyval, "name:", &val)) { - av_free(vs->varname); - vs->varname = av_strdup(val); - if (!vs->varname) - return AVERROR(ENOMEM); + vs->varname = val; continue; } else if (av_strstart(keyval, "agroup:", &val)) { - av_free(vs->agroup); - vs->agroup = av_strdup(val); - if (!vs->agroup) - return AVERROR(ENOMEM); + vs->agroup = val; continue; } else if (av_strstart(keyval, "sgroup:", &val)) { - av_free(vs->sgroup); - vs->sgroup = av_strdup(val); - if (!vs->sgroup) - return AVERROR(ENOMEM); + vs->sgroup = val; continue; } else if (av_strstart(keyval, "ccgroup:", &val)) { - av_free(vs->ccgroup); - vs->ccgroup = av_strdup(val); - if (!vs->ccgroup) - return AVERROR(ENOMEM); + vs->ccgroup = val; continue; } else if (av_strstart(keyval, "v:", &val)) { codec_type = AVMEDIA_TYPE_VIDEO; @@ -1995,10 +2016,12 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) return AVERROR(EINVAL); } - stream_index = -1; - if (av_isdigit(*val)) - stream_index = get_nth_codec_stream_index (s, codec_type, - atoi(val)); + num = strtoll(val, &end, 10); + if (!av_isdigit(*val) || *end != '\0') { + av_log(s, AV_LOG_ERROR, "Invalid stream number: '%s'\n", val); + return AVERROR(EINVAL); + } + stream_index = get_nth_codec_stream_index(s, codec_type, num); if (stream_index >= 0 && nb_streams < vs->nb_streams) { for (i = 0; nb_streams > 0 && i < nb_streams; i++) { @@ -2070,20 +2093,11 @@ static int parse_cc_stream_mapstring(AVFormatContext *s) ccstr = NULL; if (av_strstart(keyval, "ccgroup:", &val)) { - av_free(ccs->ccgroup); - ccs->ccgroup = av_strdup(val); - if (!ccs->ccgroup) - return AVERROR(ENOMEM); + ccs->ccgroup = val; } else if (av_strstart(keyval, "instreamid:", &val)) { - av_free(ccs->instreamid); - ccs->instreamid = av_strdup(val); - if (!ccs->instreamid) - return AVERROR(ENOMEM); + ccs->instreamid = val; } else if (av_strstart(keyval, "language:", &val)) { - av_free(ccs->language); - ccs->language = av_strdup(val); - if (!ccs->language) - return AVERROR(ENOMEM); + ccs->language = val; } else { av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval); return AVERROR(EINVAL); @@ -2142,17 +2156,12 @@ static int update_variant_stream_info(AVFormatContext *s) hls->var_streams[0].nb_streams = s->nb_streams; hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) * hls->var_streams[0].nb_streams); - if (!hls->var_streams[0].streams) { + if (!hls->var_streams[0].streams) return AVERROR(ENOMEM); - } //by default, the first available ccgroup is mapped to the variant stream - if (hls->nb_ccstreams) { - hls->var_streams[0].ccgroup = av_strdup(hls->cc_streams[0].ccgroup); - if (!hls->var_streams[0].ccgroup) { - return AVERROR(ENOMEM); - } - } + if (hls->nb_ccstreams) + hls->var_streams[0].ccgroup = hls->cc_streams[0].ccgroup; for (i = 0; i < s->nb_streams; i++) hls->var_streams[0].streams[i] = s->streams[i]; @@ -2168,6 +2177,8 @@ static int update_master_pl_info(AVFormatContext *s) int ret = 0; fn1 = av_strdup(s->url); + if (!fn1) + return AVERROR(ENOMEM); dir = av_dirname(fn1); /** @@ -2176,6 +2187,10 @@ static int update_master_pl_info(AVFormatContext *s) */ if (dir && av_stristr(av_basename(dir), "%v")) { fn2 = av_strdup(dir); + if (!fn2) { + ret = AVERROR(ENOMEM); + goto fail; + } dir = av_dirname(fn2); } @@ -2258,7 +2273,7 @@ static int hls_init_file_resend(AVFormatContext *s, VariantStream *vs) int ret = 0; set_http_options(s, &options, hls); - ret = hlsenc_io_open(s, &vs->out, hls->fmp4_init_filename, &options); + ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options); av_dict_free(&options); if (ret < 0) return ret; @@ -2268,6 +2283,38 @@ static int hls_init_file_resend(AVFormatContext *s, VariantStream *vs) return ret; } +static int64_t append_single_file(AVFormatContext *s, VariantStream *vs) +{ + int ret = 0; + int64_t read_byte = 0; + int64_t total_size = 0; + char *filename = NULL; + char buf[BUFSIZE]; + AVFormatContext *oc = vs->avf; + + hlsenc_io_close(s, &vs->out, vs->basename_tmp); + filename = av_asprintf("%s.tmp", oc->url); + ret = s->io_open(s, &vs->out, filename, AVIO_FLAG_READ, NULL); + if (ret < 0) { + av_free(filename); + return ret; + } + + do { + memset(buf, 0, sizeof(BUFSIZE)); + read_byte = avio_read(vs->out, buf, BUFSIZE); + avio_write(vs->out_single_file, buf, read_byte); + if (read_byte > 0) { + total_size += read_byte; + ret = total_size; + } + } while (read_byte > 0); + + hlsenc_io_close(s, &vs->out, filename); + av_free(filename); + + return ret; +} static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) { HLSContext *hls = s->priv_data; @@ -2287,7 +2334,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs = &hls->var_streams[i]; for (j = 0; j < vs->nb_streams; j++) { if (vs->streams[j] == st) { - if ( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { oc = vs->vtt_avf; stream_index = 0; } else { @@ -2312,7 +2359,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (vs->sequence - vs->nb_entries > hls->start_sequence && hls->init_time > 0) { /* reset end_pts, hls->recording_time at end of the init hls list */ int64_t init_list_dur = hls->init_time * vs->nb_entries * AV_TIME_BASE; - int64_t after_init_list_dur = (vs->sequence - hls->start_sequence - vs->nb_entries ) * (hls->time * AV_TIME_BASE); + int64_t after_init_list_dur = (vs->sequence - hls->start_sequence - vs->nb_entries) * (hls->time * AV_TIME_BASE); hls->recording_time = hls->time * AV_TIME_BASE; end_pts = init_list_dur + after_init_list_dur ; } @@ -2327,7 +2374,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs->start_pts_from_audio = 0; } - if (vs->has_video) { + if (vs->has_video) { can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME)); is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index); @@ -2386,11 +2433,6 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } } - if (oc->url[0]) { - proto = avio_find_protocol_name(oc->url); - use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE); - } - if (hls->flags & HLS_SINGLE_FILE) { ret = flush_dynbuf(vs, &range_length); av_freep(&vs->temp_buffer); @@ -2398,13 +2440,21 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } vs->size = range_length; + if (hls->key_info_file || hls->encrypt) + vs->size = append_single_file(s, vs); } else { - if ((hls->max_seg_size > 0 && (vs->size >= hls->max_seg_size)) || !byterange_mode) { + if (oc->url[0]) { + proto = avio_find_protocol_name(oc->url); + use_temp_file = proto && !strcmp(proto, "file") + && (hls->flags & HLS_TEMP_FILE); + } + + if ((hls->max_seg_size > 0 && (vs->size + vs->start_pos >= hls->max_seg_size)) || !byterange_mode) { AVDictionary *options = NULL; char *filename = NULL; if (hls->key_info_file || hls->encrypt) { - av_dict_set(&options, "encryption_key", hls->key_string, 0); - av_dict_set(&options, "encryption_iv", hls->iv_string, 0); + av_dict_set(&options, "encryption_key", vs->key_string, 0); + av_dict_set(&options, "encryption_iv", vs->iv_string, 0); filename = av_asprintf("crypto:%s", oc->url); } else { filename = av_asprintf("%s", oc->url); @@ -2424,6 +2474,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (ret < 0) { av_log(s, hls->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR, "Failed to open file '%s'\n", filename); + av_freep(&filename); av_dict_free(&options); return hls->ignore_io_errors ? 0 : ret; } @@ -2432,6 +2483,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } ret = flush_dynbuf(vs, &range_length); if (ret < 0) { + av_freep(&filename); av_dict_free(&options); return ret; } @@ -2448,10 +2500,9 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) av_freep(&vs->temp_buffer); av_freep(&filename); } - } - if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) { - hls_rename_temp_file(s, oc); + if (use_temp_file) + hls_rename_temp_file(s, oc); } old_filename = av_strdup(oc->url); @@ -2460,7 +2511,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) { - ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); + double cur_duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; + ret = hls_append_segment(s, hls, vs, cur_duration, vs->start_pos, vs->size); vs->end_pts = pkt->pts; vs->duration = 0; if (ret < 0) { @@ -2474,7 +2526,6 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if ((ret = hls_window(s, 0, vs)) < 0) { av_log(s, AV_LOG_WARNING, "upload playlist failed, will retry with a new http session.\n"); ff_format_io_close(s, &vs->out); - vs->out = NULL; if ((ret = hls_window(s, 0, vs)) < 0) { av_freep(&old_filename); return ret; @@ -2491,25 +2542,26 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } if (hls->flags & HLS_SINGLE_FILE) { - vs->number++; vs->start_pos += vs->size; + if (hls->key_info_file || hls->encrypt) + ret = hls_start(s, vs); } else if (hls->max_seg_size > 0) { - vs->start_pos = new_start_pos; - if (vs->size >= hls->max_seg_size) { + if (vs->size + vs->start_pos >= hls->max_seg_size) { vs->sequence++; sls_flag_file_rename(hls, vs, old_filename); ret = hls_start(s, vs); vs->start_pos = 0; /* When split segment by byte, the duration is short than hls_time, * so it is not enough one segment duration as hls_time, */ - vs->number--; + } else { + vs->start_pos = new_start_pos; } - vs->number++; } else { vs->start_pos = new_start_pos; sls_flag_file_rename(hls, vs, old_filename); ret = hls_start(s, vs); } + vs->number++; av_freep(&old_filename); if (ret < 0) { @@ -2534,25 +2586,22 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } -static void hls_free_variant_streams(struct HLSContext *hls) +static void hls_deinit(AVFormatContext *s) { + HLSContext *hls = s->priv_data; int i = 0; - AVFormatContext *vtt_oc = NULL; VariantStream *vs = NULL; for (i = 0; i < hls->nb_varstreams; i++) { vs = &hls->var_streams[i]; - vtt_oc = vs->vtt_avf; av_freep(&vs->basename); av_freep(&vs->base_output_dirname); av_freep(&vs->fmp4_init_filename); - if (vtt_oc) { - av_freep(&vs->vtt_basename); - av_freep(&vs->vtt_m3u8_name); - avformat_free_context(vtt_oc); - } + av_freep(&vs->vtt_basename); + av_freep(&vs->vtt_m3u8_name); + avformat_free_context(vs->vtt_avf); avformat_free_context(vs->avf); if (hls->resend_init_file) av_freep(&vs->init_buffer); @@ -2560,13 +2609,14 @@ static void hls_free_variant_streams(struct HLSContext *hls) hls_free_segments(vs->old_segments); av_freep(&vs->m3u8_name); av_freep(&vs->streams); - av_freep(&vs->agroup); - av_freep(&vs->sgroup); - av_freep(&vs->language); - av_freep(&vs->ccgroup); - av_freep(&vs->baseurl); - av_freep(&vs->varname); } + + ff_format_io_close(s, &hls->m3u8_out); + ff_format_io_close(s, &hls->sub_m3u8_out); + av_freep(&hls->key_basename); + av_freep(&hls->var_streams); + av_freep(&hls->cc_streams); + av_freep(&hls->master_m3u8_url); } static int hls_write_trailer(struct AVFormatContext *s) @@ -2595,8 +2645,8 @@ static int hls_write_trailer(struct AVFormatContext *s) return AVERROR(ENOMEM); } if (hls->key_info_file || hls->encrypt) { - av_dict_set(&options, "encryption_key", hls->key_string, 0); - av_dict_set(&options, "encryption_iv", hls->iv_string, 0); + av_dict_set(&options, "encryption_key", vs->key_string, 0); + av_dict_set(&options, "encryption_iv", vs->iv_string, 0); filename = av_asprintf("crypto:%s", oc->url); } else { filename = av_asprintf("%s", oc->url); @@ -2606,7 +2656,7 @@ static int hls_write_trailer(struct AVFormatContext *s) return AVERROR(ENOMEM); } - if ( hls->segment_type == SEGMENT_TYPE_FMP4) { + if (hls->segment_type == SEGMENT_TYPE_FMP4) { int range_length = 0; if (!vs->init_range_length) { uint8_t *buffer = NULL; @@ -2641,7 +2691,6 @@ static int hls_write_trailer(struct AVFormatContext *s) goto failed; vs->size = range_length; - hlsenc_io_close(s, &vs->out, filename); ret = hlsenc_io_close(s, &vs->out, filename); if (ret < 0) { av_log(s, AV_LOG_WARNING, "upload segment failed, will retry with a new http session.\n"); @@ -2656,9 +2705,15 @@ static int hls_write_trailer(struct AVFormatContext *s) if (ret < 0) av_log(s, AV_LOG_WARNING, "Failed to upload file '%s' at the end.\n", oc->url); } - av_freep(&vs->temp_buffer); - + if (hls->flags & HLS_SINGLE_FILE) { + if (hls->key_info_file || hls->encrypt) { + vs->size = append_single_file(s, vs); + } + hlsenc_io_close(s, &vs->out_single_file, vs->basename); + } failed: + av_freep(&vs->temp_buffer); + av_dict_free(&options); av_freep(&filename); av_write_trailer(oc); if (oc->url[0]) { @@ -2699,21 +2754,6 @@ failed: av_free(old_filename); } - hls_free_variant_streams(hls); - - for (i = 0; i < hls->nb_ccstreams; i++) { - ClosedCaptionsStream *ccs = &hls->cc_streams[i]; - av_freep(&ccs->ccgroup); - av_freep(&ccs->instreamid); - av_freep(&ccs->language); - } - - ff_format_io_close(s, &hls->m3u8_out); - ff_format_io_close(s, &hls->sub_m3u8_out); - av_freep(&hls->key_basename); - av_freep(&hls->var_streams); - av_freep(&hls->cc_streams); - av_freep(&hls->master_m3u8_url); return 0; } @@ -2724,15 +2764,21 @@ static int hls_init(AVFormatContext *s) int i = 0; int j = 0; HLSContext *hls = s->priv_data; - const char *pattern = "%d.ts"; + const char *pattern; VariantStream *vs = NULL; - int basename_size = 0; - const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s); - const char *vtt_pattern = "%d.vtt"; + const char *vtt_pattern = hls->flags & HLS_SINGLE_FILE ? ".vtt" : "%d.vtt"; char *p = NULL; - int vtt_basename_size = 0; int http_base_proto = ff_is_http_proto(s->url); int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; + double initial_program_date_time = av_gettime() / 1000000.0; + + if (hls->use_localtime) { + pattern = get_default_pattern_localtime_fmt(s); + } else { + pattern = hls->segment_type == SEGMENT_TYPE_FMP4 ? "%d.m4s" : "%d.ts"; + if (hls->flags & HLS_SINGLE_FILE) + pattern += 2; + } hls->has_default_key = 0; hls->has_video_m3u8 = 0; @@ -2740,13 +2786,7 @@ static int hls_init(AVFormatContext *s) if (ret < 0) { av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n", ret); - goto fail; - } - //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present - if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) { - ret = AVERROR(EINVAL); - av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n"); - goto fail; + return ret; } if (!hls->method && http_base_proto) { @@ -2755,24 +2795,24 @@ static int hls_init(AVFormatContext *s) ret = validate_name(hls->nb_varstreams, s->url); if (ret < 0) - goto fail; + return ret; if (hls->segment_filename) { ret = validate_name(hls->nb_varstreams, hls->segment_filename); if (ret < 0) - goto fail; + return ret; } if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { ret = validate_name(hls->nb_varstreams, hls->fmp4_init_filename); if (ret < 0) - goto fail; + return ret; } if (hls->subtitle_filename) { ret = validate_name(hls->nb_varstreams, hls->subtitle_filename); if (ret < 0) - goto fail; + return ret; } if (hls->master_pl_name) { @@ -2780,17 +2820,17 @@ static int hls_init(AVFormatContext *s) if (ret < 0) { av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n", ret); - goto fail; + return ret; } } - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - pattern = "%d.m4s"; - } if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) || + (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH) || (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) { - time_t t = time(NULL); // we will need it in either case - if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) { + time_t t = time(NULL); + if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH) { + hls->start_sequence = av_gettime(); + } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) { hls->start_sequence = (int64_t)t; } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) { char b[15]; @@ -2805,31 +2845,27 @@ static int hls_init(AVFormatContext *s) } hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; + + if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) { + // Independent segments cannot be guaranteed when splitting by time + hls->flags &= ~HLS_INDEPENDENT_SEGMENTS; + av_log(s, AV_LOG_WARNING, + "'split_by_time' and 'independent_segments' cannot be " + "enabled together. Disabling 'independent_segments' flag\n"); + } + for (i = 0; i < hls->nb_varstreams; i++) { vs = &hls->var_streams[i]; ret = format_name(s->url, &vs->m3u8_name, i, vs->varname); if (ret < 0) - goto fail; + return ret; - vs->sequence = hls->start_sequence; - vs->start_pts = AV_NOPTS_VALUE; - vs->end_pts = AV_NOPTS_VALUE; + vs->sequence = hls->start_sequence; + vs->start_pts = AV_NOPTS_VALUE; + vs->end_pts = AV_NOPTS_VALUE; vs->current_segment_final_filename_fmt[0] = '\0'; - - if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) { - // Independent segments cannot be guaranteed when splitting by time - hls->flags &= ~HLS_INDEPENDENT_SEGMENTS; - av_log(s, AV_LOG_WARNING, - "'split_by_time' and 'independent_segments' cannot be enabled together. " - "Disabling 'independent_segments' flag\n"); - } - - if (hls->flags & HLS_PROGRAM_DATE_TIME) { - time_t now0; - time(&now0); - vs->initial_prog_date_time = now0; - } + vs->initial_prog_date_time = initial_program_date_time; for (j = 0; j < vs->nb_streams; j++) { vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; @@ -2848,54 +2884,24 @@ static int hls_init(AVFormatContext *s) } else { vs->oformat = av_guess_format("mpegts", NULL, NULL); } + if (!vs->oformat) + return AVERROR_MUXER_NOT_FOUND; - if (!vs->oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; - } - - if (vs->has_subtitle) { - vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL); - if (!vs->vtt_oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; - } - } if (hls->segment_filename) { ret = format_name(hls->segment_filename, &vs->basename, i, vs->varname); if (ret < 0) - goto fail; + return ret; } else { - if (hls->flags & HLS_SINGLE_FILE) { - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - pattern = ".m4s"; - } else { - pattern = ".ts"; - } - } - - if (hls->use_localtime) { - basename_size = strlen(vs->m3u8_name) + strlen(pattern_localtime_fmt) + 1; - } else { - basename_size = strlen(vs->m3u8_name) + strlen(pattern) + 1; - } - - vs->basename = av_malloc(basename_size); - if (!vs->basename) { - ret = AVERROR(ENOMEM); - goto fail; - } + p = strrchr(vs->m3u8_name, '.'); + if (p) + *p = '\0'; - av_strlcpy(vs->basename, vs->m3u8_name, basename_size); + vs->basename = av_asprintf("%s%s", vs->m3u8_name, pattern); + if (!vs->basename) + return AVERROR(ENOMEM); - p = strrchr(vs->basename, '.'); if (p) - *p = '\0'; - if (hls->use_localtime) { - av_strlcat(vs->basename, pattern_localtime_fmt, basename_size); - } else { - av_strlcat(vs->basename, pattern, basename_size); - } + *p = '.'; } if (hls->segment_type == SEGMENT_TYPE_FMP4) { @@ -2903,96 +2909,73 @@ static int hls_init(AVFormatContext *s) fmp4_init_filename_len += strlen(POSTFIX_PATTERN); if (hls->flags & HLS_SINGLE_FILE) { vs->fmp4_init_filename = av_strdup(vs->basename); - if (!vs->fmp4_init_filename) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!vs->fmp4_init_filename) + return AVERROR(ENOMEM); } else { vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len); - if (!vs->fmp4_init_filename ) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!vs->fmp4_init_filename) + return AVERROR(ENOMEM); av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename, fmp4_init_filename_len); if (hls->nb_varstreams > 1) { if (av_stristr(vs->fmp4_init_filename, "%v")) { av_freep(&vs->fmp4_init_filename); - format_name(hls->fmp4_init_filename, &vs->fmp4_init_filename, i, vs->varname); + ret = format_name(hls->fmp4_init_filename, + &vs->fmp4_init_filename, i, vs->varname); } else { ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); } if (ret < 0) - goto fail; - } - - fmp4_init_filename_len = strlen(vs->m3u8_name) + - strlen(vs->fmp4_init_filename) + 1; - - vs->base_output_dirname = av_malloc(fmp4_init_filename_len); - if (!vs->base_output_dirname) { - ret = AVERROR(ENOMEM); - goto fail; + return ret; } - av_strlcpy(vs->base_output_dirname, vs->m3u8_name, - fmp4_init_filename_len); - p = strrchr(vs->base_output_dirname, '/'); + p = strrchr(vs->m3u8_name, '/'); if (p) { - *(p + 1) = '\0'; - av_strlcat(vs->base_output_dirname, vs->fmp4_init_filename, - fmp4_init_filename_len); + char tmp = *(++p); + *p = '\0'; + vs->base_output_dirname = av_asprintf("%s%s", vs->m3u8_name, + vs->fmp4_init_filename); + *p = tmp; } else { - av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename, - fmp4_init_filename_len); + vs->base_output_dirname = av_strdup(vs->fmp4_init_filename); } + if (!vs->base_output_dirname) + return AVERROR(ENOMEM); } } ret = hls->use_localtime ? sls_flag_check_duration_size(hls, vs) : sls_flag_check_duration_size_index(hls); if (ret < 0) - goto fail; + return ret; if (vs->has_subtitle) { + vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL); + if (!vs->vtt_oformat) + return AVERROR_MUXER_NOT_FOUND; - if (hls->flags & HLS_SINGLE_FILE) - vtt_pattern = ".vtt"; - vtt_basename_size = strlen(vs->m3u8_name) + strlen(vtt_pattern) + 1; - - vs->vtt_basename = av_malloc(vtt_basename_size); - if (!vs->vtt_basename) { - ret = AVERROR(ENOMEM); - goto fail; - } - av_strlcpy(vs->vtt_basename, vs->m3u8_name, vtt_basename_size); - p = strrchr(vs->vtt_basename, '.'); + p = strrchr(vs->m3u8_name, '.'); if (p) *p = '\0'; - if ( hls->subtitle_filename ) { + vs->vtt_basename = av_asprintf("%s%s", vs->m3u8_name, vtt_pattern); + if (!vs->vtt_basename) + return AVERROR(ENOMEM); + + if (hls->subtitle_filename) { ret = format_name(hls->subtitle_filename, &vs->vtt_m3u8_name, i, vs->varname); if (ret < 0) - goto fail; + return ret; } else { - vs->vtt_m3u8_name = av_asprintf("%s_vtt.m3u8", vs->vtt_basename); - if (!vs->vtt_m3u8_name) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size); - } - - if (hls->baseurl) { - vs->baseurl = av_strdup(hls->baseurl); - if (!vs->baseurl) { - ret = AVERROR(ENOMEM); - goto fail; + vs->vtt_m3u8_name = av_asprintf("%s_vtt.m3u8", vs->m3u8_name); + if (!vs->vtt_m3u8_name) + return AVERROR(ENOMEM); } + if (p) + *p = '.'; } if ((ret = hls_mux_init(s, vs)) < 0) - goto fail; + return ret; if (hls->flags & HLS_APPEND_LIST) { parse_playlist(s, vs->m3u8_name, vs); @@ -3006,22 +2989,8 @@ static int hls_init(AVFormatContext *s) } if ((ret = hls_start(s, vs)) < 0) - goto fail; - } - -fail: - if (ret < 0) { - hls_free_variant_streams(hls); - for (i = 0; i < hls->nb_ccstreams; i++) { - ClosedCaptionsStream *ccs = &hls->cc_streams[i]; - av_freep(&ccs->ccgroup); - av_freep(&ccs->instreamid); - av_freep(&ccs->language); - } - av_freep(&hls->key_basename); - av_freep(&hls->var_streams); - av_freep(&hls->cc_streams); - av_freep(&hls->master_m3u8_url); + return ret; + vs->number++; } return ret; @@ -3072,7 +3041,7 @@ static const AVOption options[] = { {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"}, #if FF_API_HLS_USE_LOCALTIME - {"use_localtime", "set filename expansion with strftime at segment creation(will be deprecated )", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + {"use_localtime", "set filename expansion with strftime at segment creation(will be deprecated)", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, #endif {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, #if FF_API_HLS_USE_LOCALTIME @@ -3083,9 +3052,10 @@ static const AVOption options[] = { {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" }, {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" }, {"method", "set the HTTP method(default: PUT)", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, - {"hls_start_number_source", "set source of first number in sequence", OFFSET(start_sequence_source_type), AV_OPT_TYPE_INT, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, 0, HLS_START_SEQUENCE_AS_FORMATTED_DATETIME, E, "start_sequence_source_type" }, + {"hls_start_number_source", "set source of first number in sequence", OFFSET(start_sequence_source_type), AV_OPT_TYPE_INT, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, 0, HLS_START_SEQUENCE_LAST-1, E, "start_sequence_source_type" }, {"generic", "start_number value (default)", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, + {"epoch_us", "microseconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, @@ -3120,5 +3090,6 @@ AVOutputFormat ff_hls_muxer = { .write_header = hls_write_header, .write_packet = hls_write_packet, .write_trailer = hls_write_trailer, + .deinit = hls_deinit, .priv_class = &hls_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/hlsplaylist.c b/chromium/third_party/ffmpeg/libavformat/hlsplaylist.c index 43f9d281ba0..0e1dcc087f0 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsplaylist.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsplaylist.c @@ -28,15 +28,18 @@ #include "avformat.h" #include "hlsplaylist.h" -void ff_hls_write_playlist_version(AVIOContext *out, int version) { +void ff_hls_write_playlist_version(AVIOContext *out, int version) +{ if (!out) return; avio_printf(out, "#EXTM3U\n"); avio_printf(out, "#EXT-X-VERSION:%d\n", version); } -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, - const char *filename, char *language, int name_id, int is_default) { +void ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, + const char *filename, const char *language, + int name_id, int is_default) +{ if (!out || !agroup || !filename) return; @@ -48,8 +51,10 @@ void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, avio_printf(out, "URI=\"%s\"\n", filename); } -void ff_hls_write_subtitle_rendition(AVIOContext *out, char *sgroup, - const char *filename, char *language, int name_id, int is_default) { +void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, + const char *filename, const char *language, + int name_id, int is_default) +{ if (!out || !filename) return; @@ -61,10 +66,11 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, char *sgroup, avio_printf(out, "URI=\"%s\"\n", filename); } -void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, - int bandwidth, const char *filename, char *agroup, - char *codecs, char *ccgroup, char *sgroup) { - +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + const char *filename, const char *agroup, + const char *codecs, const char *ccgroup, + const char *sgroup) +{ if (!out || !filename) return; @@ -91,7 +97,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, - uint32_t playlist_type, int iframe_mode) { + uint32_t playlist_type, int iframe_mode) +{ if (!out) return; ff_hls_write_playlist_version(out, version); @@ -112,8 +119,9 @@ void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, } } -void ff_hls_write_init_file(AVIOContext *out, char *filename, - int byterange_mode, int64_t size, int64_t pos) { +void ff_hls_write_init_file(AVIOContext *out, const char *filename, + int byterange_mode, int64_t size, int64_t pos) +{ avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", filename); if (byterange_mode) { avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", size, pos); @@ -122,12 +130,14 @@ void ff_hls_write_init_file(AVIOContext *out, char *filename, } int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, - int byterange_mode, - double duration, int round_duration, - int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set - char *baseurl, //Ignored if NULL - char *filename, double *prog_date_time, - int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode) { + int byterange_mode, double duration, + int round_duration, int64_t size, + int64_t pos /* Used only if HLS_SINGLE_FILE flag is set */, + const char *baseurl /* Ignored if NULL */, + const char *filename, double *prog_date_time, + int64_t video_keyframe_size, int64_t video_keyframe_pos, + int iframe_mode) +{ if (!out || !filename) return AVERROR(EINVAL); @@ -176,7 +186,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, return 0; } -void ff_hls_write_end_list (AVIOContext *out) { +void ff_hls_write_end_list(AVIOContext *out) +{ if (!out) return; avio_printf(out, "#EXT-X-ENDLIST\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/hlsplaylist.h b/chromium/third_party/ffmpeg/libavformat/hlsplaylist.h index a124bdcffb0..29487da3edf 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsplaylist.h +++ b/chromium/third_party/ffmpeg/libavformat/hlsplaylist.h @@ -37,25 +37,29 @@ typedef enum { } PlaylistType; void ff_hls_write_playlist_version(AVIOContext *out, int version); -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, - const char *filename, char *language, int name_id, int is_default); -void ff_hls_write_subtitle_rendition(AVIOContext *out, char *sgroup, - const char *filename, char *language, int name_id, int is_default); -void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, - int bandwidth, const char *filename, char *agroup, - char *codecs, char *ccgroup, char *sgroup); +void ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, + const char *filename, const char *language, + int name_id, int is_default); +void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, + const char *filename, const char *language, + int name_id, int is_default); +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + const char *filename, const char *agroup, + const char *codecs, const char *ccgroup, + const char *sgroup); void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, uint32_t playlist_type, int iframe_mode); -void ff_hls_write_init_file(AVIOContext *out, char *filename, +void ff_hls_write_init_file(AVIOContext *out, const char *filename, int byterange_mode, int64_t size, int64_t pos); int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, - int byterange_mode, - double duration, int round_duration, - int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set - char *baseurl, //Ignored if NULL - char *filename, double *prog_date_time, - int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode); + int byterange_mode, double duration, + int round_duration, int64_t size, + int64_t pos /* Used only if HLS_SINGLE_FILE flag is set */, + const char *baseurl /* Ignored if NULL */, + const char *filename, double *prog_date_time, + int64_t video_keyframe_size, int64_t video_keyframe_pos, + int iframe_mode); void ff_hls_write_end_list (AVIOContext *out); #endif /* AVFORMAT_HLSPLAYLIST_H_ */ diff --git a/chromium/third_party/ffmpeg/libavformat/hlsproto.c b/chromium/third_party/ffmpeg/libavformat/hlsproto.c index e5673e5e035..de45f771d66 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsproto.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsproto.c @@ -178,7 +178,7 @@ static int hls_close(URLContext *h) free_segment_list(s); free_variant_list(s); - ffurl_close(s->seg_hd); + ffurl_closep(&s->seg_hd); return 0; } @@ -260,8 +260,7 @@ start: return ret; } if (s->seg_hd) { - ffurl_close(s->seg_hd); - s->seg_hd = NULL; + ffurl_closep(&s->seg_hd); s->cur_seq_no++; } reload_interval = s->n_segments > 0 ? diff --git a/chromium/third_party/ffmpeg/libavformat/http.c b/chromium/third_party/ffmpeg/libavformat/http.c index c9415578aa1..6c39da1a8b8 100644 --- a/chromium/third_party/ffmpeg/libavformat/http.c +++ b/chromium/third_party/ffmpeg/libavformat/http.c @@ -46,7 +46,7 @@ /* The IO buffer size is unrelated to the max URL size in itself, but needs * to be large enough to fit the full request headers (including long * path names). */ -#define BUFFER_SIZE MAX_URL_SIZE +#define BUFFER_SIZE (MAX_URL_SIZE + HTTP_HEADERS_SIZE) #define MAX_REDIRECTS 8 #define HTTP_SINGLE 1 #define HTTP_MUTLI 2 @@ -786,6 +786,7 @@ static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) { char *param, *next_param, *cstr, *back; + char *saveptr = NULL; if (!set_cookie[0]) return 0; @@ -803,8 +804,9 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) } next_param = cstr; - while ((param = av_strtok(next_param, ";", &next_param))) { + while ((param = av_strtok(next_param, ";", &saveptr))) { char *name, *value; + next_param = NULL; param += strspn(param, WHITESPACES); if ((name = av_strtok(param, "=", &value))) { if (av_dict_set(dict, name, value, 0) < 0) { @@ -1064,6 +1066,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // Set-Cookie fields will result in multiple values delimited by a newline int ret = 0; char *cookie, *set_cookies, *next; + char *saveptr = NULL; // destroy any cookies in the dictionary. av_dict_free(&s->cookie_dict); @@ -1076,10 +1079,11 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, return AVERROR(ENOMEM); *cookies = NULL; - while ((cookie = av_strtok(next, "\n", &next)) && !ret) { + while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) { AVDictionary *cookie_params = NULL; AVDictionaryEntry *cookie_entry, *e; + next = NULL; // store the cookie in a dict in case it is updated in the response if (parse_cookie(s, cookie, &s->cookie_dict)) av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie); diff --git a/chromium/third_party/ffmpeg/libavformat/icecast.c b/chromium/third_party/ffmpeg/libavformat/icecast.c index 7d8f92fe73f..b06c53cabd5 100644 --- a/chromium/third_party/ffmpeg/libavformat/icecast.c +++ b/chromium/third_party/ffmpeg/libavformat/icecast.c @@ -43,6 +43,7 @@ typedef struct IcecastContext { int public; char *url; char *user_agent; + int tls; } IcecastContext; #define DEFAULT_ICE_USER "source" @@ -62,6 +63,7 @@ static const AVOption options[] = { { "password", "set password", OFFSET(pass), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "content_type", "set content-type, MUST be set if not audio/mpeg", OFFSET(content_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "legacy_icecast", "use legacy SOURCE method, for Icecast < v2.4", OFFSET(legacy_icecast), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "tls", "use a TLS connection", OFFSET(tls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { NULL } }; @@ -75,8 +77,7 @@ static void cat_header(AVBPrint *bp, const char key[], const char value[]) static int icecast_close(URLContext *h) { IcecastContext *s = h->priv_data; - if (s->hd) - ffurl_close(s->hd); + ffurl_closep(&s->hd); return 0; } @@ -163,7 +164,9 @@ static int icecast_open(URLContext *h, const char *uri, int flags) } // Build new URI for passing to http protocol - ff_url_join(h_url, sizeof(h_url), "http", auth, host, port, "%s", path); + ff_url_join(h_url, sizeof(h_url), + s->tls ? "https" : "http", + auth, host, port, "%s", path); // Finally open http proto handler ret = ffurl_open_whitelist(&s->hd, h_url, AVIO_FLAG_READ_WRITE, NULL, &opt_dict, h->protocol_whitelist, h->protocol_blacklist, h); diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.c b/chromium/third_party/ffmpeg/libavformat/id3v2.c index abe073dcc1a..cecd9b9f6d6 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.c +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.c @@ -225,7 +225,6 @@ static void free_geobtag(void *obj) av_freep(&geob->file_name); av_freep(&geob->description); av_freep(&geob->data); - av_free(geob); } /** @@ -459,20 +458,15 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, if (taglen < 1) return; - geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB)); - if (!geob_data) { - av_log(s, AV_LOG_ERROR, "Failed to alloc %"SIZE_SPECIFIER" bytes\n", - sizeof(ID3v2ExtraMetaGEOB)); - return; - } - new_extra = av_mallocz(sizeof(ID3v2ExtraMeta)); if (!new_extra) { av_log(s, AV_LOG_ERROR, "Failed to alloc %"SIZE_SPECIFIER" bytes\n", sizeof(ID3v2ExtraMeta)); - goto fail; + return; } + geob_data = &new_extra->data.geob; + /* read encoding type byte */ encoding = avio_r8(pb); taglen--; @@ -511,7 +505,6 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, /* add data to the list */ new_extra->tag = "GEOB"; - new_extra->data = geob_data; new_extra->next = *extra_meta; *extra_meta = new_extra; @@ -577,7 +570,6 @@ static void free_apic(void *obj) ID3v2ExtraMetaAPIC *apic = obj; av_buffer_unref(&apic->buf); av_freep(&apic->description); - av_freep(&apic); } static void rstrip_spaces(char *buf) @@ -603,10 +595,11 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, goto fail; new_extra = av_mallocz(sizeof(*new_extra)); - apic = av_mallocz(sizeof(*apic)); - if (!new_extra || !apic) + if (!new_extra) goto fail; + apic = &new_extra->data.apic; + enc = avio_r8(pb); taglen--; @@ -658,7 +651,6 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, 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; @@ -680,7 +672,6 @@ static void free_chapter(void *obj) ID3v2ExtraMetaCHAP *chap = obj; av_freep(&chap->element_id); av_dict_free(&chap->meta); - av_freep(&chap); } static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const char *ttag, ID3v2ExtraMeta **extra_meta, int isv34) @@ -691,10 +682,10 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const cha ID3v2ExtraMetaCHAP *chap = NULL; new_extra = av_mallocz(sizeof(*new_extra)); - chap = av_mallocz(sizeof(*chap)); + if (!new_extra) + return; - if (!new_extra || !chap) - goto fail; + chap = &new_extra->data.chap; if (decode_str(s, pb, 0, &chap->element_id, &len) < 0) goto fail; @@ -727,15 +718,13 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const cha ff_metadata_conv(&chap->meta, NULL, ff_id3v2_4_metadata_conv); new_extra->tag = "CHAP"; - new_extra->data = chap; new_extra->next = *extra_meta; *extra_meta = new_extra; return; fail: - if (chap) - free_chapter(chap); + free_chapter(chap); av_freep(&new_extra); } @@ -744,7 +733,6 @@ static void free_priv(void *obj) ID3v2ExtraMetaPRIV *priv = obj; av_freep(&priv->owner); av_freep(&priv->data); - av_freep(&priv); } static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen, @@ -754,10 +742,10 @@ static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen, ID3v2ExtraMetaPRIV *priv; meta = av_mallocz(sizeof(*meta)); - priv = av_mallocz(sizeof(*priv)); + if (!meta) + return; - if (!meta || !priv) - goto fail; + priv = &meta->data.priv; if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &priv->owner, &taglen) < 0) goto fail; @@ -772,15 +760,13 @@ static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen, goto fail; meta->tag = "PRIV"; - meta->data = priv; meta->next = *extra_meta; *extra_meta = meta; return; fail: - if (priv) - free_priv(priv); + free_priv(priv); av_freep(&meta); } @@ -1132,7 +1118,7 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) while (current) { if ((extra_func = get_extra_meta_func(current->tag, 1))) - extra_func->free(current->data); + extra_func->free(¤t->data); next = current->next; av_freep(¤t); current = next; @@ -1141,17 +1127,17 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) *extra_meta = NULL; } -int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) +int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta *extra_meta) { ID3v2ExtraMeta *cur; - for (cur = *extra_meta; cur; cur = cur->next) { + for (cur = extra_meta; cur; cur = cur->next) { ID3v2ExtraMetaAPIC *apic; AVStream *st; if (strcmp(cur->tag, "APIC")) continue; - apic = cur->data; + apic = &cur->data.apic; if (!(st = avformat_new_stream(s, NULL))) return AVERROR(ENOMEM); @@ -1181,7 +1167,7 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) return 0; } -int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) +int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *extra_meta) { int ret = 0; ID3v2ExtraMeta *cur; @@ -1192,12 +1178,12 @@ int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) // since extra_meta is a linked list where elements are prepended, // we need to reverse the order of chapters - for (cur = *extra_meta; cur; cur = cur->next) { + for (cur = extra_meta; cur; cur = cur->next) { ID3v2ExtraMetaCHAP *chap; if (strcmp(cur->tag, "CHAP")) continue; - chap = cur->data; + chap = &cur->data.chap; if ((ret = av_dynarray_add_nofree(&chapters, &num_chapters, chap)) < 0) goto end; @@ -1232,14 +1218,14 @@ end: return ret; } -int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta **extra_meta) +int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta *extra_meta) { ID3v2ExtraMeta *cur; int dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL; - for (cur = *extra_meta; cur; cur = cur->next) { + for (cur = extra_meta; cur; cur = cur->next) { if (!strcmp(cur->tag, "PRIV")) { - ID3v2ExtraMetaPRIV *priv = cur->data; + ID3v2ExtraMetaPRIV *priv = &cur->data.priv; AVBPrint bprint; char *escaped, *key; int i, ret; @@ -1272,7 +1258,7 @@ int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta **extra_met return 0; } -int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) +int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta *extra_meta) { return ff_id3v2_parse_priv_dict(&s->metadata, extra_meta); } diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.h b/chromium/third_party/ffmpeg/libavformat/id3v2.h index 9de0bee3743..a41fb271a42 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.h +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.h @@ -54,12 +54,6 @@ typedef struct ID3v2EncContext { int len; ///< size of the tag written so far } ID3v2EncContext; -typedef struct ID3v2ExtraMeta { - const char *tag; - void *data; - struct ID3v2ExtraMeta *next; -} ID3v2ExtraMeta; - typedef struct ID3v2ExtraMetaGEOB { uint32_t datasize; uint8_t *mime_type; @@ -87,6 +81,17 @@ typedef struct ID3v2ExtraMetaCHAP { AVDictionary *meta; } ID3v2ExtraMetaCHAP; +typedef struct ID3v2ExtraMeta { + const char *tag; + struct ID3v2ExtraMeta *next; + union { + ID3v2ExtraMetaAPIC apic; + ID3v2ExtraMetaCHAP chap; + ID3v2ExtraMetaGEOB geob; + ID3v2ExtraMetaPRIV priv; + } data; +} ID3v2ExtraMeta; + /** * Detect ID3v2 Header. * @param buf must be ID3v2_HEADER_SIZE byte long @@ -162,25 +167,25 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta); * Create a stream for each APIC (attached picture) extracted from the * ID3v2 header. */ -int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); +int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta *extra_meta); /** * Create chapters for all CHAP tags found in the ID3v2 header. */ -int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); +int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *extra_meta); /** * Parse PRIV tags into a dictionary. The PRIV owner is the metadata key. The * PRIV data is the value, with non-printable characters escaped. */ -int ff_id3v2_parse_priv_dict(AVDictionary **d, ID3v2ExtraMeta **extra_meta); +int ff_id3v2_parse_priv_dict(AVDictionary **d, ID3v2ExtraMeta *extra_meta); /** * Add metadata for all PRIV tags in the ID3v2 header. The PRIV owner is the * metadata key. The PRIV data is the value, with non-printable characters * escaped. */ -int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); +int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta *extra_meta); extern const AVMetadataConv ff_id3v2_34_metadata_conv[]; extern const AVMetadataConv ff_id3v2_4_metadata_conv[]; diff --git a/chromium/third_party/ffmpeg/libavformat/iff.c b/chromium/third_party/ffmpeg/libavformat/iff.c index 9cee31a86b1..7feb121cd02 100644 --- a/chromium/third_party/ffmpeg/libavformat/iff.c +++ b/chromium/third_party/ffmpeg/libavformat/iff.c @@ -312,8 +312,8 @@ static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) id3v2_extra_meta = NULL; ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); if (id3v2_extra_meta) { - if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0 || - (ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0) { + if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || + (ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) { ff_id3v2_free_extra_meta(&id3v2_extra_meta); return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/img2.c b/chromium/third_party/ffmpeg/libavformat/img2.c index 16bc9d2abd8..d243d6c1253 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2.c +++ b/chromium/third_party/ffmpeg/libavformat/img2.c @@ -40,6 +40,7 @@ const IdStrMap ff_img_tags[] = { { AV_CODEC_ID_PGMYUV, "pgmyuv" }, { AV_CODEC_ID_PBM, "pbm" }, { AV_CODEC_ID_PAM, "pam" }, + { AV_CODEC_ID_PFM, "pfm" }, { AV_CODEC_ID_ALIAS_PIX, "pix" }, { AV_CODEC_ID_DDS, "dds" }, { AV_CODEC_ID_MPEG1VIDEO, "mpg1-img" }, diff --git a/chromium/third_party/ffmpeg/libavformat/img2dec.c b/chromium/third_party/ffmpeg/libavformat/img2dec.c index 40f3e3d499e..a7e89cd056b 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/img2dec.c @@ -379,8 +379,7 @@ int ff_img_read_header(AVFormatContext *s1) * as a dictionary, so it can be used by filters like 'drawtext'. */ static int add_filename_as_pkt_side_data(char *filename, AVPacket *pkt) { - uint8_t* metadata; - int metadata_len; + int metadata_len, ret; AVDictionary *d = NULL; char *packed_metadata = NULL; @@ -391,13 +390,12 @@ static int add_filename_as_pkt_side_data(char *filename, AVPacket *pkt) { av_dict_free(&d); if (!packed_metadata) return AVERROR(ENOMEM); - if (!(metadata = av_packet_new_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, metadata_len))) { + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, + packed_metadata, metadata_len); + if (ret < 0) { av_freep(&packed_metadata); - return AVERROR(ENOMEM); + return ret; } - memcpy(metadata, packed_metadata, metadata_len); - av_freep(&packed_metadata); - return 0; } @@ -1002,6 +1000,14 @@ static int pgmyuv_probe(const AVProbeData *p) // custom FFmpeg format recognized return ret && av_match_ext(p->filename, "pgmyuv") ? ret : 0; } +static int pgx_probe(const AVProbeData *p) +{ + const uint8_t *b = p->buf; + if (!memcmp(b, "PG ML ", 6)) + return AVPROBE_SCORE_EXTENSION + 1; + return 0; +} + static int ppm_probe(const AVProbeData *p) { return pnm_magic_check(p, 3) || pnm_magic_check(p, 6) ? pnm_probe(p) : 0; @@ -1096,6 +1102,7 @@ IMAGEAUTO_DEMUXER(pbm, AV_CODEC_ID_PBM) IMAGEAUTO_DEMUXER(pcx, AV_CODEC_ID_PCX) IMAGEAUTO_DEMUXER(pgm, AV_CODEC_ID_PGM) IMAGEAUTO_DEMUXER(pgmyuv, AV_CODEC_ID_PGMYUV) +IMAGEAUTO_DEMUXER(pgx, AV_CODEC_ID_PGX) IMAGEAUTO_DEMUXER(pictor, AV_CODEC_ID_PICTOR) IMAGEAUTO_DEMUXER(png, AV_CODEC_ID_PNG) IMAGEAUTO_DEMUXER(ppm, AV_CODEC_ID_PPM) diff --git a/chromium/third_party/ffmpeg/libavformat/internal.h b/chromium/third_party/ffmpeg/libavformat/internal.h index 6786b732aca..17a6ab07d35 100644 --- a/chromium/third_party/ffmpeg/libavformat/internal.h +++ b/chromium/third_party/ffmpeg/libavformat/internal.h @@ -188,6 +188,8 @@ struct AVStreamInternal { */ int need_context_update; + int is_intra_only; + FFFrac *priv_pts; }; @@ -290,16 +292,6 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src, int interleave); /** - * Get the length in bytes which is needed to store val as v. - */ -int ff_get_v_length(uint64_t val); - -/** - * Put val using a variable number of bytes. - */ -void ff_put_v(AVIOContext *bc, uint64_t val); - -/** * Read a whole line of text from AVIOContext. Stop reading after reaching * either a \\n, a \\0 or EOF. The returned string is always \\0-terminated, * and may be truncated if the buffer is too small. @@ -520,6 +512,8 @@ unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id); enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag); +int ff_is_intra_only(enum AVCodecID id); + /** * Select a PCM codec based on the given parameters. * diff --git a/chromium/third_party/ffmpeg/libavformat/isom.c b/chromium/third_party/ffmpeg/libavformat/isom.c index eefe9277b4f..209bbac5d10 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.c +++ b/chromium/third_party/ffmpeg/libavformat/isom.c @@ -313,6 +313,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_PIXLET, MKTAG('p', 'x', 'l', 't') }, + { AV_CODEC_ID_NOTCHLC, MKTAG('n', 'c', 'l', 'c') }, + { AV_CODEC_ID_NONE, 0 }, }; @@ -393,25 +395,145 @@ const AVCodecTag ff_codec_movdata_tags[] = { /* http://developer.apple.com/documentation/mac/Text/Text-368.html */ /* deprecated by putting the code as 3*5 bits ASCII */ static const char mov_mdhd_language_map[][4] = { - /* 0-9 */ - "eng", "fra", "ger", "ita", "dut", "sve", "spa", "dan", "por", "nor", - "heb", "jpn", "ara", "fin", "gre", "ice", "mlt", "tur", "hr "/*scr*/, "chi"/*ace?*/, - "urd", "hin", "tha", "kor", "lit", "pol", "hun", "est", "lav", "", - "fo ", "", "rus", "chi", "", "iri", "alb", "ron", "ces", "slk", - "slv", "yid", "sr ", "mac", "bul", "ukr", "bel", "uzb", "kaz", "aze", - /*?*/ - "aze", "arm", "geo", "mol", "kir", "tgk", "tuk", "mon", "", "pus", - "kur", "kas", "snd", "tib", "nep", "san", "mar", "ben", "asm", "guj", - "pa ", "ori", "mal", "kan", "tam", "tel", "", "bur", "khm", "lao", - /* roman? arabic? */ - "vie", "ind", "tgl", "may", "may", "amh", "tir", "orm", "som", "swa", - /*==rundi?*/ - "", "run", "", "mlg", "epo", "", "", "", "", "", - /* 100 */ - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "wel", "baq", - "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav" + "eng", /* 0 English */ + "fra", /* 1 French */ + "ger", /* 2 German */ + "ita", /* 3 Italian */ + "dut", /* 4 Dutch */ + "sve", /* 5 Swedish */ + "spa", /* 6 Spanish */ + "dan", /* 7 Danish */ + "por", /* 8 Portuguese */ + "nor", /* 9 Norwegian */ + "heb", /* 10 Hebrew */ + "jpn", /* 11 Japanese */ + "ara", /* 12 Arabic */ + "fin", /* 13 Finnish */ + "gre", /* 14 Greek */ + "ice", /* 15 Icelandic */ + "mlt", /* 16 Maltese */ + "tur", /* 17 Turkish */ + "hr ", /* 18 Croatian */ + "chi", /* 19 Traditional Chinese */ + "urd", /* 20 Urdu */ + "hin", /* 21 Hindi */ + "tha", /* 22 Thai */ + "kor", /* 23 Korean */ + "lit", /* 24 Lithuanian */ + "pol", /* 25 Polish */ + "hun", /* 26 Hungarian */ + "est", /* 27 Estonian */ + "lav", /* 28 Latvian */ + "", /* 29 Sami */ + "fo ", /* 30 Faroese */ + "", /* 31 Farsi */ + "rus", /* 32 Russian */ + "chi", /* 33 Simplified Chinese */ + "", /* 34 Flemish */ + "iri", /* 35 Irish */ + "alb", /* 36 Albanian */ + "ron", /* 37 Romanian */ + "ces", /* 38 Czech */ + "slk", /* 39 Slovak */ + "slv", /* 40 Slovenian */ + "yid", /* 41 Yiddish */ + "sr ", /* 42 Serbian */ + "mac", /* 43 Macedonian */ + "bul", /* 44 Bulgarian */ + "ukr", /* 45 Ukrainian */ + "bel", /* 46 Belarusian */ + "uzb", /* 47 Uzbek */ + "kaz", /* 48 Kazakh */ + "aze", /* 49 Azerbaijani */ + "aze", /* 50 AzerbaijanAr */ + "arm", /* 51 Armenian */ + "geo", /* 52 Georgian */ + "mol", /* 53 Moldavian */ + "kir", /* 54 Kirghiz */ + "tgk", /* 55 Tajiki */ + "tuk", /* 56 Turkmen */ + "mon", /* 57 Mongolian */ + "", /* 58 MongolianCyr */ + "pus", /* 59 Pashto */ + "kur", /* 60 Kurdish */ + "kas", /* 61 Kashmiri */ + "snd", /* 62 Sindhi */ + "tib", /* 63 Tibetan */ + "nep", /* 64 Nepali */ + "san", /* 65 Sanskrit */ + "mar", /* 66 Marathi */ + "ben", /* 67 Bengali */ + "asm", /* 68 Assamese */ + "guj", /* 69 Gujarati */ + "pa ", /* 70 Punjabi */ + "ori", /* 71 Oriya */ + "mal", /* 72 Malayalam */ + "kan", /* 73 Kannada */ + "tam", /* 74 Tamil */ + "tel", /* 75 Telugu */ + "", /* 76 Sinhala */ + "bur", /* 77 Burmese */ + "khm", /* 78 Khmer */ + "lao", /* 79 Lao */ + "vie", /* 80 Vietnamese */ + "ind", /* 81 Indonesian */ + "tgl", /* 82 Tagalog */ + "may", /* 83 MalayRoman */ + "may", /* 84 MalayArabic */ + "amh", /* 85 Amharic */ + "tir", /* 86 Galla */ + "orm", /* 87 Oromo */ + "som", /* 88 Somali */ + "swa", /* 89 Swahili */ + "", /* 90 Kinyarwanda */ + "run", /* 91 Rundi */ + "", /* 92 Nyanja */ + "mlg", /* 93 Malagasy */ + "epo", /* 94 Esperanto */ + "", /* 95 */ + "", /* 96 */ + "", /* 97 */ + "", /* 98 */ + "", /* 99 */ + "", /* 100 */ + "", /* 101 */ + "", /* 102 */ + "", /* 103 */ + "", /* 104 */ + "", /* 105 */ + "", /* 106 */ + "", /* 107 */ + "", /* 108 */ + "", /* 109 */ + "", /* 110 */ + "", /* 111 */ + "", /* 112 */ + "", /* 113 */ + "", /* 114 */ + "", /* 115 */ + "", /* 116 */ + "", /* 117 */ + "", /* 118 */ + "", /* 119 */ + "", /* 120 */ + "", /* 121 */ + "", /* 122 */ + "", /* 123 */ + "", /* 124 */ + "", /* 125 */ + "", /* 126 */ + "", /* 127 */ + "wel", /* 128 Welsh */ + "baq", /* 129 Basque */ + "cat", /* 130 Catalan */ + "lat", /* 131 Latin */ + "que", /* 132 Quechua */ + "grn", /* 133 Guarani */ + "aym", /* 134 Aymara */ + "tat", /* 135 Tatar */ + "uig", /* 136 Uighur */ + "dzo", /* 137 Dzongkha */ + "jav", /* 138 JavaneseRom */ }; int ff_mov_iso639_to_lang(const char lang[4], int mp4) diff --git a/chromium/third_party/ffmpeg/libavformat/ivfenc.c b/chromium/third_party/ffmpeg/libavformat/ivfenc.c index 45e5b238dcb..0951f56c92a 100644 --- a/chromium/third_party/ffmpeg/libavformat/ivfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/ivfenc.c @@ -26,10 +26,9 @@ typedef struct IVFEncContext { uint64_t last_pts, sum_delta_pts; } IVFEncContext; -static int ivf_write_header(AVFormatContext *s) +static int ivf_init(AVFormatContext *s) { AVCodecParameters *par; - AVIOContext *pb = s->pb; if (s->nb_streams != 1) { av_log(s, AV_LOG_ERROR, "Format supports only exactly one video stream\n"); @@ -43,6 +42,25 @@ static int ivf_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n"); return AVERROR(EINVAL); } + + if (par->codec_id == AV_CODEC_ID_VP9) { + int ret = ff_stream_add_bitstream_filter(s->streams[0], "vp9_superframe", NULL); + if (ret < 0) + return ret; + } else if (par->codec_id == AV_CODEC_ID_AV1) { + int ret = ff_stream_add_bitstream_filter(s->streams[0], "av1_metadata", "td=insert"); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ivf_write_header(AVFormatContext *s) +{ + AVCodecParameters *par = s->streams[0]->codecpar; + AVIOContext *pb = s->pb; + avio_write(pb, "DKIF", 4); avio_wl16(pb, 0); // version avio_wl16(pb, 32); // header length @@ -92,19 +110,6 @@ static int ivf_write_trailer(AVFormatContext *s) return 0; } -static int ivf_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) -{ - int ret = 1; - AVStream *st = s->streams[pkt->stream_index]; - - if (st->codecpar->codec_id == AV_CODEC_ID_VP9) - ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL); - else if (st->codecpar->codec_id == AV_CODEC_ID_AV1) - ret = ff_stream_add_bitstream_filter(st, "av1_metadata", "td=insert"); - - return ret; -} - static const AVCodecTag codec_ivf_tags[] = { { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, @@ -119,9 +124,9 @@ AVOutputFormat ff_ivf_muxer = { .extensions = "ivf", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_VP8, + .init = ivf_init, .write_header = ivf_write_header, .write_packet = ivf_write_packet, .write_trailer = ivf_write_trailer, - .check_bitstream = ivf_check_bitstream, .codec_tag = (const AVCodecTag* const []){ codec_ivf_tags, 0 }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/jacosubdec.c b/chromium/third_party/ffmpeg/libavformat/jacosubdec.c index 121c86d6596..3414eb39386 100644 --- a/chromium/third_party/ffmpeg/libavformat/jacosubdec.c +++ b/chromium/third_party/ffmpeg/libavformat/jacosubdec.c @@ -188,8 +188,10 @@ static int jacosub_read_header(AVFormatContext *s) AVPacket *sub; sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line); - if (!sub) - return AVERROR(ENOMEM); + if (!sub) { + ret = AVERROR(ENOMEM); + goto fail; + } sub->pos = pos; merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n"); continue; diff --git a/chromium/third_party/ffmpeg/libavformat/kvag.c b/chromium/third_party/ffmpeg/libavformat/kvag.c index 71b0eb41186..0a11fc05562 100644 --- a/chromium/third_party/ffmpeg/libavformat/kvag.c +++ b/chromium/third_party/ffmpeg/libavformat/kvag.c @@ -1,5 +1,5 @@ /* - * Simon & Schuster Interactive VAG demuxer + * Simon & Schuster Interactive VAG (de)muxer * * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) * @@ -21,6 +21,7 @@ */ #include "avformat.h" #include "internal.h" +#include "rawenc.h" #include "libavutil/intreadwrite.h" #define KVAG_TAG MKTAG('K', 'V', 'A', 'G') @@ -34,6 +35,7 @@ typedef struct KVAGHeader { uint16_t stereo; } KVAGHeader; +#if CONFIG_KVAG_DEMUXER static int kvag_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != KVAG_TAG) @@ -115,3 +117,81 @@ AVInputFormat ff_kvag_demuxer = { .read_header = kvag_read_header, .read_packet = kvag_read_packet }; +#endif + +#if CONFIG_KVAG_MUXER +static int kvag_write_init(AVFormatContext *s) +{ + AVCodecParameters *par; + + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "KVAG files have exactly one stream\n"); + return AVERROR(EINVAL); + } + + par = s->streams[0]->codecpar; + + if (par->codec_id != AV_CODEC_ID_ADPCM_IMA_SSI) { + av_log(s, AV_LOG_ERROR, "%s codec not supported\n", + avcodec_get_name(par->codec_id)); + return AVERROR(EINVAL); + } + + if (par->channels > 2) { + av_log(s, AV_LOG_ERROR, "KVAG files only support up to 2 channels\n"); + return AVERROR(EINVAL); + } + + if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { + av_log(s, AV_LOG_WARNING, "Stream not seekable, unable to write output file\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int kvag_write_header(AVFormatContext *s) +{ + uint8_t buf[KVAG_HEADER_SIZE]; + AVCodecParameters *par = s->streams[0]->codecpar; + + AV_WL32(buf + 0, KVAG_TAG); + AV_WL32(buf + 4, 0); /* Data size, we fix this up later. */ + AV_WL32(buf + 8, par->sample_rate); + AV_WL16(buf + 12, par->channels == 2); + + avio_write(s->pb, buf, sizeof(buf)); + return 0; +} + +static int kvag_write_trailer(AVFormatContext *s) +{ + int64_t file_size, data_size; + + file_size = avio_tell(s->pb); + data_size = file_size - KVAG_HEADER_SIZE; + if (data_size < UINT32_MAX) { + avio_seek(s->pb, 4, SEEK_SET); + avio_wl32(s->pb, (uint32_t)data_size); + avio_seek(s->pb, file_size, SEEK_SET); + } else { + av_log(s, AV_LOG_WARNING, + "Filesize %"PRId64" invalid for KVAG, output file will be broken\n", + file_size); + } + + return 0; +} + +AVOutputFormat ff_kvag_muxer = { + .name = "kvag", + .long_name = NULL_IF_CONFIG_SMALL("Simon & Schuster Interactive VAG"), + .extensions = "vag", + .audio_codec = AV_CODEC_ID_ADPCM_IMA_SSI, + .video_codec = AV_CODEC_ID_NONE, + .init = kvag_write_init, + .write_header = kvag_write_header, + .write_packet = ff_raw_write_packet, + .write_trailer = kvag_write_trailer +}; +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/latmenc.c b/chromium/third_party/ffmpeg/libavformat/latmenc.c index 5ae677f5dad..5458ce2596b 100644 --- a/chromium/third_party/ffmpeg/libavformat/latmenc.c +++ b/chromium/third_party/ffmpeg/libavformat/latmenc.c @@ -165,7 +165,7 @@ static int latm_write_packet(AVFormatContext *s, AVPacket *pkt) return ff_raw_write_packet(s, pkt); else { uint8_t *side_data; - int side_data_size = 0, ret; + int side_data_size, ret; side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size); @@ -211,7 +211,6 @@ static int latm_write_packet(AVFormatContext *s, AVPacket *pkt) } else avpriv_copy_bits(&bs, pkt->data, 8*pkt->size); - avpriv_align_put_bits(&bs); flush_put_bits(&bs); len = put_bits_count(&bs) >> 3; diff --git a/chromium/third_party/ffmpeg/libavformat/libamqp.c b/chromium/third_party/ffmpeg/libavformat/libamqp.c index aaf0e511522..81df724a6d4 100644 --- a/chromium/third_party/ffmpeg/libavformat/libamqp.c +++ b/chromium/third_party/ffmpeg/libavformat/libamqp.c @@ -39,6 +39,7 @@ typedef struct AMQPContext { int pkt_size; int64_t connection_timeout; int pkt_size_overflow; + int delivery_mode; } AMQPContext; #define STR_LEN 1024 @@ -52,6 +53,9 @@ static const AVOption options[] = { { "exchange", "Exchange to send/read packets", OFFSET(exchange), AV_OPT_TYPE_STRING, { .str = "amq.direct" }, 0, 0, .flags = D | E }, { "routing_key", "Key to filter streams", OFFSET(routing_key), AV_OPT_TYPE_STRING, { .str = "amqp" }, 0, 0, .flags = D | E }, { "connection_timeout", "Initial connection timeout", OFFSET(connection_timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT64_MAX, .flags = D | E}, + { "delivery_mode", "Delivery mode", OFFSET(delivery_mode), AV_OPT_TYPE_INT, { .i64 = AMQP_DELIVERY_PERSISTENT }, 1, 2, .flags = E, "delivery_mode"}, + { "persistent", "Persistent delivery mode", 0, AV_OPT_TYPE_CONST, { .i64 = AMQP_DELIVERY_PERSISTENT }, 0, 0, E, "delivery_mode" }, + { "non-persistent", "Non-persistent delivery mode", 0, AV_OPT_TYPE_CONST, { .i64 = AMQP_DELIVERY_NONPERSISTENT }, 0, 0, E, "delivery_mode" }, { NULL } }; @@ -222,7 +226,7 @@ static int amqp_proto_write(URLContext *h, const unsigned char *buf, int size) props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG; props.content_type = amqp_cstring_bytes("octet/stream"); - props.delivery_mode = 2; /* persistent delivery mode */ + props.delivery_mode = s->delivery_mode; ret = amqp_basic_publish(s->conn, DEFAULT_CHANNEL, amqp_cstring_bytes(s->exchange), amqp_cstring_bytes(s->routing_key), 0, 0, diff --git a/chromium/third_party/ffmpeg/libavformat/libsrt.c b/chromium/third_party/ffmpeg/libavformat/libsrt.c index 2d6fc4b7e7e..4719ce0d4b4 100644 --- a/chromium/third_party/ffmpeg/libavformat/libsrt.c +++ b/chromium/third_party/ffmpeg/libavformat/libsrt.c @@ -96,8 +96,8 @@ typedef struct SRTContext { #define E AV_OPT_FLAG_ENCODING_PARAM #define OFFSET(x) offsetof(SRTContext, x) static const AVOption libsrt_options[] = { - { "timeout", "Timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, - { "listen_timeout", "Connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "timeout", "Timeout of socket I/O operations (in microseconds)", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "listen_timeout", "Connection awaiting timeout (in microseconds)" , OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "pkt_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, "payload_size" }, @@ -118,13 +118,13 @@ static const AVOption libsrt_options[] = { { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E }, { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E }, - { "latency", "receiver delay to absorb bursts of missed packet retransmissions", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "latency", "receiver delay (in microseconds) to absorb bursts of missed packet retransmissions", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "tsbpddelay", "deprecated, same effect as latency option", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, - { "rcvlatency", "receive latency", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, - { "peerlatency", "peer latency", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "rcvlatency", "receive latency (in microseconds)", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "peerlatency", "peer latency (in microseconds)", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "tlpktdrop", "Enable receiver pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E }, { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, .flags = D|E }, - { "connect_timeout", "Connect timeout. Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "connect_timeout", "Connect timeout(in milliseconds). Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "mode", "Connection mode (caller, listener, rendezvous)", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = SRT_MODE_CALLER }, SRT_MODE_CALLER, SRT_MODE_RENDEZVOUS, .flags = D|E, "mode" }, { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, @@ -313,8 +313,12 @@ static int libsrt_set_options_pre(URLContext *h, int fd) (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) || (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) || #if SRT_VERSION_VALUE >= 0x010302 +#if SRT_VERSION_VALUE >= 0x010401 + (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) || +#else /* SRTO_STRICTENC == SRTO_ENFORCEDENCRYPTION (53), but for compatibility, we used SRTO_STRICTENC */ (s->enforced_encryption >= 0 && libsrt_setsockopt(h, fd, SRTO_STRICTENC, "SRTO_STRICTENC", &s->enforced_encryption, sizeof(s->enforced_encryption)) < 0) || +#endif (s->kmrefreshrate >= 0 && libsrt_setsockopt(h, fd, SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", &s->kmrefreshrate, sizeof(s->kmrefreshrate)) < 0) || (s->kmpreannounce >= 0 && libsrt_setsockopt(h, fd, SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", &s->kmpreannounce, sizeof(s->kmpreannounce)) < 0) || #endif @@ -333,7 +337,11 @@ static int libsrt_set_options_pre(URLContext *h, int fd) (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) || (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) || (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) || +#if SRT_VERSION_VALUE >= 0x010401 + (s->smoother && libsrt_setsockopt(h, fd, SRTO_CONGESTION, "SRTO_CONGESTION", s->smoother, strlen(s->smoother)) < 0) || +#else (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) || +#endif (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) || (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) || ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0)) { @@ -361,7 +369,7 @@ static int libsrt_setup(URLContext *h, const char *uri, int flags) int ret; char hostname[1024],proto[1024],path[1024]; char portstr[10]; - int open_timeout = 0; + int64_t open_timeout = 0; int eid; eid = srt_epoll_create(); diff --git a/chromium/third_party/ffmpeg/libavformat/lrcdec.c b/chromium/third_party/ffmpeg/libavformat/lrcdec.c index a9a117691ac..46d5e2bc6a2 100644 --- a/chromium/third_party/ffmpeg/libavformat/lrcdec.c +++ b/chromium/third_party/ffmpeg/libavformat/lrcdec.c @@ -202,6 +202,7 @@ static int lrc_read_header(AVFormatContext *s) sub = ff_subtitles_queue_insert(&lrc->q, line.str + ts_strlength, line.len - ts_strlength, 0); if(!sub) { + ff_subtitles_queue_clean(&lrc->q); return AVERROR(ENOMEM); } sub->pos = pos; diff --git a/chromium/third_party/ffmpeg/libavformat/matroskadec.c b/chromium/third_party/ffmpeg/libavformat/matroskadec.c index b5a6d3ab065..79410e278f3 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskadec.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskadec.c @@ -253,6 +253,7 @@ typedef struct MatroskaTrack { AVStream *stream; int64_t end_timecode; int ms_compat; + int needs_decoding; uint64_t max_block_additional_id; uint32_t palette[AVPALETTE_COUNT]; @@ -262,6 +263,7 @@ typedef struct MatroskaTrack { typedef struct MatroskaAttachment { uint64_t uid; char *filename; + char *description; char *mime; EbmlBin bin; @@ -590,7 +592,7 @@ static EbmlSyntax matroska_attachment[] = { { MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachment, filename) }, { MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachment, mime) }, { MATROSKA_ID_FILEDATA, EBML_BIN, 0, offsetof(MatroskaAttachment, bin) }, - { MATROSKA_ID_FILEDESC, EBML_NONE }, + { MATROSKA_ID_FILEDESC, EBML_UTF8, 0, offsetof(MatroskaAttachment, description) }, CHILD_OF(matroska_attachments) }; @@ -1138,7 +1140,7 @@ static int is_ebml_id_valid(uint32_t id) * an entry already exists, return the existing entry. */ static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *matroska, - uint32_t id) + uint32_t id, int64_t pos) { int i; MatroskaLevel1Element *elem; @@ -1150,19 +1152,18 @@ static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *ma if (id == MATROSKA_ID_CLUSTER) return NULL; - // There can be multiple seekheads. - if (id != MATROSKA_ID_SEEKHEAD) { - for (i = 0; i < matroska->num_level1_elems; i++) { - if (matroska->level1_elems[i].id == id) + // There can be multiple SeekHeads and Tags. + for (i = 0; i < matroska->num_level1_elems; i++) { + if (matroska->level1_elems[i].id == id) { + if (matroska->level1_elems[i].pos == pos || + id != MATROSKA_ID_SEEKHEAD && id != MATROSKA_ID_TAGS) return &matroska->level1_elems[i]; } } // Only a completely broken file would have more elements. - // It also provides a low-effort way to escape from circular seekheads - // (every iteration will add a level1 entry). if (matroska->num_level1_elems >= FF_ARRAY_ELEMS(matroska->level1_elems)) { - av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements or circular seekheads.\n"); + av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements.\n"); return NULL; } @@ -1411,7 +1412,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska, if (id == MATROSKA_ID_CUES) matroska->cues_parsing_deferred = 0; if (syntax->type == EBML_LEVEL1 && - (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) { + (level1_elem = matroska_find_level1_elem(matroska, syntax->id, pos))) { if (!level1_elem->pos) { // Zero is not a valid position for a level 1 element. level1_elem->pos = pos; @@ -1775,7 +1776,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } if (!found) { - av_log(NULL, AV_LOG_WARNING, + av_log(s, AV_LOG_WARNING, "The tags at index %d refer to a " "non-existent attachment %"PRId64".\n", i, tags[i].target.attachuid); @@ -1792,7 +1793,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } if (!found) { - av_log(NULL, AV_LOG_WARNING, + av_log(s, AV_LOG_WARNING, "The tags at index %d refer to a non-existent chapter " "%"PRId64".\n", i, tags[i].target.chapteruid); @@ -1809,7 +1810,7 @@ static void matroska_convert_tags(AVFormatContext *s) } } if (!found) { - av_log(NULL, AV_LOG_WARNING, + av_log(s, AV_LOG_WARNING, "The tags at index %d refer to a non-existent track " "%"PRId64".\n", i, tags[i].target.trackuid); @@ -1869,8 +1870,12 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) MatroskaSeekhead *seekheads = seekhead_list->elem; uint32_t id = seekheads[i].id; int64_t pos = seekheads[i].pos + matroska->segment_start; + MatroskaLevel1Element *elem; + + if (id != seekheads[i].id || pos < matroska->segment_start) + continue; - MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id); + elem = matroska_find_level1_elem(matroska, id, pos); if (!elem || elem->parsed) continue; @@ -2026,12 +2031,12 @@ static int matroska_parse_flac(AVFormatContext *s, static int mkv_field_order(MatroskaDemuxContext *matroska, int64_t field_order) { - int major, minor, micro, bttb = 0; + int minor, micro, bttb = 0; /* workaround a bug in our Matroska muxer, introduced in version 57.36 alongside * this function, and fixed in 57.52 */ - if (matroska->muxingapp && sscanf(matroska->muxingapp, "Lavf%d.%d.%d", &major, &minor, µ) == 3) - bttb = (major == 57 && minor >= 36 && minor <= 51 && micro >= 100); + if (matroska->muxingapp && sscanf(matroska->muxingapp, "Lavf57.%d.%d", &minor, µ) == 2) + bttb = (minor >= 36 && minor <= 51 && micro >= 100); switch (field_order) { case MATROSKA_VIDEO_FIELDORDER_PROGRESSIVE: @@ -2157,42 +2162,40 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { return 0; } -static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) { +static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track, + void *logctx) +{ AVSphericalMapping *spherical; + const MatroskaTrackVideoProjection *mkv_projection = &track->video.projection; + const uint8_t *priv_data = mkv_projection->private.data; enum AVSphericalProjection projection; size_t spherical_size; uint32_t l = 0, t = 0, r = 0, b = 0; uint32_t padding = 0; int ret; - GetByteContext gb; - bytestream2_init(&gb, track->video.projection.private.data, - track->video.projection.private.size); - - if (bytestream2_get_byte(&gb) != 0) { - av_log(NULL, AV_LOG_WARNING, "Unknown spherical metadata\n"); + if (mkv_projection->private.size && priv_data[0] != 0) { + av_log(logctx, AV_LOG_WARNING, "Unknown spherical metadata\n"); return 0; } - bytestream2_skip(&gb, 3); // flags - switch (track->video.projection.type) { case MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR: if (track->video.projection.private.size == 20) { - t = bytestream2_get_be32(&gb); - b = bytestream2_get_be32(&gb); - l = bytestream2_get_be32(&gb); - r = bytestream2_get_be32(&gb); + t = AV_RB32(priv_data + 4); + b = AV_RB32(priv_data + 8); + l = AV_RB32(priv_data + 12); + r = AV_RB32(priv_data + 16); if (b >= UINT_MAX - t || r >= UINT_MAX - l) { - av_log(NULL, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Invalid bounding rectangle coordinates " "%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n", l, t, r, b); return AVERROR_INVALIDDATA; } } else if (track->video.projection.private.size != 0) { - av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n"); + av_log(logctx, AV_LOG_ERROR, "Unknown spherical metadata\n"); return AVERROR_INVALIDDATA; } @@ -2203,19 +2206,19 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) break; case MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP: if (track->video.projection.private.size < 4) { - av_log(NULL, AV_LOG_ERROR, "Missing projection private properties\n"); + av_log(logctx, AV_LOG_ERROR, "Missing projection private properties\n"); return AVERROR_INVALIDDATA; } else if (track->video.projection.private.size == 12) { - uint32_t layout = bytestream2_get_be32(&gb); + uint32_t layout = AV_RB32(priv_data + 4); if (layout) { - av_log(NULL, AV_LOG_WARNING, + av_log(logctx, AV_LOG_WARNING, "Unknown spherical cubemap layout %"PRIu32"\n", layout); return 0; } projection = AV_SPHERICAL_CUBEMAP; - padding = bytestream2_get_be32(&gb); + padding = AV_RB32(priv_data + 8); } else { - av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n"); + av_log(logctx, AV_LOG_ERROR, "Unknown spherical metadata\n"); return AVERROR_INVALIDDATA; } break; @@ -2223,7 +2226,7 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) /* No Spherical metadata */ return 0; default: - av_log(NULL, AV_LOG_WARNING, + av_log(logctx, AV_LOG_WARNING, "Unknown spherical metadata type %"PRIu64"\n", track->video.projection.type); return 0; @@ -2409,6 +2412,11 @@ static int matroska_parse_tracks(AVFormatContext *s) } } } + track->needs_decoding = encodings && !encodings[0].type && + encodings[0].scope & 1 && + (encodings[0].compression.algo != + MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP || + encodings[0].compression.settings.size); for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { if (!strncmp(ff_mkv_codec_tags[j].str, track->codec_id, @@ -2611,28 +2619,34 @@ static int matroska_parse_tracks(AVFormatContext *s) track->audio.sub_packet_h = avio_rb16(&b); track->audio.frame_size = avio_rb16(&b); track->audio.sub_packet_size = avio_rb16(&b); - if (flavor < 0 || - track->audio.coded_framesize <= 0 || + if (track->audio.coded_framesize <= 0 || track->audio.sub_packet_h <= 0 || - track->audio.frame_size <= 0 || - track->audio.sub_packet_size <= 0 && codec_id != AV_CODEC_ID_SIPR) + track->audio.frame_size <= 0) return AVERROR_INVALIDDATA; - track->audio.buf = av_malloc_array(track->audio.sub_packet_h, - track->audio.frame_size); - if (!track->audio.buf) - return AVERROR(ENOMEM); + if (codec_id == AV_CODEC_ID_RA_288) { + if (track->audio.sub_packet_h & 1 || 2 * track->audio.frame_size + != (int64_t)track->audio.sub_packet_h * track->audio.coded_framesize) + return AVERROR_INVALIDDATA; st->codecpar->block_align = track->audio.coded_framesize; track->codec_priv.size = 0; } else { - if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) { + if (codec_id == AV_CODEC_ID_SIPR) { static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 }; + if (flavor > 3) + return AVERROR_INVALIDDATA; track->audio.sub_packet_size = ff_sipr_subpk_size[flavor]; st->codecpar->bit_rate = sipr_bit_rate[flavor]; - } + } else if (track->audio.sub_packet_size <= 0 || + track->audio.frame_size % track->audio.sub_packet_size) + return AVERROR_INVALIDDATA; st->codecpar->block_align = track->audio.sub_packet_size; extradata_offset = 78; } + track->audio.buf = av_malloc_array(track->audio.sub_packet_h, + track->audio.frame_size); + if (!track->audio.buf) + return AVERROR(ENOMEM); #else return AVERROR_INVALIDDATA; #endif @@ -2772,7 +2786,7 @@ static int matroska_parse_tracks(AVFormatContext *s) ret = mkv_parse_video_color(st, track); if (ret < 0) return ret; - ret = mkv_parse_video_projection(st, track); + ret = mkv_parse_video_projection(st, track, matroska->ctx); if (ret < 0) return ret; } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { @@ -2907,6 +2921,8 @@ static int matroska_read_header(AVFormatContext *s) break; av_dict_set(&st->metadata, "filename", attachments[j].filename, 0); av_dict_set(&st->metadata, "mimetype", attachments[j].mime, 0); + if (attachments[j].description) + av_dict_set(&st->metadata, "title", attachments[j].description, 0); st->codecpar->codec_id = AV_CODEC_ID_NONE; for (i = 0; mkv_image_mime_tags[i].id != AV_CODEC_ID_NONE; i++) { @@ -2926,9 +2942,8 @@ static int matroska_read_header(AVFormatContext *s) st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; av_init_packet(pkt); - pkt->buf = av_buffer_ref(attachments[j].bin.buf); - if (!pkt->buf) - return AVERROR(ENOMEM); + pkt->buf = attachments[j].bin.buf; + attachments[j].bin.buf = NULL; pkt->data = attachments[j].bin.data; pkt->size = attachments[j].bin.size; pkt->stream_index = st->index; @@ -3022,10 +3037,12 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, return 0; } - av_assert0(size > 0); - *laces = *data + 1; - data += 1; - size -= 1; + if (size <= 0) + return AVERROR_INVALIDDATA; + + *laces = *data + 1; + data += 1; + size -= 1; switch (type) { case 0x1: /* Xiph lacing */ @@ -3035,31 +3052,26 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, for (n = 0; n < *laces - 1; n++) { lace_size[n] = 0; - while (1) { - if (size <= total) { + do { + if (size <= total) return AVERROR_INVALIDDATA; - } temp = *data; total += temp; lace_size[n] += temp; data += 1; size -= 1; - if (temp != 0xff) - break; - } + } while (temp == 0xff); } - if (size <= total) { + if (size < total) return AVERROR_INVALIDDATA; - } lace_size[n] = size - total; break; } case 0x2: /* fixed-size lacing */ - if (size % (*laces)) { + if (size % (*laces)) return AVERROR_INVALIDDATA; - } for (n = 0; n < *laces; n++) lace_size[n] = size / *laces; break; @@ -3095,15 +3107,15 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, } data += offset; size -= offset; - if (size <= total) { + if (size < total) return AVERROR_INVALIDDATA; - } + lace_size[*laces - 1] = size - total; break; } } - *buf = data; + *buf = data; return 0; } @@ -3113,12 +3125,12 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, uint8_t *data, int size, uint64_t timecode, int64_t pos) { - int a = st->codecpar->block_align; - int sps = track->audio.sub_packet_size; - int cfs = track->audio.coded_framesize; - int h = track->audio.sub_packet_h; + const int a = st->codecpar->block_align; + const int sps = track->audio.sub_packet_size; + const int cfs = track->audio.coded_framesize; + const int h = track->audio.sub_packet_h; + const int w = track->audio.frame_size; int y = track->audio.sub_packet_cnt; - int w = track->audio.frame_size; int x; if (!track->audio.pkt_cnt) { @@ -3141,7 +3153,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } memcpy(track->audio.buf + y * w, data, w); } else { - if (size < sps * w / sps || h<=0 || w%sps) { + if (size < w) { av_log(matroska->ctx, AV_LOG_ERROR, "Corrupt generic RM-style audio packet size\n"); return AVERROR_INVALIDDATA; @@ -3191,10 +3203,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, } /* reconstruct full wavpack blocks from mangled matroska ones */ -static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, - uint8_t **pdst, int *size) +static int matroska_parse_wavpack(MatroskaTrack *track, + uint8_t **data, int *size) { uint8_t *dst = NULL; + uint8_t *src = *data; int dstlen = 0; int srclen = *size; uint32_t samples; @@ -3264,7 +3277,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); - *pdst = dst; + *data = dst; *size = dstlen; return 0; @@ -3274,22 +3287,22 @@ fail: return ret; } -static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src, - uint8_t **pdst, int *size) +static int matroska_parse_prores(MatroskaTrack *track, + uint8_t **data, int *size) { uint8_t *dst; int dstlen = *size + 8; - dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE); - if (!dst) - return AVERROR(ENOMEM); + dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst) + return AVERROR(ENOMEM); - AV_WB32(dst, dstlen); - AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f')); - memcpy(dst + 8, src, dstlen - 8); - memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); + AV_WB32(dst, dstlen); + AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f')); + memcpy(dst + 8, *data, dstlen - 8); + memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); - *pdst = dst; + *data = dst; *size = dstlen; return 0; @@ -3418,46 +3431,40 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, uint8_t *additional, uint64_t additional_id, int additional_size, int64_t discard_padding) { - MatroskaTrackEncoding *encodings = track->encodings.elem; uint8_t *pkt_data = data; - int res; + int res = 0; AVPacket pktl, *pkt = &pktl; - if (encodings && !encodings->type && encodings->scope & 1) { - res = matroska_decode_buffer(&pkt_data, &pkt_size, track); - if (res < 0) - return res; - } - if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) { - uint8_t *wv_data; - res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size); + res = matroska_parse_wavpack(track, &pkt_data, &pkt_size); if (res < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a wavpack block.\n"); goto fail; } - if (pkt_data != data) - av_freep(&pkt_data); - pkt_data = wv_data; + if (!buf) + av_freep(&data); + buf = NULL; } if (st->codecpar->codec_id == AV_CODEC_ID_PRORES && AV_RB32(pkt_data + 4) != MKBETAG('i', 'c', 'p', 'f')) { - uint8_t *pr_data; - res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size); + res = matroska_parse_prores(track, &pkt_data, &pkt_size); if (res < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a prores block.\n"); goto fail; } - if (pkt_data != data) - av_freep(&pkt_data); - pkt_data = pr_data; + if (!buf) + av_freep(&data); + buf = NULL; } + if (!pkt_size && !additional_size) + goto no_output; + av_init_packet(pkt); - if (pkt_data != data) + if (!buf) pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE, NULL, NULL, 0); else @@ -3526,9 +3533,10 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; +no_output: fail: - if (pkt_data != data) - av_freep(&pkt_data); + if (!buf) + av_free(pkt_data); return res; } @@ -3557,16 +3565,20 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf size -= n; track = matroska_find_track_by_num(matroska, num); - if (!track || !track->stream) { - av_log(matroska->ctx, AV_LOG_INFO, - "Invalid stream %"PRIu64"\n", num); + if (!track || size < 3) return AVERROR_INVALIDDATA; - } else if (size <= 3) + + if (!(st = track->stream)) { + av_log(matroska->ctx, AV_LOG_VERBOSE, + "No stream associated to TrackNumber %"PRIu64". " + "Ignoring Block with this TrackNumber.\n", num); return 0; - st = track->stream; + } + if (st->discard >= AVDISCARD_ALL) return res; - av_assert1(block_duration != AV_NOPTS_VALUE); + if (block_duration > INT64_MAX) + block_duration = INT64_MAX; block_time = sign_extend(AV_RB16(data), 16); data += 2; @@ -3627,33 +3639,41 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf for (n = 0; n < laces; n++) { int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces; + uint8_t *out_data = data; + int out_size = lace_size[n]; - if ((st->codecpar->codec_id == AV_CODEC_ID_RA_288 || - st->codecpar->codec_id == AV_CODEC_ID_COOK || - st->codecpar->codec_id == AV_CODEC_ID_SIPR || - st->codecpar->codec_id == AV_CODEC_ID_ATRAC3) && - st->codecpar->block_align && track->audio.sub_packet_size) { -#if CONFIG_RA_288_DECODER || CONFIG_COOK_DECODER || CONFIG_ATRAC3_DECODER || CONFIG_SIPR_DECODER - res = matroska_parse_rm_audio(matroska, track, st, data, - lace_size[n], + if (track->needs_decoding) { + res = matroska_decode_buffer(&out_data, &out_size, track); + if (res < 0) + return res; + /* Given that we are here means that out_data is no longer + * owned by buf, so set it to NULL. This depends upon + * zero-length header removal compression being ignored. */ + av_assert1(out_data != data); + buf = NULL; + } + + if (track->audio.buf) { + res = matroska_parse_rm_audio(matroska, track, st, + out_data, out_size, timecode, pos); -#else - res = AVERROR_INVALIDDATA; -#endif + if (!buf) + av_free(out_data); if (res) return res; - } else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) { res = matroska_parse_webvtt(matroska, track, st, - data, lace_size[n], + out_data, out_size, timecode, lace_duration, pos); + if (!buf) + av_free(out_data); if (res) return res; } else { - res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n], - timecode, lace_duration, pos, - !n ? is_keyframe : 0, + res = matroska_parse_frame(matroska, track, st, buf, out_data, + out_size, timecode, lace_duration, + pos, !n ? is_keyframe : 0, additional, additional_id, additional_size, discard_padding); if (res) @@ -4170,15 +4190,18 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Failed to read file headers\n"); return -1; } - if (!s->nb_streams) { - matroska_read_close(s); - av_log(s, AV_LOG_ERROR, "No streams found\n"); - return AVERROR_INVALIDDATA; + if (!matroska->tracks.nb_elem || !s->nb_streams) { + av_log(s, AV_LOG_ERROR, "No track found\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } if (!matroska->is_live) { buf = av_asprintf("%g", matroska->duration); - if (!buf) return AVERROR(ENOMEM); + if (!buf) { + ret = AVERROR(ENOMEM); + goto fail; + } av_dict_set(&s->streams[0]->metadata, DURATION, buf, AV_DICT_DONT_STRDUP_VAL); @@ -4201,7 +4224,7 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) ret = webm_dash_manifest_cues(s, init_range); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Error parsing Cues\n"); - return ret; + goto fail; } } @@ -4211,6 +4234,9 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) matroska->bandwidth, 0); } return 0; +fail: + matroska_read_close(s); + return ret; } static int webm_dash_manifest_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c index 784973a9515..233c472b8f3 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c @@ -55,8 +55,11 @@ #include "libavcodec/mpeg4audio.h" /* Level 1 elements we create a SeekHead entry for: - * Info, Tracks, Chapters, Attachments, Tags and Cues */ -#define MAX_SEEKHEAD_ENTRIES 6 + * Info, Tracks, Chapters, Attachments, Tags (potentially twice) and Cues */ +#define MAX_SEEKHEAD_ENTRIES 7 + +#define IS_SEEKABLE(pb, mkv) (((pb)->seekable & AVIO_SEEKABLE_NORMAL) && \ + !(mkv)->is_live) enum { DEFAULT_MODE_INFER, @@ -69,6 +72,11 @@ typedef struct ebml_master { int sizebytes; ///< how many bytes were reserved for the size } ebml_master; +typedef struct ebml_stored_master { + AVIOContext *bc; + int64_t pos; +} ebml_stored_master; + typedef struct mkv_seekhead_entry { uint32_t elementid; uint64_t segmentpos; @@ -90,7 +98,7 @@ typedef struct mkv_cuepoint { } mkv_cuepoint; typedef struct mkv_cues { - mkv_cuepoint *entries; + mkv_cuepoint *entries; int num_entries; } mkv_cues; @@ -113,46 +121,43 @@ typedef struct mkv_track { #define MODE_WEBM 0x02 typedef struct MatroskaMuxContext { - const AVClass *class; - int mode; - AVIOContext *tags_bc; - int64_t tags_pos; - AVIOContext *info_bc; - int64_t info_pos; - AVIOContext *tracks_bc; - int64_t tracks_pos; - ebml_master segment; - int64_t segment_offset; - AVIOContext *cluster_bc; - int64_t cluster_pos; ///< file offset of the current cluster - int64_t cluster_pts; - int64_t duration_offset; - int64_t duration; - mkv_seekhead seekhead; - mkv_cues cues; - mkv_track *tracks; - - AVPacket cur_audio_pkt; - - unsigned nb_attachments; - int have_video; - - int reserve_cues_space; - int cluster_size_limit; - int64_t cues_pos; - int64_t cluster_time_limit; - int is_dash; - int dash_track_number; - int is_live; - int write_crc; - - uint32_t chapter_id_offset; - int wrote_chapters; - - int allow_raw_vfw; - int default_mode; - - uint32_t segment_uid[4]; + const AVClass *class; + int mode; + ebml_stored_master info; + ebml_stored_master track; + ebml_stored_master tags; + int64_t segment_offset; + AVIOContext *cluster_bc; + int64_t cluster_pos; ///< file offset of the current Cluster + int64_t cluster_pts; + int64_t duration_offset; + int64_t duration; + mkv_track *tracks; + mkv_seekhead seekhead; + mkv_cues cues; + int64_t cues_pos; + + AVPacket cur_audio_pkt; + + unsigned nb_attachments; + int have_video; + + int wrote_chapters; + int wrote_tags; + + int reserve_cues_space; + int cluster_size_limit; + int64_t cluster_time_limit; + int write_crc; + int is_live; + + int is_dash; + int dash_track_number; + int allow_raw_vfw; + int flipped_raw_rgb; + int default_mode; + + uint32_t segment_uid[4]; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -349,6 +354,17 @@ static void end_ebml_master(AVIOContext *pb, ebml_master master) avio_seek(pb, pos, SEEK_SET); } +static void mkv_add_seekhead_entry(MatroskaMuxContext *mkv, uint32_t elementid, + uint64_t filepos) +{ + mkv_seekhead *seekhead = &mkv->seekhead; + + av_assert1(seekhead->num_entries < MAX_SEEKHEAD_ENTRIES); + + seekhead->entries[seekhead->num_entries].elementid = elementid; + seekhead->entries[seekhead->num_entries++].segmentpos = filepos - mkv->segment_offset; +} + static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv) { int ret; @@ -362,15 +378,22 @@ static int start_ebml_master_crc32(AVIOContext **dyn_cp, MatroskaMuxContext *mkv return 0; } -static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, - MatroskaMuxContext *mkv, uint32_t id, - int length_size, int keep_buffer) +static int end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, + MatroskaMuxContext *mkv, uint32_t id, + int length_size, int keep_buffer, + int add_seekentry) { uint8_t *buf, crc[4]; - int size, skip = 0; + int ret, size, skip = 0; - put_ebml_id(pb, id); size = avio_get_dyn_buf(*dyn_cp, &buf); + if ((ret = (*dyn_cp)->error) < 0) + goto fail; + + if (add_seekentry) + mkv_add_seekhead_entry(mkv, id, avio_tell(pb)); + + put_ebml_id(pb, id); put_ebml_length(pb, size, length_size); if (mkv->write_crc) { skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ @@ -379,27 +402,40 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, } avio_write(pb, buf + skip, size - skip); +fail: if (keep_buffer) { ffio_reset_dyn_buf(*dyn_cp); } else { ffio_free_dyn_buf(dyn_cp); } + return ret; } /** -* Complete ebml master without destroying the buffer, allowing for later updates -*/ -static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext *dyn_cp, - uint32_t id, int64_t *pos) + * Output EBML master. Keep the buffer if seekable, allowing for later updates. + * Furthermore always add a SeekHead Entry for this element. + */ +static int end_ebml_master_crc32_tentatively(AVIOContext *pb, + ebml_stored_master *elem, + MatroskaMuxContext *mkv, uint32_t id) { - uint8_t *buf; - int size = avio_get_dyn_buf(dyn_cp, &buf); + if (IS_SEEKABLE(pb, mkv)) { + uint8_t *buf; + int size = avio_get_dyn_buf(elem->bc, &buf); - *pos = avio_tell(pb); + if (elem->bc->error < 0) + return elem->bc->error; - put_ebml_id(pb, id); - put_ebml_length(pb, size, 0); - avio_write(pb, buf, size); + elem->pos = avio_tell(pb); + mkv_add_seekhead_entry(mkv, id, elem->pos); + + put_ebml_id(pb, id); + put_ebml_length(pb, size, 0); + avio_write(pb, buf, size); + + return 0; + } else + return end_ebml_master_crc32(pb, &elem->bc, mkv, id, 0, 0, 1); } static void put_xiph_size(AVIOContext *pb, int size) @@ -418,9 +454,9 @@ static void mkv_deinit(AVFormatContext *s) av_packet_unref(&mkv->cur_audio_pkt); ffio_free_dyn_buf(&mkv->cluster_bc); - ffio_free_dyn_buf(&mkv->info_bc); - ffio_free_dyn_buf(&mkv->tracks_bc); - ffio_free_dyn_buf(&mkv->tags_bc); + ffio_free_dyn_buf(&mkv->info.bc); + ffio_free_dyn_buf(&mkv->track.bc); + ffio_free_dyn_buf(&mkv->tags.bc); av_freep(&mkv->cues.entries); av_freep(&mkv->tracks); @@ -441,17 +477,6 @@ static void mkv_start_seekhead(MatroskaMuxContext *mkv, AVIOContext *pb) put_ebml_void(pb, mkv->seekhead.reserved_size); } -static void mkv_add_seekhead_entry(MatroskaMuxContext *mkv, uint32_t elementid, - uint64_t filepos) -{ - mkv_seekhead *seekhead = &mkv->seekhead; - - av_assert1(seekhead->num_entries < MAX_SEEKHEAD_ENTRIES); - - seekhead->entries[seekhead->num_entries].elementid = elementid; - seekhead->entries[seekhead->num_entries++].segmentpos = filepos - mkv->segment_offset; -} - /** * Write the SeekHead to the file at the location reserved for it * and seek to destpos afterwards. When error_on_seek_failure @@ -489,7 +514,10 @@ static int mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv, put_ebml_uint(dyn_cp, MATROSKA_ID_SEEKPOSITION, entry->segmentpos); end_ebml_master(dyn_cp, seekentry); } - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD, 0, 0); + ret = end_ebml_master_crc32(pb, &dyn_cp, mkv, + MATROSKA_ID_SEEKHEAD, 0, 0, 0); + if (ret < 0) + return ret; remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); put_ebml_void(pb, remaining); @@ -562,12 +590,14 @@ static int mkv_assemble_cues(AVStream **streams, AVIOContext *dyn_cp, end_ebml_master(cuepoint, track_positions); } while (++entry < end && entry->pts == pts); size = avio_get_dyn_buf(cuepoint, &buf); + if ((ret = cuepoint->error) < 0) + break; put_ebml_binary(dyn_cp, MATROSKA_ID_POINTENTRY, buf, size); ffio_reset_dyn_buf(cuepoint); } ffio_free_dyn_buf(&cuepoint); - return 0; + return ret; } static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, @@ -576,17 +606,18 @@ static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, const uint8_t *header_start[3]; int header_len[3]; int first_header_size; - int j; + int err, j; if (par->codec_id == AV_CODEC_ID_VORBIS) first_header_size = 30; else first_header_size = 42; - if (avpriv_split_xiph_headers(par->extradata, par->extradata_size, - first_header_size, header_start, header_len) < 0) { + err = avpriv_split_xiph_headers(par->extradata, par->extradata_size, + first_header_size, header_start, header_len); + if (err < 0) { av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n"); - return -1; + return err; } avio_w8(pb, 2); // number packets - 1 @@ -624,42 +655,29 @@ static int put_flac_codecpriv(AVFormatContext *s, AVIOContext *pb, const char *vendor = (s->flags & AVFMT_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT; AVDictionary *dict = NULL; - uint8_t buf[32], *data, *p; + uint8_t buf[32]; int64_t len; snprintf(buf, sizeof(buf), "0x%"PRIx64, par->channel_layout); av_dict_set(&dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", buf, 0); len = ff_vorbiscomment_length(dict, vendor, NULL, 0); - if (len >= (1 << 24) - 4) { - av_dict_free(&dict); - return AVERROR(EINVAL); - } - - data = av_malloc(len + 4); - if (!data) { - av_dict_free(&dict); - return AVERROR(ENOMEM); - } - - data[0] = 0x84; - AV_WB24(data + 1, len); + av_assert1(len < (1 << 24) - 4); - p = data + 4; - ff_vorbiscomment_write(&p, &dict, vendor, NULL, 0); + avio_w8(pb, 0x84); + avio_wb24(pb, len); - avio_write(pb, data, len + 4); + ff_vorbiscomment_write(pb, dict, vendor, NULL, 0); - av_freep(&data); av_dict_free(&dict); } return 0; } -static int get_aac_sample_rates(AVFormatContext *s, const uint8_t *extradata, - int extradata_size, int *sample_rate, - int *output_sample_rate) +static int get_aac_sample_rates(AVFormatContext *s, MatroskaMuxContext *mkv, + const uint8_t *extradata, int extradata_size, + int *sample_rate, int *output_sample_rate) { MPEG4AudioConfig mp4ac; int ret; @@ -670,7 +688,7 @@ static int get_aac_sample_rates(AVFormatContext *s, const uint8_t *extradata, * first packet. * Abort however if s->pb is not seekable, as we would not be able to seek back * to write the sample rate elements once the extradata shows up, anyway. */ - if (ret < 0 && (extradata_size || !(s->pb->seekable & AVIO_SEEKABLE_NORMAL))) { + if (ret < 0 && (extradata_size || !IS_SEEKABLE(s->pb, mkv))) { av_log(s, AV_LOG_ERROR, "Error parsing AAC extradata, unable to determine samplerate.\n"); return AVERROR(EINVAL); @@ -747,6 +765,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, int native_id, int qt_id) { AVIOContext *dyn_cp; + MatroskaMuxContext *mkv = s->priv_data; uint8_t *codecpriv; int ret, codecpriv_size; @@ -785,7 +804,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, ret = AVERROR(EINVAL); } - ff_put_bmp_header(dyn_cp, par, 0, 0); + ff_put_bmp_header(dyn_cp, par, 0, 0, mkv->flipped_raw_rgb); } } else if (par->codec_type == AVMEDIA_TYPE_AUDIO) { unsigned int tag; @@ -801,26 +820,28 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, ff_put_wav_header(s, dyn_cp, par, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); } - codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); - if (codecpriv_size) - put_ebml_binary(pb, MATROSKA_ID_CODECPRIVATE, codecpriv, - codecpriv_size); + if (ret >= 0) { + codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); + if ((ret = dyn_cp->error) >= 0 && codecpriv_size) + put_ebml_binary(pb, MATROSKA_ID_CODECPRIVATE, codecpriv, + codecpriv_size); + } ffio_free_dyn_buf(&dyn_cp); return ret; } -static int mkv_write_video_color(AVIOContext *pb, const AVCodecParameters *par, - const AVStream *st) +static void mkv_write_video_color(AVIOContext *pb, const AVStream *st, + const AVCodecParameters *par) { - AVIOContext *dyn_cp; - uint8_t *colorinfo_ptr; - int side_data_size = 0; - int ret, colorinfo_size; - const uint8_t *side_data; + /* 18 Elements with two bytes ID, one byte length field, 8 bytes payload + * a master element with two bytes ID and one byte length field + * plus another byte to stay clear of the end. */ + uint8_t colour[(2 + 1 + 8) * 18 + (2 + 1) + 1]; + AVIOContext buf, *dyn_cp = &buf; + int colorinfo_size; + const void *side_data; - ret = avio_open_dyn_buf(&dyn_cp); - if (ret < 0) - return ret; + ffio_init_context(dyn_cp, colour, sizeof(colour), 1, NULL, NULL, NULL, NULL); if (par->color_trc != AVCOL_TRC_UNSPECIFIED && par->color_trc < AVCOL_TRC_NB) { @@ -849,21 +870,19 @@ static int mkv_write_video_color(AVIOContext *pb, const AVCodecParameters *par, } side_data = av_stream_get_side_data(st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, - &side_data_size); - if (side_data_size) { - const AVContentLightMetadata *metadata = - (const AVContentLightMetadata*)side_data; + NULL); + if (side_data) { + const AVContentLightMetadata *metadata = side_data; put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXCLL, metadata->MaxCLL); put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXFALL, metadata->MaxFALL); } side_data = av_stream_get_side_data(st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, - &side_data_size); - if (side_data_size == sizeof(AVMasteringDisplayMetadata)) { + NULL); + if (side_data) { ebml_master meta_element = start_ebml_master( dyn_cp, MATROSKA_ID_VIDEOCOLORMASTERINGMETA, 10 * (2 + 1 + 8)); - const AVMasteringDisplayMetadata *metadata = - (const AVMasteringDisplayMetadata*)side_data; + const AVMasteringDisplayMetadata *metadata = side_data; if (metadata->has_primaries) { put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_RX, av_q2d(metadata->display_primaries[0][0])); @@ -891,35 +910,29 @@ static int mkv_write_video_color(AVIOContext *pb, const AVCodecParameters *par, end_ebml_master(dyn_cp, meta_element); } - colorinfo_size = avio_get_dyn_buf(dyn_cp, &colorinfo_ptr); - if (colorinfo_size) { - ebml_master colorinfo = start_ebml_master(pb, MATROSKA_ID_VIDEOCOLOR, colorinfo_size); - avio_write(pb, colorinfo_ptr, colorinfo_size); - end_ebml_master(pb, colorinfo); - } - ffio_free_dyn_buf(&dyn_cp); - return 0; + colorinfo_size = avio_tell(dyn_cp); + if (colorinfo_size) + put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLOR, colour, colorinfo_size); } -static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, - const AVStream *st) +static void mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, + const AVStream *st) { ebml_master projection; - int side_data_size = 0; uint8_t private[20]; const AVSphericalMapping *spherical = (const AVSphericalMapping *)av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, - &side_data_size); + NULL); - if (!side_data_size) - return 0; + if (!spherical) + return; if (spherical->projection != AV_SPHERICAL_EQUIRECTANGULAR && spherical->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE && spherical->projection != AV_SPHERICAL_CUBEMAP) { av_log(s, AV_LOG_WARNING, "Unknown projection type\n"); - return 0; + return; } // Maximally 4 8-byte elements with id-length 2 + 1 byte length field @@ -967,8 +980,6 @@ static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, (double) spherical->roll / (1 << 16)); end_ebml_master(pb, projection); - - return 0; } static void mkv_write_field_order(AVIOContext *pb, int mode, @@ -1013,10 +1024,9 @@ static void mkv_write_field_order(AVIOContext *pb, int mode, static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb, AVStream *st, int mode, int *h_width, int *h_height) { - int i; - int ret = 0; const AVDictionaryEntry *tag; MatroskaVideoStereoModeType format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB; + const AVStereo3D *stereo; *h_width = 1; *h_height = 1; @@ -1025,7 +1035,7 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb, (tag = av_dict_get( s->metadata, "stereo_mode", NULL, 0))) { int stereo_mode = atoi(tag->value); - for (i=0; i<MATROSKA_VIDEO_STEREOMODE_TYPE_NB; i++) + for (int i = 0; i < MATROSKA_VIDEO_STEREOMODE_TYPE_NB; i++) if (!strcmp(tag->value, ff_matroska_video_stereo_mode[i])){ stereo_mode = i; break; @@ -1039,57 +1049,52 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb, } } - // iterate to find the stereo3d side data - for (i = 0; i < st->nb_side_data; i++) { - AVPacketSideData sd = st->side_data[i]; - if (sd.type == AV_PKT_DATA_STEREO3D) { - AVStereo3D *stereo = (AVStereo3D *)sd.data; - - switch (stereo->type) { - case AV_STEREO3D_2D: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_MONO; - break; - case AV_STEREO3D_SIDEBYSIDE: - format = (stereo->flags & AV_STEREO3D_FLAG_INVERT) - ? MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT - : MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT; - *h_width = 2; - break; - case AV_STEREO3D_TOPBOTTOM: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM; - if (stereo->flags & AV_STEREO3D_FLAG_INVERT) - format--; - *h_height = 2; - break; - case AV_STEREO3D_CHECKERBOARD: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR; - if (stereo->flags & AV_STEREO3D_FLAG_INVERT) - format--; - break; - case AV_STEREO3D_LINES: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR; - if (stereo->flags & AV_STEREO3D_FLAG_INVERT) - format--; - *h_height = 2; - break; - case AV_STEREO3D_COLUMNS: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR; - if (stereo->flags & AV_STEREO3D_FLAG_INVERT) - format--; - *h_width = 2; - break; - case AV_STEREO3D_FRAMESEQUENCE: - format = MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR; - if (stereo->flags & AV_STEREO3D_FLAG_INVERT) - format++; - break; - } + stereo = (const AVStereo3D*)av_stream_get_side_data(st, AV_PKT_DATA_STEREO3D, + NULL); + if (stereo) { + switch (stereo->type) { + case AV_STEREO3D_2D: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_MONO; + break; + case AV_STEREO3D_SIDEBYSIDE: + format = (stereo->flags & AV_STEREO3D_FLAG_INVERT) + ? MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT + : MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT; + *h_width = 2; + break; + case AV_STEREO3D_TOPBOTTOM: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM; + if (stereo->flags & AV_STEREO3D_FLAG_INVERT) + format--; + *h_height = 2; + break; + case AV_STEREO3D_CHECKERBOARD: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR; + if (stereo->flags & AV_STEREO3D_FLAG_INVERT) + format--; + break; + case AV_STEREO3D_LINES: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR; + if (stereo->flags & AV_STEREO3D_FLAG_INVERT) + format--; + *h_height = 2; + break; + case AV_STEREO3D_COLUMNS: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR; + if (stereo->flags & AV_STEREO3D_FLAG_INVERT) + format--; + *h_width = 2; + break; + case AV_STEREO3D_FRAMESEQUENCE: + format = MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR; + if (stereo->flags & AV_STEREO3D_FLAG_INVERT) + format++; break; } } if (format == MATROSKA_VIDEO_STEREOMODE_TYPE_NB) - return ret; + return 0; // if webm, do not write unsupported modes if ((mode == MODE_WEBM && @@ -1098,14 +1103,13 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb, || format >= MATROSKA_VIDEO_STEREOMODE_TYPE_NB) { av_log(s, AV_LOG_ERROR, "The specified stereo mode is not valid.\n"); - format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB; return AVERROR(EINVAL); } // write StereoMode if format is valid put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, format); - return ret; + return 0; } static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, @@ -1128,8 +1132,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, return 0; if (par->codec_id == AV_CODEC_ID_AAC) { - ret = get_aac_sample_rates(s, par->extradata, par->extradata_size, &sample_rate, - &output_sample_rate); + ret = get_aac_sample_rates(s, mkv, par->extradata, par->extradata_size, + &sample_rate, &output_sample_rate); if (ret < 0) return ret; } @@ -1291,12 +1295,9 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, uint32_t color_space = av_le2ne32(par->codec_tag); put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLORSPACE, &color_space, sizeof(color_space)); } - ret = mkv_write_video_color(pb, par, st); - if (ret < 0) - return ret; - ret = mkv_write_video_projection(s, pb, st); - if (ret < 0) - return ret; + mkv_write_video_color(pb, st, par); + mkv_write_video_projection(s, pb, st); + end_ebml_master(pb, subinfo); break; @@ -1383,9 +1384,7 @@ static int mkv_write_tracks(AVFormatContext *s) if (mkv->nb_attachments == s->nb_streams) return 0; - mkv_add_seekhead_entry(mkv, MATROSKA_ID_TRACKS, avio_tell(pb)); - - ret = start_ebml_master_crc32(&mkv->tracks_bc, mkv); + ret = start_ebml_master_crc32(&mkv->track.bc, mkv); if (ret < 0) return ret; @@ -1425,72 +1424,13 @@ static int mkv_write_tracks(AVFormatContext *s) i == video_default_idx || i == audio_default_idx || i == subtitle_default_idx; ret = mkv_write_track(s, mkv, st, &mkv->tracks[i], - mkv->tracks_bc, is_default); + mkv->track.bc, is_default); if (ret < 0) return ret; } - if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(pb, mkv->tracks_bc, - MATROSKA_ID_TRACKS, &mkv->tracks_pos); - else - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS, 0, 0); - - return 0; -} - -static int mkv_write_chapters(AVFormatContext *s) -{ - MatroskaMuxContext *mkv = s->priv_data; - AVIOContext *dyn_cp = NULL, *pb = s->pb; - ebml_master editionentry; - AVRational scale = {1, 1E9}; - int i, ret; - - if (!s->nb_chapters || mkv->wrote_chapters) - return 0; - - mkv_add_seekhead_entry(mkv, MATROSKA_ID_CHAPTERS, avio_tell(pb)); - - ret = start_ebml_master_crc32(&dyn_cp, mkv); - if (ret < 0) - return ret; - - editionentry = start_ebml_master(dyn_cp, MATROSKA_ID_EDITIONENTRY, 0); - if (mkv->mode != MODE_WEBM) - put_ebml_uint(dyn_cp, MATROSKA_ID_EDITIONFLAGDEFAULT, 1); - - for (i = 0; i < s->nb_chapters; i++) { - ebml_master chapteratom, chapterdisplay; - const AVChapter *c = s->chapters[i]; - int64_t chapterstart = av_rescale_q(c->start, c->time_base, scale); - int64_t chapterend = av_rescale_q(c->end, c->time_base, scale); - const AVDictionaryEntry *t; - if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) { - av_log(s, AV_LOG_ERROR, - "Invalid chapter start (%"PRId64") or end (%"PRId64").\n", - chapterstart, chapterend); - return AVERROR_INVALIDDATA; - } - - chapteratom = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERATOM, 0); - put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID, - (uint32_t)c->id + (uint64_t)mkv->chapter_id_offset); - put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMESTART, chapterstart); - put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMEEND, chapterend); - if ((t = av_dict_get(c->metadata, "title", NULL, 0))) { - chapterdisplay = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERDISPLAY, 0); - put_ebml_string(dyn_cp, MATROSKA_ID_CHAPSTRING, t->value); - put_ebml_string(dyn_cp, MATROSKA_ID_CHAPLANG , "und"); - end_ebml_master(dyn_cp, chapterdisplay); - } - end_ebml_master(dyn_cp, chapteratom); - } - end_ebml_master(dyn_cp, editionentry); - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS, 0, 0); - - mkv->wrote_chapters = 1; - return 0; + return end_ebml_master_crc32_tentatively(pb, &mkv->track, mkv, + MATROSKA_ID_TRACKS); } static int mkv_write_simpletag(AVIOContext *pb, const AVDictionaryEntry *t) @@ -1527,28 +1467,23 @@ static int mkv_write_simpletag(AVIOContext *pb, const AVDictionaryEntry *t) return 0; } -static int mkv_write_tag_targets(AVFormatContext *s, uint32_t elementid, - uint64_t uid, ebml_master *tag) +static int mkv_write_tag_targets(MatroskaMuxContext *mkv, AVIOContext **pb, + ebml_master *tag, uint32_t elementid, uint64_t uid) { - AVIOContext *pb; - MatroskaMuxContext *mkv = s->priv_data; ebml_master targets; int ret; - if (!mkv->tags_bc) { - mkv_add_seekhead_entry(mkv, MATROSKA_ID_TAGS, avio_tell(s->pb)); - - ret = start_ebml_master_crc32(&mkv->tags_bc, mkv); + if (!*pb) { + ret = start_ebml_master_crc32(pb, mkv); if (ret < 0) return ret; } - pb = mkv->tags_bc; - *tag = start_ebml_master(pb, MATROSKA_ID_TAG, 0); - targets = start_ebml_master(pb, MATROSKA_ID_TAGTARGETS, 4 + 1 + 8); + *tag = start_ebml_master(*pb, MATROSKA_ID_TAG, 0); + targets = start_ebml_master(*pb, MATROSKA_ID_TAGTARGETS, 4 + 1 + 8); if (elementid) - put_ebml_uid(pb, elementid, uid); - end_ebml_master(pb, targets); + put_ebml_uid(*pb, elementid, uid); + end_ebml_master(*pb, targets); return 0; } @@ -1566,28 +1501,28 @@ static int mkv_check_tag_name(const char *name, uint32_t elementid) av_strcasecmp(name, "mimetype"))); } -static int mkv_write_tag(AVFormatContext *s, const AVDictionary *m, - uint32_t elementid, uint64_t uid, ebml_master *tag) +static int mkv_write_tag(MatroskaMuxContext *mkv, const AVDictionary *m, + AVIOContext **pb, ebml_master *tag, + uint32_t elementid, uint64_t uid) { - MatroskaMuxContext *mkv = s->priv_data; const AVDictionaryEntry *t = NULL; ebml_master tag2; int ret; - ret = mkv_write_tag_targets(s, elementid, uid, tag ? tag : &tag2); + ret = mkv_write_tag_targets(mkv, pb, tag ? tag : &tag2, elementid, uid); if (ret < 0) return ret; while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { if (mkv_check_tag_name(t->key, elementid)) { - ret = mkv_write_simpletag(mkv->tags_bc, t); + ret = mkv_write_simpletag(*pb, t); if (ret < 0) return ret; } } if (!tag) - end_ebml_master(mkv->tags_bc, tag2); + end_ebml_master(*pb, tag2); return 0; } @@ -1606,18 +1541,19 @@ static int mkv_check_tag(const AVDictionary *m, uint32_t elementid) static int mkv_write_tags(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - ebml_master tag, *tagp; + ebml_master tag, *tagp = IS_SEEKABLE(s->pb, mkv) ? &tag : NULL; int i, ret; + mkv->wrote_tags = 1; + ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL); if (mkv_check_tag(s->metadata, 0)) { - ret = mkv_write_tag(s, s->metadata, 0, 0, NULL); + ret = mkv_write_tag(mkv, s->metadata, &mkv->tags.bc, NULL, 0, 0); if (ret < 0) return ret; } - tagp = (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live ? &tag : NULL; for (i = 0; i < s->nb_streams; i++) { const AVStream *st = s->streams[i]; mkv_track *track = &mkv->tracks[i]; @@ -1628,13 +1564,13 @@ static int mkv_write_tags(AVFormatContext *s) if (!tagp && !mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, - track->uid, tagp); + ret = mkv_write_tag(mkv, st->metadata, &mkv->tags.bc, tagp, + MATROSKA_ID_TAGTARGETS_TRACKUID, track->uid); if (ret < 0) return ret; if (tagp) { - AVIOContext *pb = mkv->tags_bc; + AVIOContext *pb = mkv->tags.bc; ebml_master simpletag; simpletag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, @@ -1650,21 +1586,6 @@ static int mkv_write_tags(AVFormatContext *s) } } - if (mkv->mode != MODE_WEBM) { - for (i = 0; i < s->nb_chapters; i++) { - AVChapter *ch = s->chapters[i]; - - if (!mkv_check_tag(ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) - continue; - - ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, - (uint32_t)ch->id + (uint64_t)mkv->chapter_id_offset, - NULL); - if (ret < 0) - return ret; - } - } - if (mkv->nb_attachments && mkv->mode != MODE_WEBM) { for (i = 0; i < s->nb_streams; i++) { const mkv_track *track = &mkv->tracks[i]; @@ -1676,23 +1597,124 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, - track->uid, NULL); + ret = mkv_write_tag(mkv, st->metadata, &mkv->tags.bc, NULL, + MATROSKA_ID_TAGTARGETS_ATTACHUID, track->uid); if (ret < 0) return ret; } } - if (mkv->tags_bc) { - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(s->pb, mkv->tags_bc, - MATROSKA_ID_TAGS, &mkv->tags_pos); - else - end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0, 0); + if (mkv->tags.bc) { + return end_ebml_master_crc32_tentatively(s->pb, &mkv->tags, mkv, + MATROSKA_ID_TAGS); } return 0; } +static int mkv_write_chapters(AVFormatContext *s) +{ + MatroskaMuxContext *mkv = s->priv_data; + AVIOContext *dyn_cp = NULL, *dyn_tags = NULL, **tags, *pb = s->pb; + ebml_master editionentry; + uint64_t chapter_id_offset = 0; + AVRational scale = {1, 1E9}; + int i, ret; + + if (!s->nb_chapters || mkv->wrote_chapters) + return 0; + + for (i = 0; i < s->nb_chapters; i++) + if (!s->chapters[i]->id) { + chapter_id_offset = 1; + break; + } + + ret = start_ebml_master_crc32(&dyn_cp, mkv); + if (ret < 0) + return ret; + + editionentry = start_ebml_master(dyn_cp, MATROSKA_ID_EDITIONENTRY, 0); + if (mkv->mode != MODE_WEBM) { + put_ebml_uint(dyn_cp, MATROSKA_ID_EDITIONFLAGDEFAULT, 1); + /* If mkv_write_tags() has already been called, then any tags + * corresponding to chapters will be put into a new Tags element. */ + tags = mkv->wrote_tags ? &dyn_tags : &mkv->tags.bc; + } else + tags = NULL; + + for (i = 0; i < s->nb_chapters; i++) { + ebml_master chapteratom, chapterdisplay; + const AVChapter *c = s->chapters[i]; + int64_t chapterstart = av_rescale_q(c->start, c->time_base, scale); + int64_t chapterend = av_rescale_q(c->end, c->time_base, scale); + const AVDictionaryEntry *t; + if (chapterstart < 0 || chapterstart > chapterend || chapterend < 0) { + av_log(s, AV_LOG_ERROR, + "Invalid chapter start (%"PRId64") or end (%"PRId64").\n", + chapterstart, chapterend); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + chapteratom = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERATOM, 0); + put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERUID, + (uint32_t)c->id + chapter_id_offset); + put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMESTART, chapterstart); + put_ebml_uint(dyn_cp, MATROSKA_ID_CHAPTERTIMEEND, chapterend); + if ((t = av_dict_get(c->metadata, "title", NULL, 0))) { + chapterdisplay = start_ebml_master(dyn_cp, MATROSKA_ID_CHAPTERDISPLAY, 0); + put_ebml_string(dyn_cp, MATROSKA_ID_CHAPSTRING, t->value); + put_ebml_string(dyn_cp, MATROSKA_ID_CHAPLANG , "und"); + end_ebml_master(dyn_cp, chapterdisplay); + } + end_ebml_master(dyn_cp, chapteratom); + + if (tags && mkv_check_tag(c->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) { + ret = mkv_write_tag(mkv, c->metadata, tags, NULL, + MATROSKA_ID_TAGTARGETS_CHAPTERUID, + (uint32_t)c->id + chapter_id_offset); + if (ret < 0) + goto fail; + } + } + end_ebml_master(dyn_cp, editionentry); + mkv->wrote_chapters = 1; + + ret = end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS, 0, 0, 1); + if (ret < 0) + goto fail; + if (dyn_tags) + return end_ebml_master_crc32(pb, &dyn_tags, mkv, + MATROSKA_ID_TAGS, 0, 0, 1); + return 0; + +fail: + if (tags) { + /* tags == &mkv->tags.bc can only happen if mkv->tags.bc was + * initially NULL, so we never free older tags. */ + ffio_free_dyn_buf(tags); + } + ffio_free_dyn_buf(&dyn_cp); + return ret; +} + +static const char *get_mimetype(const AVStream *st) +{ + const AVDictionaryEntry *t; + + if (t = av_dict_get(st->metadata, "mimetype", NULL, 0)) + return t->value; + if (st->codecpar->codec_id != AV_CODEC_ID_NONE) { + const AVCodecDescriptor *desc = avcodec_descriptor_get(st->codecpar->codec_id); + if (desc && desc->mime_types) { + return desc->mime_types[0]; + } else if (st->codecpar->codec_id == AV_CODEC_ID_TEXT) + return "text/plain"; + } + + return NULL; +} + static int mkv_write_attachments(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; @@ -1702,8 +1724,6 @@ static int mkv_write_attachments(AVFormatContext *s) if (!mkv->nb_attachments) return 0; - mkv_add_seekhead_entry(mkv, MATROSKA_ID_ATTACHMENTS, avio_tell(pb)); - ret = start_ebml_master_crc32(&dyn_cp, mkv); if (ret < 0) return ret; @@ -1713,7 +1733,7 @@ static int mkv_write_attachments(AVFormatContext *s) mkv_track *track = &mkv->tracks[i]; ebml_master attached_file; const AVDictionaryEntry *t; - const char *mimetype = NULL; + const char *mimetype; if (st->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT) continue; @@ -1727,29 +1747,16 @@ static int mkv_write_attachments(AVFormatContext *s) return AVERROR(EINVAL); } put_ebml_string(dyn_cp, MATROSKA_ID_FILENAME, t->value); - if (t = av_dict_get(st->metadata, "mimetype", NULL, 0)) - mimetype = t->value; - else if (st->codecpar->codec_id != AV_CODEC_ID_NONE ) { - const AVCodecDescriptor *desc = avcodec_descriptor_get(st->codecpar->codec_id); - if (desc && desc->mime_types) { - mimetype = desc->mime_types[0]; - } else if (st->codecpar->codec_id == AV_CODEC_ID_TEXT) - mimetype = "text/plain"; - } - if (!mimetype) { - av_log(s, AV_LOG_ERROR, "Attachment stream %d has no mimetype tag and " - "it cannot be deduced from the codec id.\n", i); - return AVERROR(EINVAL); - } + mimetype = get_mimetype(st); + av_assert0(mimetype); put_ebml_string(dyn_cp, MATROSKA_ID_FILEMIMETYPE, mimetype); put_ebml_binary(dyn_cp, MATROSKA_ID_FILEDATA, st->codecpar->extradata, st->codecpar->extradata_size); put_ebml_uid(dyn_cp, MATROSKA_ID_FILEUID, track->uid); end_ebml_master(dyn_cp, attached_file); } - end_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS, 0, 0); - - return 0; + return end_ebml_master_crc32(pb, &dyn_cp, mkv, + MATROSKA_ID_ATTACHMENTS, 0, 0, 1); } static int64_t get_metadata_duration(AVFormatContext *s) @@ -1807,19 +1814,18 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION, 2); end_ebml_master(pb, ebml_header); - mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT, 0); + put_ebml_id(pb, MATROSKA_ID_SEGMENT); + put_ebml_size_unknown(pb, 8); mkv->segment_offset = avio_tell(pb); - // we write a seek head at the beginning to point to all other level + // We write a SeekHead at the beginning to point to all other level // one elements (except Clusters). mkv_start_seekhead(mkv, pb); - mkv_add_seekhead_entry(mkv, MATROSKA_ID_INFO, avio_tell(pb)); - - ret = start_ebml_master_crc32(&mkv->info_bc, mkv); + ret = start_ebml_master_crc32(&mkv->info.bc, mkv); if (ret < 0) return ret; - pb = mkv->info_bc; + pb = mkv->info.bc; put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) @@ -1861,27 +1867,20 @@ static int mkv_write_header(AVFormatContext *s) int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); - } else { + } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { put_ebml_void(pb, 11); // assumes double-precision float to be written } } - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(s->pb, mkv->info_bc, - MATROSKA_ID_INFO, &mkv->info_pos); - else - end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0, 0); + ret = end_ebml_master_crc32_tentatively(s->pb, &mkv->info, + mkv, MATROSKA_ID_INFO); + if (ret < 0) + return ret; pb = s->pb; ret = mkv_write_tracks(s); if (ret < 0) return ret; - for (i = 0; i < s->nb_chapters; i++) - if (!s->chapters[i]->id) { - mkv->chapter_id_offset = 1; - break; - } - ret = mkv_write_chapters(s); if (ret < 0) return ret; @@ -1892,11 +1891,13 @@ static int mkv_write_header(AVFormatContext *s) return ret; } + /* Must come after mkv_write_chapters() to write chapter tags + * into the same Tags element as the other tags. */ ret = mkv_write_tags(s); if (ret < 0) return ret; - if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { + if (!IS_SEEKABLE(pb, mkv)) { ret = mkv_write_seekhead(pb, mkv, 0, avio_tell(pb)); if (ret < 0) return ret; @@ -1908,11 +1909,14 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_void(pb, s->metadata_header_padding); } - if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mkv->reserve_cues_space) { - mkv->cues_pos = avio_tell(pb); - if (mkv->reserve_cues_space == 1) - mkv->reserve_cues_space++; - put_ebml_void(pb, mkv->reserve_cues_space); + if (mkv->reserve_cues_space) { + if (IS_SEEKABLE(pb, mkv)) { + mkv->cues_pos = avio_tell(pb); + if (mkv->reserve_cues_space == 1) + mkv->reserve_cues_space++; + put_ebml_void(pb, mkv->reserve_cues_space); + } else + mkv->reserve_cues_space = -1; } av_init_packet(&mkv->cur_audio_pkt); @@ -1921,7 +1925,7 @@ static int mkv_write_header(AVFormatContext *s) // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or // after 4k and on a keyframe - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { + if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) mkv->cluster_time_limit = 5000; if (mkv->cluster_size_limit < 0) @@ -2005,7 +2009,7 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; mkv_track *track = &mkv->tracks[pkt->stream_index]; uint8_t *data = NULL, *side_data = NULL; - int err = 0, offset = 0, size = pkt->size, side_data_size = 0; + int err = 0, offset = 0, size = pkt->size, side_data_size; int64_t ts = track->write_dts ? pkt->dts : pkt->pts; uint64_t additional_id; int64_t discard_padding = 0; @@ -2116,17 +2120,17 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac mkv_track *track = &mkv->tracks[pkt->stream_index]; ebml_master blockgroup; int id_size, settings_size, size; - uint8_t *id, *settings; + const char *id, *settings; int64_t ts = track->write_dts ? pkt->dts : pkt->pts; const int flags = 0; - id_size = 0; id = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_IDENTIFIER, &id_size); + id = id ? id : ""; - settings_size = 0; settings = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_SETTINGS, &settings_size); + settings = settings ? settings : ""; size = id_size + 1 + settings_size + 1 + pkt->size; @@ -2155,17 +2159,23 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, const AVPac return pkt->duration; } -static void mkv_end_cluster(AVFormatContext *s) +static int mkv_end_cluster(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; + int ret; - end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER, 0, 1); if (!mkv->have_video) { for (unsigned i = 0; i < s->nb_streams; i++) mkv->tracks[i].has_cue = 0; } mkv->cluster_pos = -1; + ret = end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, + MATROSKA_ID_CLUSTER, 0, 1, 0); + if (ret < 0) + return ret; + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); + return 0; } static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) @@ -2174,17 +2184,17 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) mkv_track *track = &mkv->tracks[pkt->stream_index]; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; uint8_t *side_data; - int side_data_size = 0, ret; + int side_data_size, ret; side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size); switch (par->codec_id) { case AV_CODEC_ID_AAC: - if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { + if (side_data_size && mkv->track.bc) { int filler, output_sample_rate = 0; - ret = get_aac_sample_rates(s, side_data, side_data_size, &track->sample_rate, - &output_sample_rate); + ret = get_aac_sample_rates(s, mkv, side_data, side_data_size, + &track->sample_rate, &output_sample_rate); if (ret < 0) return ret; if (!output_sample_rate) @@ -2193,14 +2203,14 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) if (ret < 0) return ret; memcpy(par->extradata, side_data, side_data_size); - avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET); - mkv_write_codecprivate(s, mkv->tracks_bc, par, 1, 0); - filler = MAX_PCE_SIZE + 2 + 4 - (avio_tell(mkv->tracks_bc) - track->codecpriv_offset); + avio_seek(mkv->track.bc, track->codecpriv_offset, SEEK_SET); + mkv_write_codecprivate(s, mkv->track.bc, par, 1, 0); + filler = MAX_PCE_SIZE + 2 + 4 - (avio_tell(mkv->track.bc) - track->codecpriv_offset); if (filler) - put_ebml_void(mkv->tracks_bc, filler); - avio_seek(mkv->tracks_bc, track->sample_rate_offset, SEEK_SET); - put_ebml_float(mkv->tracks_bc, MATROSKA_ID_AUDIOSAMPLINGFREQ, track->sample_rate); - put_ebml_float(mkv->tracks_bc, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate); + put_ebml_void(mkv->track.bc, filler); + avio_seek(mkv->track.bc, track->sample_rate_offset, SEEK_SET); + put_ebml_float(mkv->track.bc, MATROSKA_ID_AUDIOSAMPLINGFREQ, track->sample_rate); + put_ebml_float(mkv->track.bc, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate); } else if (!par->extradata_size && !track->sample_rate) { // No extradata (codecpar or packet side data). av_log(s, AV_LOG_ERROR, "Error parsing AAC extradata, unable to determine samplerate.\n"); @@ -2208,7 +2218,7 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) } break; case AV_CODEC_ID_FLAC: - if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { + if (side_data_size && mkv->track.bc) { uint8_t *old_extradata = par->extradata; if (side_data_size != par->extradata_size) { av_log(s, AV_LOG_ERROR, "Invalid FLAC STREAMINFO metadata for output stream %d\n", @@ -2216,16 +2226,15 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) return AVERROR(EINVAL); } par->extradata = side_data; - avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET); - mkv_write_codecprivate(s, mkv->tracks_bc, par, 1, 0); + avio_seek(mkv->track.bc, track->codecpriv_offset, SEEK_SET); + mkv_write_codecprivate(s, mkv->track.bc, par, 1, 0); par->extradata = old_extradata; } break; // FIXME: Remove the following once libaom starts propagating extradata during init() // See https://bugs.chromium.org/p/aomedia/issues/detail?id=2012 case AV_CODEC_ID_AV1: - if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live && - !par->extradata_size) { + if (side_data_size && mkv->track.bc && !par->extradata_size) { AVIOContext *dyn_cp; uint8_t *codecpriv; int codecpriv_size; @@ -2233,15 +2242,16 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt) if (ret < 0) return ret; ff_isom_write_av1c(dyn_cp, side_data, side_data_size); - codecpriv_size = avio_close_dyn_buf(dyn_cp, &codecpriv); - if (!codecpriv_size) { - av_free(codecpriv); - return AVERROR_INVALIDDATA; + codecpriv_size = avio_get_dyn_buf(dyn_cp, &codecpriv); + if ((ret = dyn_cp->error) < 0 || + !codecpriv_size && (ret = AVERROR_INVALIDDATA)) { + ffio_free_dyn_buf(&dyn_cp); + return ret; } - avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET); + avio_seek(mkv->track.bc, track->codecpriv_offset, SEEK_SET); // Do not write the OBUs as we don't have space saved for them - put_ebml_binary(mkv->tracks_bc, MATROSKA_ID_CODECPRIVATE, codecpriv, 4); - av_free(codecpriv); + put_ebml_binary(mkv->track.bc, MATROSKA_ID_CODECPRIVATE, codecpriv, 4); + ffio_free_dyn_buf(&dyn_cp); ret = ff_alloc_extradata(par, side_data_size); if (ret < 0) return ret; @@ -2279,7 +2289,9 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) if (mkv->cluster_pos != -1) { int64_t cluster_time = ts - mkv->cluster_pts; if ((int16_t)cluster_time != cluster_time) { - mkv_end_cluster(s); + ret = mkv_end_cluster(s); + if (ret < 0) + return ret; av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n"); } } @@ -2304,7 +2316,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) ret = mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe); if (ret < 0) return ret; - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && keyframe && + if (keyframe && IS_SEEKABLE(s->pb, mkv) && (par->codec_type == AVMEDIA_TYPE_VIDEO || !mkv->have_video && !track->has_cue)) { ret = mkv_add_cuepoint(mkv, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos, -1); @@ -2334,7 +2346,7 @@ FF_ENABLE_DEPRECATION_WARNINGS end_ebml_master(pb, blockgroup); } - if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { + if (IS_SEEKABLE(s->pb, mkv)) { ret = mkv_add_cuepoint(mkv, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos, duration); if (ret < 0) @@ -2389,8 +2401,11 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt) } else start_new_cluster = 0; - if (start_new_cluster) - mkv_end_cluster(s); + if (start_new_cluster) { + ret = mkv_end_cluster(s); + if (ret < 0) + return ret; + } } if (!mkv->cluster_pos) @@ -2425,7 +2440,9 @@ static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt) if (!pkt) { if (mkv->cluster_pos != -1) { - mkv_end_cluster(s); + int ret = mkv_end_cluster(s); + if (ret < 0) + return ret; av_log(s, AV_LOG_DEBUG, "Flushing cluster at offset %" PRIu64 " bytes\n", avio_tell(s->pb)); @@ -2439,7 +2456,8 @@ static int mkv_write_trailer(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; AVIOContext *pb = s->pb; - int ret; + int64_t endpos, ret64; + int ret, ret2 = 0; // check if we have an audio packet cached if (mkv->cur_audio_pkt.size > 0) { @@ -2451,130 +2469,143 @@ static int mkv_write_trailer(AVFormatContext *s) } } - if (mkv->cluster_bc) { - end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, - MATROSKA_ID_CLUSTER, 0, 0); + if (mkv->cluster_pos != -1) { + ret = end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv, + MATROSKA_ID_CLUSTER, 0, 0, 0); + if (ret < 0) + return ret; } ret = mkv_write_chapters(s); if (ret < 0) return ret; + if (!IS_SEEKABLE(pb, mkv)) + return 0; - if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { - int64_t endpos, ret64; - - endpos = avio_tell(pb); + endpos = avio_tell(pb); - if (mkv->cues.num_entries) { - AVIOContext *cues = NULL; - uint64_t size; - int64_t cuespos = endpos; - int length_size = 0; + if (mkv->cues.num_entries && mkv->reserve_cues_space >= 0) { + AVIOContext *cues = NULL; + uint64_t size; + int length_size = 0; - ret = start_ebml_master_crc32(&cues, mkv); - if (ret < 0) - return ret; + ret = start_ebml_master_crc32(&cues, mkv); + if (ret < 0) + return ret; - ret = mkv_assemble_cues(s->streams, cues, &mkv->cues, - mkv->tracks, s->nb_streams); - if (ret < 0) { - ffio_free_dyn_buf(&cues); - return ret; - } + ret = mkv_assemble_cues(s->streams, cues, &mkv->cues, + mkv->tracks, s->nb_streams); + if (ret < 0) { + ffio_free_dyn_buf(&cues); + return ret; + } - if (mkv->reserve_cues_space) { - size = avio_tell(cues); - length_size = ebml_length_size(size); - size += 4 + length_size; - if (mkv->reserve_cues_space < size) { - av_log(s, AV_LOG_WARNING, - "Insufficient space reserved for Cues: " - "%d < %"PRIu64". No Cues will be output.\n", - mkv->reserve_cues_space, size); - mkv->reserve_cues_space = -1; + if (mkv->reserve_cues_space) { + size = avio_tell(cues); + length_size = ebml_length_size(size); + size += 4 + length_size; + if (mkv->reserve_cues_space < size) { + av_log(s, AV_LOG_WARNING, + "Insufficient space reserved for Cues: " + "%d < %"PRIu64". No Cues will be output.\n", + mkv->reserve_cues_space, size); + ret2 = AVERROR(EINVAL); + goto after_cues; + } else { + if ((ret64 = avio_seek(pb, mkv->cues_pos, SEEK_SET)) < 0) { ffio_free_dyn_buf(&cues); - goto after_cues; - } else { - cuespos = mkv->cues_pos; - if ((ret64 = avio_seek(pb, mkv->cues_pos, SEEK_SET)) < 0) { - ffio_free_dyn_buf(&cues); - return ret64; - } - if (mkv->reserve_cues_space == size + 1) { - /* There is no way to reserve a single byte because - * the minimal size of an EBML Void element is 2 - * (1 byte ID, 1 byte length field). This problem - * is solved by writing the Cues' length field on - * one byte more than necessary. */ - length_size++; - size++; - } + return ret64; + } + if (mkv->reserve_cues_space == size + 1) { + /* There is no way to reserve a single byte because + * the minimal size of an EBML Void element is 2 + * (1 byte ID, 1 byte length field). This problem + * is solved by writing the Cues' length field on + * one byte more than necessary. */ + length_size++; + size++; } } - mkv_add_seekhead_entry(mkv, MATROSKA_ID_CUES, cuespos); - end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, - length_size, 0); - if (mkv->reserve_cues_space) { - if (size < mkv->reserve_cues_space) - put_ebml_void(pb, mkv->reserve_cues_space - size); - } else - endpos = avio_tell(pb); } - - after_cues: - ret = mkv_write_seekhead(pb, mkv, 1, mkv->info_pos); + ret = end_ebml_master_crc32(pb, &cues, mkv, MATROSKA_ID_CUES, + length_size, 0, 1); if (ret < 0) return ret; + if (mkv->reserve_cues_space) { + if (size < mkv->reserve_cues_space) + put_ebml_void(pb, mkv->reserve_cues_space - size); + } else + endpos = avio_tell(pb); + } +after_cues: + /* Lengths greater than (1ULL << 56) - 1 can't be represented + * via an EBML number, so leave the unknown length field. */ + if (endpos - mkv->segment_offset < (1ULL << 56) - 1) { + if ((ret64 = avio_seek(pb, mkv->segment_offset - 8, SEEK_SET)) < 0) + return ret64; + put_ebml_length(pb, endpos - mkv->segment_offset, 8); + } + + ret = mkv_write_seekhead(pb, mkv, 1, mkv->info.pos); + if (ret < 0) + return ret; + + if (mkv->info.bc) { // update the duration av_log(s, AV_LOG_DEBUG, "end duration = %" PRIu64 "\n", mkv->duration); - avio_seek(mkv->info_bc, mkv->duration_offset, SEEK_SET); - put_ebml_float(mkv->info_bc, MATROSKA_ID_DURATION, mkv->duration); - end_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO, 0, 0); - - if (mkv->tracks_bc) { - // write Tracks master - avio_seek(pb, mkv->tracks_pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, - MATROSKA_ID_TRACKS, 0, 0); - } + avio_seek(mkv->info.bc, mkv->duration_offset, SEEK_SET); + put_ebml_float(mkv->info.bc, MATROSKA_ID_DURATION, mkv->duration); + ret = end_ebml_master_crc32(pb, &mkv->info.bc, mkv, + MATROSKA_ID_INFO, 0, 0, 0); + if (ret < 0) + return ret; + } - // update stream durations - if (mkv->tags_bc) { - int i; - for (i = 0; i < s->nb_streams; ++i) { - const AVStream *st = s->streams[i]; - const mkv_track *track = &mkv->tracks[i]; + if (mkv->track.bc) { + // write Tracks master + avio_seek(pb, mkv->track.pos, SEEK_SET); + ret = end_ebml_master_crc32(pb, &mkv->track.bc, mkv, + MATROSKA_ID_TRACKS, 0, 0, 0); + if (ret < 0) + return ret; + } - if (track->duration_offset > 0) { - double duration_sec = track->duration * av_q2d(st->time_base); - char duration_string[20] = ""; + // update stream durations + if (mkv->tags.bc) { + int i; + for (i = 0; i < s->nb_streams; ++i) { + const AVStream *st = s->streams[i]; + const mkv_track *track = &mkv->tracks[i]; - av_log(s, AV_LOG_DEBUG, "stream %d end duration = %" PRIu64 "\n", i, - track->duration); + if (track->duration_offset > 0) { + double duration_sec = track->duration * av_q2d(st->time_base); + char duration_string[20] = ""; - avio_seek(mkv->tags_bc, track->duration_offset, SEEK_SET); + av_log(s, AV_LOG_DEBUG, "stream %d end duration = %" PRIu64 "\n", i, + track->duration); - snprintf(duration_string, 20, "%02d:%02d:%012.9f", - (int) duration_sec / 3600, ((int) duration_sec / 60) % 60, - fmod(duration_sec, 60)); + avio_seek(mkv->tags.bc, track->duration_offset, SEEK_SET); - put_ebml_binary(mkv->tags_bc, MATROSKA_ID_TAGSTRING, duration_string, 20); - } - } + snprintf(duration_string, 20, "%02d:%02d:%012.9f", + (int) duration_sec / 3600, ((int) duration_sec / 60) % 60, + fmod(duration_sec, 60)); - avio_seek(pb, mkv->tags_pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS, 0, 0); + put_ebml_binary(mkv->tags.bc, MATROSKA_ID_TAGSTRING, duration_string, 20); + } } - avio_seek(pb, endpos, SEEK_SET); + avio_seek(pb, mkv->tags.pos, SEEK_SET); + ret = end_ebml_master_crc32(pb, &mkv->tags.bc, mkv, + MATROSKA_ID_TAGS, 0, 0, 0); + if (ret < 0) + return ret; } - if (!mkv->is_live) - end_ebml_master(pb, mkv->segment); + avio_seek(pb, endpos, SEEK_SET); - return mkv->reserve_cues_space < 0 ? AVERROR(EINVAL) : 0; + return ret2; } static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance) @@ -2683,6 +2714,10 @@ static int mkv_init(struct AVFormatContext *s) if (mkv->mode == MODE_WEBM) { av_log(s, AV_LOG_WARNING, "Stream %d will be ignored " "as WebM doesn't support attachments.\n", i); + } else if (!get_mimetype(st)) { + av_log(s, AV_LOG_ERROR, "Attachment stream %d has no mimetype " + "tag and it cannot be deduced from the codec id.\n", i); + return AVERROR(EINVAL); } mkv->nb_attachments++; continue; @@ -2754,6 +2789,7 @@ static const AVOption options[] = { { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS }, { "live", "Write files assuming it is a live stream.", OFFSET(is_live), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "allow_raw_vfw", "allow RAW VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "flipped_raw_rgb", "Raw RGB bitmaps in VFW mode are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "write_crc32", "write a CRC32 element inside every Level 1 element", OFFSET(write_crc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, { "default_mode", "Controls how a track's FlagDefault is inferred", OFFSET(default_mode), AV_OPT_TYPE_INT, { .i64 = DEFAULT_MODE_INFER }, DEFAULT_MODE_INFER, DEFAULT_MODE_PASSTHROUGH, FLAGS, "default_mode" }, { "infer", "For each track type, mark the first track of disposition default as default; if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 0, FLAGS, "default_mode" }, diff --git a/chromium/third_party/ffmpeg/libavformat/mccdec.c b/chromium/third_party/ffmpeg/libavformat/mccdec.c new file mode 100644 index 00000000000..874ff45cdf3 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/mccdec.c @@ -0,0 +1,238 @@ +/* + * MCC subtitle demuxer + * Copyright (c) 2020 Paul B Mahol + * + * 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 "avformat.h" +#include "internal.h" +#include "subtitles.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" +#include "libavutil/intreadwrite.h" + +typedef struct MCCContext { + FFDemuxSubtitlesQueue q; +} MCCContext; + +static int mcc_probe(const AVProbeData *p) +{ + char buf[28]; + FFTextReader tr; + + ff_text_init_buf(&tr, p->buf, p->buf_size); + + while (ff_text_peek_r8(&tr) == '\r' || ff_text_peek_r8(&tr) == '\n') + ff_text_r8(&tr); + + ff_text_read(&tr, buf, sizeof(buf)); + + if (!memcmp(buf, "File Format=MacCaption_MCC V", 28)) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int convert(uint8_t x) +{ + if (x >= 'a') + x -= 87; + else if (x >= 'A') + x -= 55; + else + x -= '0'; + return x; +} + +typedef struct alias { + uint8_t key; + int len; + const char *value; +} alias; + +static const alias aliases[20] = { + { .key = 16, .len = 3, .value = "\xFA\x0\x0", }, + { .key = 17, .len = 6, .value = "\xFA\x0\x0\xFA\x0\x0", }, + { .key = 18, .len = 9, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 19, .len = 12, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 20, .len = 15, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 21, .len = 18, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 22, .len = 21, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 23, .len = 24, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 24, .len = 27, .value = "\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0\xFA\x0\x0", }, + { .key = 25, .len = 3, .value = "\xFB\x80\x80", }, + { .key = 26, .len = 3, .value = "\xFC\x80\x80", }, + { .key = 27, .len = 3, .value = "\xFD\x80\x80", }, + { .key = 28, .len = 2, .value = "\x96\x69", }, + { .key = 29, .len = 2, .value = "\x61\x01", }, + { .key = 30, .len = 3, .value = "\xFC\x80\x80", }, + { .key = 31, .len = 3, .value = "\xFC\x80\x80", }, + { .key = 32, .len = 4, .value = "\xE1\x00\x00\x00", }, + { .key = 33, .len = 0, .value = NULL, }, + { .key = 34, .len = 0, .value = NULL, }, + { .key = 35, .len = 1, .value = "\x0", }, +}; + +static int mcc_read_header(AVFormatContext *s) +{ + MCCContext *mcc = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + AVRational rate; + int64_t ts, pos; + uint8_t out[4096]; + char line[4096]; + FFTextReader tr; + int ret = 0; + + ff_text_init_avio(s, &tr, s->pb); + + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_EIA_608; + avpriv_set_pts_info(st, 64, 1, 30); + + while (!ff_text_eof(&tr)) { + int hh, mm, ss, fs, i = 0, j = 0; + int start = 12, count = 0; + AVPacket *sub; + char *lline; + + ff_subtitles_read_line(&tr, line, sizeof(line)); + if (!strncmp(line, "File Format=MacCaption_MCC V", 28)) + continue; + if (!strncmp(line, "//", 2)) + continue; + if (!strncmp(line, "Time Code Rate=", 15)) { + char *rate_str = line + 15; + char *df = NULL; + int num = -1, den = -1; + + if (rate_str[0]) { + num = strtol(rate_str, &df, 10); + den = 1; + if (df && !av_strncasecmp(df, "DF", 2)) { + num *= 1000; + den = 1001; + } + } + + if (num > 0 && den > 0) { + rate = av_make_q(num, den); + avpriv_set_pts_info(st, 64, rate.den, rate.num); + } + continue; + } + + if (av_sscanf(line, "%d:%d:%d:%d", &hh, &mm, &ss, &fs) != 4) + continue; + + ts = av_rescale(hh * 3600LL + mm * 60LL + ss, rate.num, rate.den) + fs; + + lline = (char *)&line; + lline += 12; + pos = ff_text_pos(&tr); + + while (lline[i]) { + uint8_t v = convert(lline[i]); + + if (v >= 16 && v <= 35) { + int idx = v - 16; + if (aliases[idx].len) { + if (j >= sizeof(out) - 1 - aliases[idx].len) { + j = 0; + break; + } + memcpy(out + j, aliases[idx].value, aliases[idx].len); + j += aliases[idx].len; + } + } else { + uint8_t vv; + + if (i + 13 >= sizeof(line) - 1) + break; + vv = convert(lline[i + 1]); + if (j >= sizeof(out) - 1) { + j = 0; + break; + } + out[j++] = vv | (v << 4); + i++; + } + + i++; + } + out[j] = 0; + + if (out[7] & 0x80) + start += 4; + count = (out[11] & 0x1f) * 3; + if (j < start + count + 1) + continue; + + if (!count) + continue; + sub = ff_subtitles_queue_insert(&mcc->q, out + start, count, 0); + if (!sub) + goto fail; + + sub->pos = pos; + sub->pts = ts; + sub->duration = 1; + } + + ff_subtitles_queue_finalize(s, &mcc->q); + + return ret; +fail: + ff_subtitles_queue_clean(&mcc->q); + return AVERROR(ENOMEM); +} + +static int mcc_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + MCCContext *mcc = s->priv_data; + return ff_subtitles_queue_read_packet(&mcc->q, pkt); +} + +static int mcc_read_seek(AVFormatContext *s, int stream_index, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + MCCContext *mcc = s->priv_data; + return ff_subtitles_queue_seek(&mcc->q, s, stream_index, + min_ts, ts, max_ts, flags); +} + +static int mcc_read_close(AVFormatContext *s) +{ + MCCContext *mcc = s->priv_data; + ff_subtitles_queue_clean(&mcc->q); + return 0; +} + +AVInputFormat ff_mcc_demuxer = { + .name = "mcc", + .long_name = NULL_IF_CONFIG_SMALL("MacCaption"), + .priv_data_size = sizeof(MCCContext), + .read_probe = mcc_probe, + .read_header = mcc_read_header, + .read_packet = mcc_read_packet, + .read_seek2 = mcc_read_seek, + .read_close = mcc_read_close, + .extensions = "mcc", +}; diff --git a/chromium/third_party/ffmpeg/libavformat/microdvddec.c b/chromium/third_party/ffmpeg/libavformat/microdvddec.c index 08e6fca09cc..1f871b25182 100644 --- a/chromium/third_party/ffmpeg/libavformat/microdvddec.c +++ b/chromium/third_party/ffmpeg/libavformat/microdvddec.c @@ -81,7 +81,7 @@ static int microdvd_read_header(AVFormatContext *s) AVRational pts_info = (AVRational){ 2997, 125 }; /* default: 23.976 fps */ MicroDVDContext *microdvd = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); - int i = 0; + int i = 0, ret; char line_buf[MAX_LINESIZE]; int has_real_fps = 0; @@ -94,6 +94,7 @@ static int microdvd_read_header(AVFormatContext *s) int64_t pos = avio_tell(s->pb); int len = ff_get_line(s->pb, line_buf, sizeof(line_buf)); char *line = line_buf; + int64_t pts; if (!strncmp(line, bom, 3)) line += 3; @@ -117,10 +118,10 @@ static int microdvd_read_header(AVFormatContext *s) continue; } if (!st->codecpar->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) { - int ret, size = strlen(line + 11); + int size = strlen(line + 11); ret = ff_alloc_extradata(st->codecpar, size); if (ret < 0) - return ret; + goto fail; memcpy(st->codecpar->extradata, line + 11, size); continue; } @@ -137,11 +138,16 @@ static int microdvd_read_header(AVFormatContext *s) SKIP_FRAME_ID; if (!*p) continue; + pts = get_pts(line); + if (pts == AV_NOPTS_VALUE) + continue; sub = ff_subtitles_queue_insert(µdvd->q, p, strlen(p), 0); - if (!sub) - return AVERROR(ENOMEM); + if (!sub) { + ret = AVERROR(ENOMEM); + goto fail; + } sub->pos = pos; - sub->pts = get_pts(line); + sub->pts = pts; sub->duration = get_duration(line); } ff_subtitles_queue_finalize(s, µdvd->q); @@ -156,6 +162,9 @@ static int microdvd_read_header(AVFormatContext *s) st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_MICRODVD; return 0; +fail: + ff_subtitles_queue_clean(µdvd->q); + return ret; } static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/mlvdec.c b/chromium/third_party/ffmpeg/libavformat/mlvdec.c index dae13cae53a..03aed710244 100644 --- a/chromium/third_party/ffmpeg/libavformat/mlvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mlvdec.c @@ -393,10 +393,14 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt) { MlvContext *mlv = avctx->priv_data; AVIOContext *pb; - AVStream *st = avctx->streams[mlv->stream_index]; + AVStream *st; int index, ret; unsigned int size, space; + if (!avctx->nb_streams) + return AVERROR_EOF; + + st = avctx->streams[mlv->stream_index]; if (mlv->pts >= st->duration) return AVERROR_EOF; diff --git a/chromium/third_party/ffmpeg/libavformat/mm.c b/chromium/third_party/ffmpeg/libavformat/mm.c index d40fd12accc..02ffbcd8242 100644 --- a/chromium/third_party/ffmpeg/libavformat/mm.c +++ b/chromium/third_party/ffmpeg/libavformat/mm.c @@ -175,6 +175,8 @@ static int read_packet(AVFormatContext *s, return 0; case MM_TYPE_AUDIO : + if (s->nb_streams < 2) + return AVERROR_INVALIDDATA; if ((ret = av_get_packet(s->pb, pkt, length)) < 0) return ret; pkt->stream_index = 1; diff --git a/chromium/third_party/ffmpeg/libavformat/mmsh.c b/chromium/third_party/ffmpeg/libavformat/mmsh.c index 13c0ffe4387..495d7fb73ba 100644 --- a/chromium/third_party/ffmpeg/libavformat/mmsh.c +++ b/chromium/third_party/ffmpeg/libavformat/mmsh.c @@ -65,8 +65,7 @@ static int mmsh_close(URLContext *h) { MMSHContext *mmsh = (MMSHContext *)h->priv_data; MMSContext *mms = &mmsh->mms; - if (mms->mms_hd) - ffurl_closep(&mms->mms_hd); + ffurl_closep(&mms->mms_hd); av_freep(&mms->streams); av_freep(&mms->asf_header); return 0; @@ -265,7 +264,7 @@ static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int tim } // close the socket and then reopen it for sending the second play request. - ffurl_close(mms->mms_hd); + ffurl_closep(&mms->mms_hd); memset(headers, 0, sizeof(headers)); if ((err = ffurl_alloc(&mms->mms_hd, httpname, AVIO_FLAG_READ, &h->interrupt_callback)) < 0) { diff --git a/chromium/third_party/ffmpeg/libavformat/mmst.c b/chromium/third_party/ffmpeg/libavformat/mmst.c index 533cbe76986..377323fe274 100644 --- a/chromium/third_party/ffmpeg/libavformat/mmst.c +++ b/chromium/third_party/ffmpeg/libavformat/mmst.c @@ -473,7 +473,7 @@ static int mms_close(URLContext *h) MMSContext *mms = &mmst->mms; if(mms->mms_hd) { send_close_packet(mmst); - ffurl_close(mms->mms_hd); + ffurl_closep(&mms->mms_hd); } /* free all separately allocated pointers in mms */ diff --git a/chromium/third_party/ffmpeg/libavformat/mov.c b/chromium/third_party/ffmpeg/libavformat/mov.c index 2fc5bd65286..88faea491c4 100644 --- a/chromium/third_party/ffmpeg/libavformat/mov.c +++ b/chromium/third_party/ffmpeg/libavformat/mov.c @@ -181,7 +181,6 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len, static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) { - AVPacket pkt; AVStream *st; MOVStreamContext *sc; enum AVCodecID id; @@ -205,12 +204,12 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) return AVERROR(ENOMEM); st->priv_data = sc; - ret = av_get_packet(pb, &pkt, len); + ret = av_get_packet(pb, &st->attached_pic, len); if (ret < 0) return ret; - if (pkt.size >= 8 && id != AV_CODEC_ID_BMP) { - if (AV_RB64(pkt.data) == 0x89504e470d0a1a0a) { + if (st->attached_pic.size >= 8 && id != AV_CODEC_ID_BMP) { + if (AV_RB64(st->attached_pic.data) == 0x89504e470d0a1a0a) { id = AV_CODEC_ID_PNG; } else { id = AV_CODEC_ID_MJPEG; @@ -219,7 +218,6 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) st->disposition |= AV_DISPOSITION_ATTACHED_PIC; - st->attached_pic = pkt; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; @@ -299,7 +297,7 @@ static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len) static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - char tmp_key[5]; + char tmp_key[AV_FOURCC_MAX_STRING_SIZE] = {0}; char key2[32], language[4] = {0}; char *str = NULL; const char *key = NULL; @@ -446,8 +444,7 @@ retry: str_size = atom.size; if (c->export_all && !key) { - snprintf(tmp_key, 5, "%.4s", (char*)&atom.type); - key = tmp_key; + key = av_fourcc_make_string(tmp_key, atom.type); } if (!key) @@ -646,7 +643,7 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 16); for (type = 0; type != -1 && avio_tell(pb) < next; ) { - if(avio_feof(pb)) + if (avio_feof(pb)) return AVERROR_EOF; type = avio_rb16(pb); len = avio_rb16(pb); @@ -859,26 +856,20 @@ static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - const uint32_t ddts_size = 20; +#define DDTS_SIZE 20 + uint8_t buf[DDTS_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; AVStream *st = NULL; - uint8_t *buf = NULL; uint32_t frame_duration_code = 0; uint32_t channel_layout_code = 0; GetBitContext gb; + int ret; - buf = av_malloc(ddts_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!buf) { - return AVERROR(ENOMEM); - } - if (avio_read(pb, buf, ddts_size) < ddts_size) { - av_free(buf); - return AVERROR_INVALIDDATA; - } + if ((ret = ffio_read_size(pb, buf, DDTS_SIZE)) < 0) + return ret; - init_get_bits(&gb, buf, 8*ddts_size); + init_get_bits(&gb, buf, 8 * DDTS_SIZE); if (c->fc->nb_streams < 1) { - av_free(buf); return 0; } st = c->fc->streams[c->fc->nb_streams-1]; @@ -886,7 +877,6 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->sample_rate = get_bits_long(&gb, 32); if (st->codecpar->sample_rate <= 0) { av_log(c->fc, AV_LOG_ERROR, "Invalid sample rate %d\n", st->codecpar->sample_rate); - av_free(buf); return AVERROR_INVALIDDATA; } skip_bits_long(&gb, 32); /* max bitrate */ @@ -903,7 +893,7 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) (frame_duration_code == 3) ? 4096 : 0; if (channel_layout_code > 0xff) { - av_log(c->fc, AV_LOG_WARNING, "Unsupported DTS audio channel layout"); + av_log(c->fc, AV_LOG_WARNING, "Unsupported DTS audio channel layout\n"); } st->codecpar->channel_layout = ((channel_layout_code & 0x1) ? AV_CH_FRONT_CENTER : 0) | @@ -914,7 +904,6 @@ static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom) ((channel_layout_code & 0x8) ? AV_CH_LOW_FREQUENCY : 0); st->codecpar->channels = av_get_channel_layout_nb_channels(st->codecpar->channel_layout); - av_free(buf); return 0; } @@ -1119,7 +1108,7 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0); comp_brand_size = atom.size - 8; - if (comp_brand_size < 0) + if (comp_brand_size < 0 || comp_brand_size == INT_MAX) return AVERROR_INVALIDDATA; comp_brands_str = av_malloc(comp_brand_size + 1); /* Add null terminator */ if (!comp_brands_str) @@ -1318,7 +1307,7 @@ static int update_frag_index(MOVContext *c, int64_t offset) &c->frag_index.allocated_size, (c->frag_index.nb_items + 1) * sizeof(*c->frag_index.item)); - if(!item) + if (!item) return -1; c->frag_index.item = item; @@ -1402,7 +1391,7 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time, void *logctx) { if (time) { - if(time >= 2082844800) + if (time >= 2082844800) time -= 2082844800; /* seconds between 1904-01-01 and Epoch */ if ((int64_t)(time * 1000000ULL) / 1000000 != time) { @@ -1576,8 +1565,7 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) ret = ffio_read_size(pb, icc_profile, atom.size - 4); if (ret < 0) return ret; - } - else { + } else { color_primaries = avio_rb16(pb); color_trc = avio_rb16(pb); color_matrix = avio_rb16(pb); @@ -1730,7 +1718,7 @@ static int mov_read_dpxe(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI); - if(ret == 0) + if (!ret) ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_DNXHD); return ret; } @@ -2351,18 +2339,15 @@ FF_ENABLE_DEPRECATION_WARNINGS uint32_t format = AV_RB32(st->codecpar->extradata + 22); if (format == AV_RB32("name") && (int64_t)size >= (int64_t)len + 18) { uint16_t str_size = AV_RB16(st->codecpar->extradata + 26); /* string length */ - if (str_size > 0 && size >= (int)str_size + 26) { + if (str_size > 0 && size >= (int)str_size + 30 && + st->codecpar->extradata[30] /* Don't add empty string */) { char *reel_name = av_malloc(str_size + 1); if (!reel_name) return AVERROR(ENOMEM); memcpy(reel_name, st->codecpar->extradata + 30, str_size); reel_name[str_size] = 0; /* Add null terminator */ - /* don't add reel_name if emtpy string */ - if (*reel_name == 0) { - av_free(reel_name); - } else { - av_dict_set(&st->metadata, "reel_name", reel_name, AV_DICT_DONT_STRDUP_VAL); - } + av_dict_set(&st->metadata, "reel_name", reel_name, + AV_DICT_DONT_STRDUP_VAL); } } } @@ -2559,11 +2544,8 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) /* Move the current stream extradata to the stream context one. */ sc->extradata_size[pseudo_stream_id] = extra_size; - sc->extradata[pseudo_stream_id] = av_malloc(extra_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!sc->extradata[pseudo_stream_id]) - return AVERROR(ENOMEM); - memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, extra_size); - av_freep(&st->codecpar->extradata); + sc->extradata[pseudo_stream_id] = st->codecpar->extradata; + st->codecpar->extradata = NULL; st->codecpar->extradata_size = 0; } sc->stsd_count++; @@ -2798,8 +2780,7 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "keyframe_count = %u\n", entries); - if (!entries) - { + if (!entries) { sc->keyframe_absent = 1; if (!st->need_parsing && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) st->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -2927,8 +2908,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; MOVStreamContext *sc; unsigned int i, entries, alloc_size = 0; - int64_t duration=0; - int64_t total_sample_count=0; + int64_t duration = 0; + int64_t total_sample_count = 0; if (c->fc->nb_streams < 1) return 0; @@ -2963,7 +2944,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stts_count = min_entries; sc->stts_data = stts_data; - sample_count=avio_rb32(pb); + sample_count = avio_rb32(pb); sample_duration = avio_rb32(pb); sc->stts_data[i].count= sample_count; @@ -2980,8 +2961,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (duration > 0 && duration <= INT64_MAX - sc->duration_for_fps && - total_sample_count <= INT_MAX - sc->nb_frames_for_fps - ) { + total_sample_count <= INT_MAX - sc->nb_frames_for_fps) { sc->duration_for_fps += duration; sc->nb_frames_for_fps += total_sample_count; } @@ -3070,8 +3050,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); for (i = 0; i < entries && !pb->eof_reached; i++) { - int count =avio_rb32(pb); - int duration =avio_rb32(pb); + int count = avio_rb32(pb); + int duration = avio_rb32(pb); if (count <= 0) { av_log(c->fc, AV_LOG_TRACE, @@ -3311,13 +3291,13 @@ static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, FFMAX(min_size_needed, 2 * st->index_entries_allocated_size) : min_size_needed; - if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) + if (st->nb_index_entries + 1U >= UINT_MAX / sizeof(AVIndexEntry)) return -1; entries = av_fast_realloc(st->index_entries, &st->index_entries_allocated_size, requested_size); - if(!entries) + if (!entries) return -1; st->index_entries= entries; @@ -3362,12 +3342,12 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns FFMAX(min_size_needed, 2 * (*allocated_size)) : min_size_needed; - if((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1) + if ((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1) return -1; ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size); - if(!ctts_buf_new) + if (!ctts_buf_new) return -1; *ctts_data = ctts_buf_new; @@ -3380,7 +3360,8 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns } #define MAX_REORDER_DELAY 16 -static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { +static void mov_estimate_video_delay(MOVContext *c, AVStream* st) +{ MOVStreamContext *msc = st->priv_data; int ind; int ctts_ind = 0; @@ -3395,7 +3376,7 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { if (st->codecpar->video_delay <= 0 && msc->ctts_data && st->codecpar->codec_id == AV_CODEC_ID_H264) { st->codecpar->video_delay = 0; - for(ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { + for (ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { // Point j to the last elem of the buffer and insert the current pts there. j = buf_start; buf_start = (buf_start + 1); @@ -4193,10 +4174,10 @@ static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDr return AVERROR(ENOENT); } - if(strstr(ref->path + l + 1, "..") || - strstr(ref->path + l + 1, ":") || - (ref->nlvl_from > 1 && same_origin < 0) || - (filename[0] == '/' && src_path == src)) + if (strstr(ref->path + l + 1, "..") || + strstr(ref->path + l + 1, ":") || + (ref->nlvl_from > 1 && same_origin < 0) || + (filename[0] == '/' && src_path == src)) return AVERROR(ENOENT); } @@ -4451,6 +4432,9 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else break; + if (*p) + break; + *p = av_malloc(len + 1); if (!*p) { ret = AVERROR(ENOMEM); @@ -4827,8 +4811,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); frag_stream_info = get_current_frag_stream_info(&c->frag_index); - if (frag_stream_info) - { + if (frag_stream_info) { if (frag_stream_info->next_trun_dts != AV_NOPTS_VALUE) { dts = frag_stream_info->next_trun_dts - sc->time_offset; } else if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && @@ -4877,7 +4860,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) new_entries = av_fast_realloc(st->index_entries, &st->index_entries_allocated_size, requested_size); - if(!new_entries) + if (!new_entries) return AVERROR(ENOMEM); st->index_entries= new_entries; @@ -5048,8 +5031,9 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) { + int64_t stream_size = avio_size(pb); int64_t offset = avio_tell(pb) + atom.size, pts, timestamp; - uint8_t version; + uint8_t version, is_complete; unsigned i, j, track_id, item_count; AVStream *st = NULL; AVStream *ref_st = NULL; @@ -5126,7 +5110,22 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->has_sidx = 1; - if (offset == avio_size(pb)) { + // See if the remaining bytes are just an mfra which we can ignore. + is_complete = offset == stream_size; + if (!is_complete) { + int ret; + int64_t original_pos = avio_tell(pb); + int32_t mfra_size; + if ((ret = avio_seek(pb, stream_size - 4, SEEK_SET)) < 0) + return ret; + mfra_size = avio_rb32(pb); + if (offset + mfra_size == stream_size) + is_complete = 1; + if ((ret = avio_seek(pb, original_pos, SEEK_SET)) < 0) + return ret; + } + + if (is_complete) { // Find first entry in fragment index that came from an sidx. // This will pretty much always be the first entry. for (i = 0; i < c->frag_index.nb_items; i++) { @@ -5256,7 +5255,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else { edit_count = atom.size / elst_entry_size; if (edit_count * elst_entry_size != atom.size) { - av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.", atom.size, edit_count); + av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.\n", atom.size, edit_count); } } } @@ -5791,12 +5790,9 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) st = c->fc->streams[c->fc->nb_streams - 1]; sc = st->priv_data; - ret = avio_read(pb, uuid, sizeof(uuid)); - if (ret < 0) { + ret = ffio_read_size(pb, uuid, sizeof(uuid)); + if (ret < 0) return ret; - } else if (ret != sizeof(uuid)) { - return AVERROR_INVALIDDATA; - } if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) { uint8_t *buffer, *ptr; char *endptr; @@ -5812,13 +5808,10 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!buffer) { return AVERROR(ENOMEM); } - ret = avio_read(pb, buffer, len); + ret = ffio_read_size(pb, buffer, len); if (ret < 0) { av_free(buffer); return ret; - } else if (ret != len) { - av_free(buffer); - return AVERROR_INVALIDDATA; } ptr = buffer; @@ -5849,13 +5842,10 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!buffer) { return AVERROR(ENOMEM); } - ret = avio_read(pb, buffer, len); + ret = ffio_read_size(pb, buffer, len); if (ret < 0) { av_free(buffer); return ret; - } else if (ret != len) { - av_free(buffer); - return AVERROR_INVALIDDATA; } buffer[len] = '\0'; av_dict_set(&c->fc->metadata, "xmp", @@ -5999,7 +5989,7 @@ static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encry static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVStreamContext *sc, AVEncryptionInfo **sample, int use_subsamples) { - int i; + int i, ret; unsigned int subsample_count; AVSubsampleEncryptionInfo *subsamples; @@ -6013,11 +6003,11 @@ static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVSt return AVERROR(ENOMEM); if (sc->cenc.per_sample_iv_size != 0) { - if (avio_read(pb, (*sample)->iv, sc->cenc.per_sample_iv_size) != sc->cenc.per_sample_iv_size) { + if ((ret = ffio_read_size(pb, (*sample)->iv, sc->cenc.per_sample_iv_size)) < 0) { av_log(c->fc, AV_LOG_ERROR, "failed to read the initialization vector\n"); av_encryption_info_free(*sample); *sample = NULL; - return AVERROR_INVALIDDATA; + return ret; } } @@ -6385,9 +6375,8 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!info) return AVERROR(ENOMEM); - if (avio_read(pb, info->system_id, 16) != 16) { + if ((ret = ffio_read_size(pb, info->system_id, 16)) < 0) { av_log(c->fc, AV_LOG_ERROR, "Failed to read the system id\n"); - ret = AVERROR_INVALIDDATA; goto finish; } @@ -6415,9 +6404,8 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) } info->num_key_ids = i + 1; - if (avio_read(pb, info->key_ids[i], 16) != 16) { + if ((ret = ffio_read_size(pb, info->key_ids[i], 16)) < 0) { av_log(c->fc, AV_LOG_ERROR, "Failed to read the key id\n"); - ret = AVERROR_INVALIDDATA; goto finish; } } @@ -6638,15 +6626,13 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv); - if (!sample->subsample_count) - { + if (!sample->subsample_count) { /* decrypt the whole packet */ av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size); return 0; } - for (i = 0; i < sample->subsample_count; i++) - { + for (i = 0; i < sample->subsample_count; i++) { if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) { av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n"); return AVERROR_INVALIDDATA; @@ -6855,7 +6841,7 @@ static int mov_read_dvcc_dvvc(MOVContext *c, AVIOContext *pb, MOVAtom atom) ret = av_stream_add_side_data(st, AV_PKT_DATA_DOVI_CONF, (uint8_t *)dovi, dovi_size); if (ret < 0) { - av_freep(dovi); + av_free(dovi); return ret; } @@ -6997,22 +6983,20 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) a.type == MKTAG('h','o','o','v')) && a.size >= 8 && c->fc->strict_std_compliance < FF_COMPLIANCE_STRICT) { - uint8_t buf[8]; - uint32_t *type = (uint32_t *)buf + 1; - if (avio_read(pb, buf, 8) != 8) - return AVERROR_INVALIDDATA; + uint32_t type; + avio_skip(pb, 4); + type = avio_rl32(pb); avio_seek(pb, -8, SEEK_CUR); - if (*type == MKTAG('m','v','h','d') || - *type == MKTAG('c','m','o','v')) { + if (type == MKTAG('m','v','h','d') || + type == MKTAG('c','m','o','v')) { av_log(c->fc, AV_LOG_ERROR, "Detected moov in a free or hoov atom.\n"); a.type = MKTAG('m','o','o','v'); } } if (atom.type != MKTAG('r','o','o','t') && - atom.type != MKTAG('m','o','o','v')) - { - if (a.type == MKTAG('t','r','a','k') || a.type == MKTAG('m','d','a','t')) - { + atom.type != MKTAG('m','o','o','v')) { + if (a.type == MKTAG('t','r','a','k') || + a.type == MKTAG('m','d','a','t')) { av_log(c->fc, AV_LOG_ERROR, "Broken file, trak/mdat not at top-level\n"); avio_skip(pb, -8); c->atom_depth --; @@ -7050,7 +7034,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html if (!parse && c->found_hdlr_mdta && atom.type == MKTAG('m','e','t','a') && - a.type == MKTAG('k','e','y','s')) { + a.type == MKTAG('k','e','y','s') && + c->meta_keys_count == 0) { parse = mov_read_keys; } @@ -7077,8 +7062,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, left); else if (left < 0) { av_log(c->fc, AV_LOG_WARNING, - "overread end of atom '%.4s' by %"PRId64" bytes\n", - (char*)&a.type, -left); + "overread end of atom '%s' by %"PRId64" bytes\n", + av_fourcc2str(a.type), -left); avio_seek(pb, left, SEEK_CUR); } } @@ -7151,25 +7136,26 @@ static int mov_probe(const AVProbeData *p) offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; } } - if(score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) { + if (score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) { /* moov atom in the header - we should make sure that this is not a * MOV-packed MPEG-PS */ offset = moov_offset; - while(offset < (p->buf_size - 16)){ /* Sufficient space */ + while (offset < (p->buf_size - 16)) { /* Sufficient space */ /* We found an actual hdlr atom */ - if(AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') && - AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') && - AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')){ + if (AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') && + AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') && + AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')) { av_log(NULL, AV_LOG_WARNING, "Found media data tag MPEG indicating this is a MOV-packed MPEG-PS.\n"); /* We found a media handler reference atom describing an * MPEG-PS-in-MOV, return a * low score to force expanding the probe window until * mpegps_probe finds what it needs */ return 5; - }else + } else { /* Keep looking */ - offset+=2; + offset += 2; + } } } @@ -7206,17 +7192,15 @@ static void mov_read_chapters(AVFormatContext *s) st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS; if (st->nb_index_entries) { // Retrieve the first frame, if possible - AVPacket pkt; AVIndexEntry *sample = &st->index_entries[0]; if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { av_log(s, AV_LOG_ERROR, "Failed to retrieve first frame\n"); goto finish; } - if (av_get_packet(sc->pb, &pkt, sample->size) < 0) + if (av_get_packet(sc->pb, &st->attached_pic, sample->size) < 0) goto finish; - st->attached_pic = pkt; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; } @@ -7410,10 +7394,9 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->coll); } - if (mov->dv_demux) { - avformat_free_context(mov->dv_fctx); - mov->dv_fctx = NULL; - } + av_freep(&mov->dv_demux); + avformat_free_context(mov->dv_fctx); + mov->dv_fctx = NULL; if (mov->meta_keys) { for (i = 1; i < mov->meta_keys_count; i++) { @@ -7602,14 +7585,13 @@ static int mov_read_header(AVFormatContext *s) avio_seek(pb, 0, SEEK_SET); if ((err = mov_read_default(mov, pb, atom)) < 0) { av_log(s, AV_LOG_ERROR, "error reading header\n"); - mov_read_close(s); - return err; + goto fail; } } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++); if (!mov->found_moov) { av_log(s, AV_LOG_ERROR, "moov atom not found\n"); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); @@ -7649,7 +7631,8 @@ static int mov_read_header(AVFormatContext *s) AVStream *st = s->streams[i]; MOVStreamContext *sc = st->priv_data; fix_timescale(mov, sc); - if(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->codec_id == AV_CODEC_ID_AAC) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + st->codecpar->codec_id == AV_CODEC_ID_AAC) { st->skip_samples = sc->start_pad; } if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) @@ -7662,13 +7645,12 @@ static int mov_read_header(AVFormatContext *s) } if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE) { if ((err = mov_rewrite_dvd_sub_extradata(st)) < 0) - return err; + goto fail; } } if (mov->handbrake_version && mov->handbrake_version <= 1000000*0 + 1000*10 + 2 && // 0.10.2 - st->codecpar->codec_id == AV_CODEC_ID_MP3 - ) { + st->codecpar->codec_id == AV_CODEC_ID_MP3) { av_log(s, AV_LOG_VERBOSE, "Forcing full parsing for mp3 stream\n"); st->need_parsing = AVSTREAM_PARSE_FULL; } @@ -7682,8 +7664,8 @@ static int mov_read_header(AVFormatContext *s) if (sc->data_size > INT64_MAX / sc->time_scale / 8) { av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %"PRId64" * 8 * %d\n", sc->data_size, sc->time_scale); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->bit_rate = sc->data_size * 8 * sc->time_scale / st->duration; } @@ -7698,8 +7680,8 @@ static int mov_read_header(AVFormatContext *s) if (sc->data_size > INT64_MAX / sc->time_scale / 8) { av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %"PRId64" * 8 * %d\n", sc->data_size, sc->time_scale); - mov_read_close(s); - return AVERROR_INVALIDDATA; + err = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->bit_rate = sc->data_size * 8 * sc->time_scale / sc->duration_for_fps; @@ -7722,17 +7704,15 @@ static int mov_read_header(AVFormatContext *s) switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: err = ff_replaygain_export(st, s->metadata); - if (err < 0) { - mov_read_close(s); - return err; - } + if (err < 0) + goto fail; break; case AVMEDIA_TYPE_VIDEO: if (sc->display_matrix) { err = av_stream_add_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, (uint8_t*)sc->display_matrix, sizeof(int32_t) * 9); if (err < 0) - return err; + goto fail; sc->display_matrix = NULL; } @@ -7741,7 +7721,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->stereo3d, sizeof(*sc->stereo3d)); if (err < 0) - return err; + goto fail; sc->stereo3d = NULL; } @@ -7750,7 +7730,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->spherical, sc->spherical_size); if (err < 0) - return err; + goto fail; sc->spherical = NULL; } @@ -7759,7 +7739,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->mastering, sizeof(*sc->mastering)); if (err < 0) - return err; + goto fail; sc->mastering = NULL; } @@ -7768,7 +7748,7 @@ static int mov_read_header(AVFormatContext *s) (uint8_t *)sc->coll, sc->coll_size); if (err < 0) - return err; + goto fail; sc->coll = NULL; } @@ -7782,6 +7762,9 @@ static int mov_read_header(AVFormatContext *s) mov->frag_index.item[i].headers_read = 1; return 0; +fail: + mov_read_close(s); + return err; } static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) @@ -7876,6 +7859,27 @@ static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt) return 0; } +static int get_eia608_packet(AVIOContext *pb, AVPacket *pkt, int size) +{ + int new_size, ret; + + if (size <= 8) + return AVERROR_INVALIDDATA; + new_size = ((size - 8) / 2) * 3; + ret = av_new_packet(pkt, new_size); + if (ret < 0) + return ret; + + avio_skip(pb, 8); + for (int j = 0; j < new_size; j += 3) { + pkt->data[j] = 0xFC; + pkt->data[j+1] = avio_r8(pb); + pkt->data[j+2] = avio_r8(pb); + } + + return 0; +} + static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) { MOVContext *mov = s->priv_data; @@ -7915,18 +7919,34 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_INVALIDDATA; } - if( st->discard == AVDISCARD_NONKEY && 0==(sample->flags & AVINDEX_KEYFRAME) ) { + if (st->discard == AVDISCARD_NONKEY && !(sample->flags & AVINDEX_KEYFRAME)) { av_log(mov->fc, AV_LOG_DEBUG, "Nonkey frame from stream %d discarded due to AVDISCARD_NONKEY\n", sc->ffindex); goto retry; } - ret = av_get_packet(sc->pb, pkt, sample->size); + if (st->codecpar->codec_id == AV_CODEC_ID_EIA_608 && sample->size > 8) + ret = get_eia608_packet(sc->pb, pkt, sample->size); + else + ret = av_get_packet(sc->pb, pkt, sample->size); if (ret < 0) { if (should_retry(sc->pb, ret)) { mov_current_sample_dec(sc); } return ret; } +#if CONFIG_DV_DEMUXER + if (mov->dv_demux && sc->dv_audio_container) { + AVBufferRef *buf = pkt->buf; + ret = avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); + pkt->buf = buf; + av_packet_unref(pkt); + if (ret < 0) + return ret; + ret = avpriv_dv_get_packet(mov->dv_demux, pkt); + if (ret < 0) + return ret; + } +#endif if (sc->has_palette) { uint8_t *pal; @@ -7938,16 +7958,6 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) sc->has_palette = 0; } } -#if CONFIG_DV_DEMUXER - if (mov->dv_demux && sc->dv_audio_container) { - avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); - av_freep(&pkt->data); - pkt->size = 0; - ret = avpriv_dv_get_packet(mov->dv_demux, pkt); - if (ret < 0) - return ret; - } -#endif if (st->codecpar->codec_id == AV_CODEC_ID_MP3 && !st->need_parsing && pkt->size > 4) { if (ff_mpa_check_header(AV_RB32(pkt->data)) < 0) st->need_parsing = AVSTREAM_PARSE_FULL; @@ -8073,17 +8083,17 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, /* adjust stsd index */ if (sc->chunk_count) { - time_sample = 0; - for (i = 0; i < sc->stsc_count; i++) { - int64_t next = time_sample + mov_get_stsc_samples(sc, i); - if (next > sc->current_sample) { - sc->stsc_index = i; - sc->stsc_sample = sc->current_sample - time_sample; - break; + time_sample = 0; + for (i = 0; i < sc->stsc_count; i++) { + int64_t next = time_sample + mov_get_stsc_samples(sc, i); + if (next > sc->current_sample) { + sc->stsc_index = i; + sc->stsc_sample = sc->current_sample - time_sample; + break; + } + av_assert0(next == (int)next); + time_sample = next; } - av_assert0(next == (int)next); - time_sample = next; - } } return sample; diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.c b/chromium/third_party/ffmpeg/libavformat/movenc.c index 32e81092687..7db2e288407 100644 --- a/chromium/third_party/ffmpeg/libavformat/movenc.c +++ b/chromium/third_party/ffmpeg/libavformat/movenc.c @@ -4798,28 +4798,40 @@ static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov) { - int64_t pos = avio_tell(pb); - int i; + AVIOContext *mfra_pb; + int i, ret, sz; + uint8_t *buf; - avio_wb32(pb, 0); /* size placeholder */ - ffio_wfourcc(pb, "mfra"); + ret = avio_open_dyn_buf(&mfra_pb); + if (ret < 0) + return ret; + + avio_wb32(mfra_pb, 0); /* size placeholder */ + ffio_wfourcc(mfra_pb, "mfra"); /* An empty mfra atom is enough to indicate to the publishing point that * the stream has ended. */ if (mov->flags & FF_MOV_FLAG_ISML) - return update_size(pb, pos); + goto done_mfra; for (i = 0; i < mov->nb_streams; i++) { MOVTrack *track = &mov->tracks[i]; if (track->nb_frag_info) - mov_write_tfra_tag(pb, track); + mov_write_tfra_tag(mfra_pb, track); } - avio_wb32(pb, 16); - ffio_wfourcc(pb, "mfro"); - avio_wb32(pb, 0); /* version + flags */ - avio_wb32(pb, avio_tell(pb) + 4 - pos); + avio_wb32(mfra_pb, 16); + ffio_wfourcc(mfra_pb, "mfro"); + avio_wb32(mfra_pb, 0); /* version + flags */ + avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4); - return update_size(pb, pos); +done_mfra: + + sz = update_size(mfra_pb, 0); + ret = avio_get_dyn_buf(mfra_pb, &buf); + avio_write(pb, buf, ret); + ffio_free_dyn_buf(&mfra_pb); + + return sz; } static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov) @@ -4875,7 +4887,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; int64_t pos = avio_tell(pb); - int has_h264 = 0, has_video = 0; + int has_h264 = 0, has_av1 = 0, has_video = 0; int i; for (i = 0; i < s->nb_streams; i++) { @@ -4886,6 +4898,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) has_video = 1; if (st->codecpar->codec_id == AV_CODEC_ID_H264) has_h264 = 1; + if (st->codecpar->codec_id == AV_CODEC_ID_AV1) + has_av1 = 1; } avio_wb32(pb, 0); /* size */ @@ -4909,6 +4923,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) ffio_wfourcc(pb, "cmfc"); if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)) ffio_wfourcc(pb, "iso6"); + if (has_av1) + ffio_wfourcc(pb, "av01"); } else { if (mov->flags & FF_MOV_FLAG_FRAGMENT) ffio_wfourcc(pb, "iso6"); @@ -5504,6 +5520,23 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE); } + if ((par->codec_id == AV_CODEC_ID_DNXHD || + par->codec_id == AV_CODEC_ID_H264 || + par->codec_id == AV_CODEC_ID_HEVC || + par->codec_id == AV_CODEC_ID_TRUEHD || + par->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len && + !TAG_IS_AVCI(trk->tag)) { + /* copy frame to create needed atoms */ + trk->vos_len = size; + trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!trk->vos_data) { + ret = AVERROR(ENOMEM); + goto err; + } + memcpy(trk->vos_data, pkt->data, size); + memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + } + if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { if (!s->streams[pkt->stream_index]->nb_frames) { @@ -5565,6 +5598,22 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) goto end; avio_write(pb, pkt->data, size); #endif + } else if (par->codec_id == AV_CODEC_ID_EIA_608) { + size = 8; + + for (int i = 0; i < pkt->size; i += 3) { + if (pkt->data[i] == 0xFC) { + size += 2; + } + } + avio_wb32(pb, size); + ffio_wfourcc(pb, "cdat"); + for (int i = 0; i < pkt->size; i += 3) { + if (pkt->data[i] == 0xFC) { + avio_w8(pb, pkt->data[i + 1]); + avio_w8(pb, pkt->data[i + 2]); + } + } } else { if (trk->cenc.aes_ctr) { if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) { @@ -5582,20 +5631,6 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } } - if ((par->codec_id == AV_CODEC_ID_DNXHD || - par->codec_id == AV_CODEC_ID_TRUEHD || - par->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len) { - /* copy frame to create needed atoms */ - trk->vos_len = size; - trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!trk->vos_data) { - ret = AVERROR(ENOMEM); - goto err; - } - memcpy(trk->vos_data, pkt->data, size); - memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - } - if (trk->entry >= trk->cluster_capacity) { unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE; if (av_reallocp_array(&trk->cluster, new_capacity, @@ -5765,7 +5800,7 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) trk->par->codec_id == AV_CODEC_ID_AAC || trk->par->codec_id == AV_CODEC_ID_AV1 || trk->par->codec_id == AV_CODEC_ID_FLAC) { - int side_size = 0; + int side_size; uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE); @@ -6964,7 +6999,9 @@ static int mov_write_trailer(AVFormatContext *s) } if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) { avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); - mov_write_mfra_tag(pb, mov); + res = mov_write_mfra_tag(pb, mov); + if (res < 0) + return res; } } diff --git a/chromium/third_party/ffmpeg/libavformat/mp3enc.c b/chromium/third_party/ffmpeg/libavformat/mp3enc.c index 34b753ffa06..a3586e1f860 100644 --- a/chromium/third_party/ffmpeg/libavformat/mp3enc.c +++ b/chromium/third_party/ffmpeg/libavformat/mp3enc.c @@ -45,6 +45,7 @@ static int id3v1_set_string(AVFormatContext *s, const char *key, return !!tag; } +// refer to: http://id3.org/ID3v1 static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) { AVDictionaryEntry *tag; @@ -58,7 +59,17 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) count += id3v1_set_string(s, "TIT2", buf + 3, 30 + 1); //title count += id3v1_set_string(s, "TPE1", buf + 33, 30 + 1); //author|artist count += id3v1_set_string(s, "TALB", buf + 63, 30 + 1); //album - count += id3v1_set_string(s, "TDRC", buf + 93, 4 + 1); //date + if ((tag = av_dict_get(s->metadata, "TYER", NULL, 0))) { //year + av_strlcpy(buf + 93, tag->value, 4 + 1); + count++; + } else if ((tag = av_dict_get(s->metadata, "TDRC", NULL, 0))) { + av_strlcpy(buf + 93, tag->value, 4 + 1); + count++; + } else if ((tag = av_dict_get(s->metadata, "TDAT", NULL, 0))) { + av_strlcpy(buf + 93, tag->value, 4 + 1); + count++; + } + count += id3v1_set_string(s, "comment", buf + 97, 30 + 1); if ((tag = av_dict_get(s->metadata, "TRCK", NULL, 0))) { //track buf[125] = 0; @@ -343,7 +354,7 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) if (mp3->xing_offset) { uint8_t *side_data = NULL; - int side_data_size = 0; + int side_data_size; mp3_xing_add_frame(mp3, pkt); mp3->audio_size += pkt->size; diff --git a/chromium/third_party/ffmpeg/libavformat/mpeg.c b/chromium/third_party/ffmpeg/libavformat/mpeg.c index 33c03980606..265b2bd1adb 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/mpeg.c @@ -99,7 +99,7 @@ static int mpegps_probe(const AVProbeData *p) if (sys > invalid && sys * 9 <= pspack * 10) return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2 - : AVPROBE_SCORE_EXTENSION / 2 + 1; // 1 more than mp3 + : AVPROBE_SCORE_EXTENSION / 2 + (audio + vid + pspack > 1); // 1 more than mp3 if (pspack > invalid && (priv1 + vid + audio) * 10 >= pspack * 9) return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg diff --git a/chromium/third_party/ffmpeg/libavformat/mpegenc.c b/chromium/third_party/ffmpeg/libavformat/mpegenc.c index 669ff9d152b..9bd0a555d46 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegenc.c @@ -1210,7 +1210,7 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) if (s->is_dvd) { // min VOBU length 0.4 seconds (mpucoder) if (is_iframe && - (s->packet_number == 0 || + (s->packet_number == 0 || pts != AV_NOPTS_VALUE && (pts - stream->vobu_start_pts >= 36000))) { stream->bytes_to_iframe = av_fifo_size(stream->fifo); stream->align_iframe = 1; diff --git a/chromium/third_party/ffmpeg/libavformat/mpegts.c b/chromium/third_party/ffmpeg/libavformat/mpegts.c index ff3898c3a56..f71f18a57d9 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegts.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegts.c @@ -123,10 +123,6 @@ struct MpegTSContext { /** raw packet size, including FEC if present */ int raw_packet_size; - int size_stat[3]; - int size_stat_count; -#define SIZE_STAT_THRESHOLD 10 - int64_t pos47_full; /** if true, all pids are analyzed to find streams */ @@ -514,20 +510,22 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, { MpegTSFilter *filter; MpegTSSectionFilter *sec; + uint8_t *section_buf = av_mallocz(MAX_SECTION_SIZE); + + if (!section_buf) + return NULL; - if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) + if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) { + av_free(section_buf); return NULL; + } sec = &filter->u.section_filter; sec->section_cb = section_cb; sec->opaque = opaque; - sec->section_buf = av_mallocz(MAX_SECTION_SIZE); + sec->section_buf = section_buf; sec->check_crc = check_crc; sec->last_ver = -1; - if (!sec->section_buf) { - av_free(filter); - return NULL; - } return filter; } @@ -2180,7 +2178,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type ret = av_stream_add_side_data(st, AV_PKT_DATA_DOVI_CONF, (uint8_t *)dovi, dovi_size); if (ret < 0) { - av_freep(dovi); + av_free(dovi); return ret; } @@ -2840,63 +2838,39 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet, int64_t pos) return 0; } -static void reanalyze(MpegTSContext *ts) { - AVIOContext *pb = ts->stream->pb; - int64_t pos = avio_tell(pb); - if (pos < 0) - return; - pos -= ts->pos47_full; - if (pos == TS_PACKET_SIZE) { - ts->size_stat[0] ++; - } else if (pos == TS_DVHS_PACKET_SIZE) { - ts->size_stat[1] ++; - } else if (pos == TS_FEC_PACKET_SIZE) { - ts->size_stat[2] ++; - } - - ts->size_stat_count ++; - if (ts->size_stat_count > SIZE_STAT_THRESHOLD) { - int newsize = 0; - if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) { - newsize = TS_PACKET_SIZE; - } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) { - newsize = TS_DVHS_PACKET_SIZE; - } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) { - newsize = TS_FEC_PACKET_SIZE; - } - if (newsize && newsize != ts->raw_packet_size) { - av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize); - ts->raw_packet_size = newsize; - } - ts->size_stat_count = 0; - memset(ts->size_stat, 0, sizeof(ts->size_stat)); - } -} - -/* XXX: try to find a better synchro over several packets (use - * get_packet_size() ?) */ static int mpegts_resync(AVFormatContext *s, int seekback, const uint8_t *current_packet) { MpegTSContext *ts = s->priv_data; AVIOContext *pb = s->pb; int c, i; uint64_t pos = avio_tell(pb); - - avio_seek(pb, -FFMIN(seekback, pos), SEEK_CUR); + int64_t back = FFMIN(seekback, pos); //Special case for files like 01c56b0dc1.ts if (current_packet[0] == 0x80 && current_packet[12] == 0x47) { - avio_seek(pb, 12, SEEK_CUR); + avio_seek(pb, 12 - back, SEEK_CUR); return 0; } + avio_seek(pb, -back, SEEK_CUR); + for (i = 0; i < ts->resync_size; i++) { c = avio_r8(pb); if (avio_feof(pb)) return AVERROR_EOF; if (c == 0x47) { + int new_packet_size, ret; avio_seek(pb, -1, SEEK_CUR); - reanalyze(s->priv_data); + pos = avio_tell(pb); + ret = ffio_ensure_seekback(pb, PROBE_PACKET_MAX_BUF); + if (ret < 0) + return ret; + new_packet_size = get_packet_size(s); + if (new_packet_size > 0 && new_packet_size != ts->raw_packet_size) { + av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", new_packet_size); + ts->raw_packet_size = new_packet_size; + } + avio_seek(pb, pos, SEEK_SET); return 0; } } diff --git a/chromium/third_party/ffmpeg/libavformat/mpegts.h b/chromium/third_party/ffmpeg/libavformat/mpegts.h index 059b693f078..fe10b38691b 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegts.h +++ b/chromium/third_party/ffmpeg/libavformat/mpegts.h @@ -137,6 +137,13 @@ #define STREAM_TYPE_AUDIO_TRUEHD 0x83 #define STREAM_TYPE_AUDIO_EAC3 0x87 +/* ISO/IEC 13818-1 Table 2-22 */ +#define STREAM_ID_PRIVATE_STREAM_1 0xbd +#define STREAM_ID_AUDIO_STREAM_0 0xc0 +#define STREAM_ID_VIDEO_STREAM_0 0xe0 +#define STREAM_ID_METADATA_STREAM 0xfc +#define STREAM_ID_EXTENDED_STREAM_ID 0xfd + typedef struct MpegTSContext MpegTSContext; MpegTSContext *avpriv_mpegts_parse_open(AVFormatContext *s); diff --git a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c index f2be6c66327..718ddabff7e 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c @@ -79,8 +79,6 @@ typedef struct MpegTSWrite { int64_t sdt_period; /* SDT period in PCR time base */ int64_t pat_period; /* PAT/PMT period in PCR time base */ int nb_services; - int onid; - int tsid; int64_t first_pcr; int64_t next_pcr; int mux_rate; ///< set to 1 when VBR @@ -261,7 +259,7 @@ static void mpegts_write_pat(AVFormatContext *s) put16(&q, service->sid); put16(&q, 0xe000 | service->pmt.pid); } - mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, ts->tables_version, 0, 0, + mpegts_write_section1(&ts->pat, PAT_TID, ts->transport_stream_id, ts->tables_version, 0, 0, data, q - data); } @@ -355,6 +353,13 @@ static int get_dvb_stream_type(AVFormatContext *s, AVStream *st) case AV_CODEC_ID_DVB_TELETEXT: stream_type = STREAM_TYPE_PRIVATE_DATA; break; + case AV_CODEC_ID_SMPTE_KLV: + if (st->codecpar->profile == FF_PROFILE_KLVA_SYNC) { + stream_type = STREAM_TYPE_METADATA; + } else { + stream_type = STREAM_TYPE_PRIVATE_DATA; + } + break; default: av_log_once(s, AV_LOG_WARNING, AV_LOG_DEBUG, &ts_st->data_st_warning, "Stream %d, codec %s, is muxed as a private data stream " @@ -448,6 +453,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) AVStream *st = s->streams[i]; MpegTSWriteStream *ts_st = st->priv_data; AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); + enum AVCodecID codec_id = st->codecpar->codec_id; if (s->nb_programs) { int k, found = 0; @@ -478,19 +484,20 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) /* write optional descriptors here */ switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: - if (st->codecpar->codec_id==AV_CODEC_ID_AC3 && (ts->flags & MPEGTS_FLAG_SYSTEM_B)) { - *q++=0x6a; // AC3 descriptor see A038 DVB SI - *q++=1; // 1 byte, all flags sets to 0 - *q++=0; // omit all fields... - } - if (st->codecpar->codec_id==AV_CODEC_ID_EAC3 && (ts->flags & MPEGTS_FLAG_SYSTEM_B)) { - *q++=0x7a; // EAC3 descriptor see A038 DVB SI - *q++=1; // 1 byte, all flags sets to 0 - *q++=0; // omit all fields... + if (ts->flags & MPEGTS_FLAG_SYSTEM_B) { + if (codec_id == AV_CODEC_ID_AC3) { + *q++=0x6a; // AC3 descriptor see A038 DVB SI + *q++=1; // 1 byte, all flags sets to 0 + *q++=0; // omit all fields... + } else if (codec_id == AV_CODEC_ID_EAC3) { + *q++=0x7a; // EAC3 descriptor see A038 DVB SI + *q++=1; // 1 byte, all flags sets to 0 + *q++=0; // omit all fields... + } } - if (st->codecpar->codec_id==AV_CODEC_ID_S302M) + if (codec_id == AV_CODEC_ID_S302M) put_registration_descriptor(&q, MKTAG('B', 'S', 'S', 'D')); - if (st->codecpar->codec_id==AV_CODEC_ID_OPUS) { + if (codec_id == AV_CODEC_ID_OPUS) { /* 6 bytes registration descriptor, 4 bytes Opus audio descriptor */ if (q - data > SECTION_LENGTH - 6 - 4) { err = 1; @@ -605,7 +612,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) const char default_language[] = "und"; const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language; - if (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE) { + if (codec_id == AV_CODEC_ID_DVB_SUBTITLE) { uint8_t *len_ptr; int extradata_copied = 0; @@ -647,7 +654,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) } *len_ptr = q - len_ptr - 1; - } else if (st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT) { + } else if (codec_id == AV_CODEC_ID_DVB_TELETEXT) { uint8_t *len_ptr = NULL; int extradata_copied = 0; @@ -691,9 +698,9 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) } break; case AVMEDIA_TYPE_DATA: - if (st->codecpar->codec_id == AV_CODEC_ID_SMPTE_KLV) { + if (codec_id == AV_CODEC_ID_SMPTE_KLV) { put_registration_descriptor(&q, MKTAG('K', 'L', 'V', 'A')); - } else if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { + } else if (codec_id == AV_CODEC_ID_TIMED_ID3) { const char *tag = "ID3 "; *q++ = 0x26; /* metadata descriptor */ *q++ = 13; @@ -731,7 +738,7 @@ static void mpegts_write_sdt(AVFormatContext *s) int i, running_status, free_ca_mode, val; q = data; - put16(&q, ts->onid); + put16(&q, ts->original_network_id); *q++ = 0xff; for (i = 0; i < ts->nb_services; i++) { service = ts->services[i]; @@ -757,7 +764,7 @@ static void mpegts_write_sdt(AVFormatContext *s) desc_list_len_ptr[0] = val >> 8; desc_list_len_ptr[1] = val; } - mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, ts->tables_version, 0, 0, + mpegts_write_section1(&ts->sdt, SDT_TID, ts->transport_stream_id, ts->tables_version, 0, 0, data, q - data); } @@ -931,7 +938,6 @@ static int mpegts_init(AVFormatContext *s) { MpegTSWrite *ts = s->priv_data; int i, j; - int *pids; int ret; if (ts->m2ts_mode == -1) { @@ -961,8 +967,6 @@ static int mpegts_init(AVFormatContext *s) // round up to a whole number of TS packets ts->pes_payload_size = (ts->pes_payload_size + 14 + 183) / 184 * 184 - 14; - ts->tsid = ts->transport_stream_id; - ts->onid = ts->original_network_id; if (!s->nb_programs) { /* allocate a single DVB service */ if (!mpegts_add_service(s, ts->service_id, s->metadata, NULL)) @@ -989,12 +993,6 @@ static int mpegts_init(AVFormatContext *s) ts->sdt.write_packet = section_write_packet; ts->sdt.opaque = s; - pids = av_malloc_array(s->nb_streams, sizeof(*pids)); - if (!pids) { - ret = AVERROR(ENOMEM); - goto fail; - } - /* assign pids to each stream */ for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -1002,8 +1000,7 @@ static int mpegts_init(AVFormatContext *s) ts_st = av_mallocz(sizeof(MpegTSWriteStream)); if (!ts_st) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } st->priv_data = ts_st; @@ -1011,8 +1008,7 @@ static int mpegts_init(AVFormatContext *s) ts_st->payload = av_mallocz(ts->pes_payload_size); if (!ts_st->payload) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } /* MPEG pid values < 16 are reserved. Applications which set st->id in @@ -1043,8 +1039,7 @@ static int mpegts_init(AVFormatContext *s) ts->m2ts_textsub_pid > M2TS_TEXTSUB_PID + 1 || ts_st->pid < 16) { av_log(s, AV_LOG_ERROR, "Cannot automatically assign PID for stream %d\n", st->index); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } } else { ts_st->pid = ts->start_pid + i; @@ -1055,30 +1050,26 @@ static int mpegts_init(AVFormatContext *s) if (ts_st->pid >= 0x1FFF) { av_log(s, AV_LOG_ERROR, "Invalid stream id %d, must be less than 8191\n", st->id); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } for (j = 0; j < ts->nb_services; j++) { if (ts->services[j]->pmt.pid > LAST_OTHER_PID) { av_log(s, AV_LOG_ERROR, "Invalid PMT PID %d, must be less than %d\n", ts->services[j]->pmt.pid, LAST_OTHER_PID + 1); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } if (ts_st->pid == ts->services[j]->pmt.pid) { av_log(s, AV_LOG_ERROR, "PID %d cannot be both elementary and PMT PID\n", ts_st->pid); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } } for (j = 0; j < i; j++) { - if (pids[j] == ts_st->pid) { + MpegTSWriteStream *ts_st_prev = s->streams[j]->priv_data; + if (ts_st_prev->pid == ts_st->pid) { av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", ts_st->pid); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } } - pids[i] = ts_st->pid; ts_st->payload_pts = AV_NOPTS_VALUE; ts_st->payload_dts = AV_NOPTS_VALUE; ts_st->first_pts_check = 1; @@ -1089,35 +1080,30 @@ static int mpegts_init(AVFormatContext *s) AVStream *ast; ts_st->amux = avformat_alloc_context(); if (!ts_st->amux) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } ts_st->amux->oformat = av_guess_format((ts->flags & MPEGTS_FLAG_AAC_LATM) ? "latm" : "adts", NULL, NULL); if (!ts_st->amux->oformat) { - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } if (!(ast = avformat_new_stream(ts_st->amux, NULL))) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } ret = avcodec_parameters_copy(ast->codecpar, st->codecpar); if (ret != 0) - goto fail; + return ret; ast->time_base = st->time_base; ret = avformat_write_header(ts_st->amux, NULL); if (ret < 0) - goto fail; + return ret; } if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) { ts_st->opus_pending_trim_start = st->codecpar->initial_padding * 48000 / st->codecpar->sample_rate; } } - av_freep(&pids); - if (ts->copyts < 1) ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE); @@ -1138,10 +1124,6 @@ static int mpegts_init(AVFormatContext *s) av_rescale(ts->pat_period, 1000, PCR_TIME_BASE)); return 0; - -fail: - av_freep(&pids); - return ret; } /* send SDT, PAT and PMT tables regularly */ @@ -1402,28 +1384,28 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, is_dvb_teletext = 0; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (st->codecpar->codec_id == AV_CODEC_ID_DIRAC) - *q++ = 0xfd; + *q++ = STREAM_ID_EXTENDED_STREAM_ID; else - *q++ = 0xe0; + *q++ = STREAM_ID_VIDEO_STREAM_0; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && (st->codecpar->codec_id == AV_CODEC_ID_MP2 || st->codecpar->codec_id == AV_CODEC_ID_MP3 || st->codecpar->codec_id == AV_CODEC_ID_AAC)) { - *q++ = 0xc0; + *q++ = STREAM_ID_AUDIO_STREAM_0; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->codec_id == AV_CODEC_ID_AC3 && ts->m2ts_mode) { - *q++ = 0xfd; + *q++ = STREAM_ID_EXTENDED_STREAM_ID; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA && st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { - *q++ = 0xbd; + *q++ = STREAM_ID_PRIVATE_STREAM_1; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { - *q++ = stream_id != -1 ? stream_id : 0xfc; + *q++ = stream_id != -1 ? stream_id : STREAM_ID_METADATA_STREAM; - if (stream_id == 0xbd) /* asynchronous KLV */ + if (stream_id == STREAM_ID_PRIVATE_STREAM_1) /* asynchronous KLV */ pts = dts = AV_NOPTS_VALUE; } else { - *q++ = 0xbd; + *q++ = STREAM_ID_PRIVATE_STREAM_1; if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { if (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE) { is_dvb_subtitle = 1; @@ -1459,10 +1441,10 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, if (ts->m2ts_mode && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->codec_id == AV_CODEC_ID_AC3) { - /* set PES_extension_flag */ - pes_extension = 1; - flags |= 0x01; - header_len += 3; + /* set PES_extension_flag */ + pes_extension = 1; + flags |= 0x01; + header_len += 3; } if (is_dvb_teletext) { pes_header_stuffing_bytes = 0x24 - header_len; @@ -1505,14 +1487,14 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, *q++ = 0x00 | 0x60; } /* For Blu-ray AC3 Audio Setting extended flags */ - if (ts->m2ts_mode && - pes_extension && - st->codecpar->codec_id == AV_CODEC_ID_AC3) { - flags = 0x01; /* set PES_extension_flag_2 */ - *q++ = flags; - *q++ = 0x80 | 0x01; /* marker bit + extension length */ - *q++ = 0x00 | 0x71; /* for AC3 Audio (specifically on blue-rays) */ - } + if (ts->m2ts_mode && + pes_extension && + st->codecpar->codec_id == AV_CODEC_ID_AC3) { + flags = 0x01; /* set PES_extension_flag_2 */ + *q++ = flags; + *q++ = 0x80 | 0x01; /* marker bit + extension length */ + *q++ = 0x00 | 0x71; /* for AC3 Audio (specifically on blue-rays) */ + } if (is_dvb_subtitle) { @@ -1989,94 +1971,62 @@ static int mpegts_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt return ret; } +#define OFFSET(x) offsetof(MpegTSWrite, x) +#define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "mpegts_transport_stream_id", "Set transport_stream_id field.", - offsetof(MpegTSWrite, transport_stream_id), AV_OPT_TYPE_INT, - { .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(transport_stream_id), AV_OPT_TYPE_INT, { .i64 = 0x0001 }, 0x0001, 0xffff, ENC }, { "mpegts_original_network_id", "Set original_network_id field.", - offsetof(MpegTSWrite, original_network_id), AV_OPT_TYPE_INT, - { .i64 = DVB_PRIVATE_NETWORK_START }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(original_network_id), AV_OPT_TYPE_INT, { .i64 = DVB_PRIVATE_NETWORK_START }, 0x0001, 0xffff, ENC }, { "mpegts_service_id", "Set service_id field.", - offsetof(MpegTSWrite, service_id), AV_OPT_TYPE_INT, - { .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(service_id), AV_OPT_TYPE_INT, { .i64 = 0x0001 }, 0x0001, 0xffff, ENC }, { "mpegts_service_type", "Set service_type field.", - offsetof(MpegTSWrite, service_type), AV_OPT_TYPE_INT, - { .i64 = 0x01 }, 0x01, 0xff, AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + OFFSET(service_type), AV_OPT_TYPE_INT, { .i64 = 0x01 }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "digital_tv", "Digital Television.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_TV }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_TV }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "digital_radio", "Digital Radio.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_RADIO }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_RADIO }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "teletext", "Teletext.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_TELETEXT }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_TELETEXT }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "advanced_codec_digital_radio", "Advanced Codec Digital Radio.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "mpeg2_digital_hdtv", "MPEG2 Digital HDTV.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "advanced_codec_digital_sdtv", "Advanced Codec Digital SDTV.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "advanced_codec_digital_hdtv", "Advanced Codec Digital HDTV.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "hevc_digital_hdtv", "HEVC Digital Television Service.", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_HEVC_DIGITAL_HDTV }, 0x01, 0xff, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_HEVC_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" }, { "mpegts_pmt_start_pid", "Set the first pid of the PMT.", - offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT, - { .i64 = 0x1000 }, FIRST_OTHER_PID, LAST_OTHER_PID, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(pmt_start_pid), AV_OPT_TYPE_INT, { .i64 = 0x1000 }, FIRST_OTHER_PID, LAST_OTHER_PID, ENC }, { "mpegts_start_pid", "Set the first pid.", - offsetof(MpegTSWrite, start_pid), AV_OPT_TYPE_INT, - { .i64 = 0x0100 }, FIRST_OTHER_PID, LAST_OTHER_PID, AV_OPT_FLAG_ENCODING_PARAM }, - { "mpegts_m2ts_mode", "Enable m2ts mode.", - offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_BOOL, - { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "muxrate", NULL, - offsetof(MpegTSWrite, mux_rate), AV_OPT_TYPE_INT, - { .i64 = 1 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(start_pid), AV_OPT_TYPE_INT, { .i64 = 0x0100 }, FIRST_OTHER_PID, LAST_OTHER_PID, ENC }, + { "mpegts_m2ts_mode", "Enable m2ts mode.", OFFSET(m2ts_mode), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, ENC }, + { "muxrate", NULL, OFFSET(mux_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, { "pes_payload_size", "Minimum PES packet payload in bytes", - offsetof(MpegTSWrite, pes_payload_size), AV_OPT_TYPE_INT, - { .i64 = DEFAULT_PES_PAYLOAD_SIZE }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, - { "mpegts_flags", "MPEG-TS muxing flags", - offsetof(MpegTSWrite, flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, + OFFSET(pes_payload_size), AV_OPT_TYPE_INT, { .i64 = DEFAULT_PES_PAYLOAD_SIZE }, 0, INT_MAX, ENC }, + { "mpegts_flags", "MPEG-TS muxing flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX, ENC, "mpegts_flags" }, { "resend_headers", "Reemit PAT/PMT before writing the next packet", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_REEMIT_PAT_PMT }, 0, INT_MAX, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_REEMIT_PAT_PMT }, 0, INT_MAX, ENC, "mpegts_flags" }, { "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" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_AAC_LATM }, 0, INT_MAX, ENC, "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" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_PAT_PMT_AT_FRAMES}, 0, INT_MAX, ENC, "mpegts_flags" }, { "system_b", "Conform to System B (DVB) instead of System A (ATSC)", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX, ENC, "mpegts_flags" }, { "initial_discontinuity", "Mark initial packets as discontinuous", - 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 0, INT_MAX, - AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, - { "mpegts_copyts", "don't offset dts/pts", - offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_BOOL, - { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM }, - { "tables_version", "set PAT, PMT and SDT version", - offsetof(MpegTSWrite, tables_version), AV_OPT_TYPE_INT, - { .i64 = 0 }, 0, 31, AV_OPT_FLAG_ENCODING_PARAM }, + 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 0, INT_MAX, ENC, "mpegts_flags" }, + { "mpegts_copyts", "don't offset dts/pts", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, ENC }, + { "tables_version", "set PAT, PMT and SDT version", OFFSET(tables_version), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 31, ENC }, { "omit_video_pes_length", "Omit the PES packet length for video packets", - offsetof(MpegTSWrite, omit_video_pes_length), AV_OPT_TYPE_BOOL, - { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(omit_video_pes_length), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC }, { "pcr_period", "PCR retransmission time in milliseconds", - offsetof(MpegTSWrite, pcr_period_ms), AV_OPT_TYPE_INT, - { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(pcr_period_ms), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC }, { "pat_period", "PAT/PMT retransmission time limit in seconds", - offsetof(MpegTSWrite, pat_period_us), AV_OPT_TYPE_DURATION, - { .i64 = PAT_RETRANS_TIME * 1000LL }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(pat_period_us), AV_OPT_TYPE_DURATION, { .i64 = PAT_RETRANS_TIME * 1000LL }, 0, INT64_MAX, ENC }, { "sdt_period", "SDT retransmission time limit in seconds", - offsetof(MpegTSWrite, sdt_period_us), AV_OPT_TYPE_DURATION, - { .i64 = SDT_RETRANS_TIME * 1000LL }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + OFFSET(sdt_period_us), AV_OPT_TYPE_DURATION, { .i64 = SDT_RETRANS_TIME * 1000LL }, 0, INT64_MAX, ENC }, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/mpl2dec.c b/chromium/third_party/ffmpeg/libavformat/mpl2dec.c index 4ae18390f0b..38445c7aad3 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpl2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/mpl2dec.c @@ -55,7 +55,7 @@ static int mpl2_probe(const AVProbeData *p) return AVPROBE_SCORE_MAX; } -static int read_ts(char **line, int64_t *pts_start, int *duration) +static int read_ts(char **line, int64_t *pts_start, int64_t *duration) { char c; int len; @@ -69,7 +69,10 @@ static int read_ts(char **line, int64_t *pts_start, int *duration) } if (sscanf(*line, "[%"SCNd64"][%"SCNd64"]%c%n", pts_start, &end, &c, &len) >= 3) { - *duration = end - *pts_start; + if (end < *pts_start || end - (uint64_t)*pts_start > INT64_MAX) { + *duration = -1; + } else + *duration = end - *pts_start; *line += len - 1; return 0; } @@ -80,7 +83,6 @@ static int mpl2_read_header(AVFormatContext *s) { MPL2Context *mpl2 = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); - int res = 0; if (!st) return AVERROR(ENOMEM); @@ -97,7 +99,7 @@ static int mpl2_read_header(AVFormatContext *s) const int64_t pos = avio_tell(s->pb); int len = ff_get_line(s->pb, line, sizeof(line)); int64_t pts_start; - int duration; + int64_t duration; if (!len) break; @@ -108,8 +110,10 @@ static int mpl2_read_header(AVFormatContext *s) AVPacket *sub; sub = ff_subtitles_queue_insert(&mpl2->q, p, strlen(p), 0); - if (!sub) + if (!sub) { + ff_subtitles_queue_clean(&mpl2->q); return AVERROR(ENOMEM); + } sub->pos = pos; sub->pts = pts_start; sub->duration = duration; @@ -117,7 +121,7 @@ static int mpl2_read_header(AVFormatContext *s) } ff_subtitles_queue_finalize(s, &mpl2->q); - return res; + return 0; } static int mpl2_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/mpsubdec.c b/chromium/third_party/ffmpeg/libavformat/mpsubdec.c index 82c73457ead..e7b83a1d85f 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpsubdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mpsubdec.c @@ -154,8 +154,10 @@ static int mpsub_read_header(AVFormatContext *s) } st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); + if (!st) { + res = AVERROR(ENOMEM); + goto end; + } avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_TEXT; diff --git a/chromium/third_party/ffmpeg/libavformat/mux.c b/chromium/third_party/ffmpeg/libavformat/mux.c index 3d1f71ab1ad..44d5e5d1c0b 100644 --- a/chromium/third_party/ffmpeg/libavformat/mux.c +++ b/chromium/third_party/ffmpeg/libavformat/mux.c @@ -344,6 +344,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (desc && desc->props & AV_CODEC_PROP_REORDER) st->internal->reorder = 1; + st->internal->is_intra_only = ff_is_intra_only(par->codec_id); + if (of->codec_tag) { if ( par->codec_tag && par->codec_id == AV_CODEC_ID_RAWVIDEO @@ -757,18 +759,11 @@ static int check_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int prepare_input_packet(AVFormatContext *s, AVPacket *pkt) +static int prepare_input_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt) { - int ret; - - ret = check_packet(s, pkt); - if (ret < 0) - return ret; - #if !FF_API_COMPUTE_PKT_FIELDS2 || !FF_API_LAVF_AVCTX /* sanitize the timestamps */ if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { - AVStream *st = s->streams[pkt->stream_index]; /* when there is no reordering (so dts is equal to pts), but * only one of them is set, set the other as well */ @@ -805,114 +800,13 @@ static int prepare_input_packet(AVFormatContext *s, AVPacket *pkt) } } #endif + /* update flags */ + if (st->internal->is_intra_only) + pkt->flags |= AV_PKT_FLAG_KEY; return 0; } -static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { - AVStream *st = s->streams[pkt->stream_index]; - int ret; - - if (!(s->flags & AVFMT_FLAG_AUTO_BSF)) - return 1; - - if (s->oformat->check_bitstream) { - if (!st->internal->bitstream_checked) { - if ((ret = s->oformat->check_bitstream(s, pkt)) < 0) - return ret; - else if (ret == 1) - st->internal->bitstream_checked = 1; - } - } - - if (st->internal->bsfc) { - AVBSFContext *ctx = st->internal->bsfc; - // TODO: when any bitstream filter requires flushing at EOF, we'll need to - // flush each stream's BSF chain on write_trailer. - if ((ret = av_bsf_send_packet(ctx, pkt)) < 0) { - av_log(ctx, AV_LOG_ERROR, - "Failed to send packet to filter %s for stream %d\n", - ctx->filter->name, pkt->stream_index); - return ret; - } - // TODO: when any automatically-added bitstream filter is generating multiple - // output packets for a single input one, we'll need to call this in a loop - // and write each output packet. - if ((ret = av_bsf_receive_packet(ctx, pkt)) < 0) { - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - return 0; - av_log(ctx, AV_LOG_ERROR, - "Failed to receive packet from filter %s for stream %d\n", - ctx->filter->name, pkt->stream_index); - if (s->error_recognition & AV_EF_EXPLODE) - return ret; - return 0; - } - } - return 1; -} - -int av_write_frame(AVFormatContext *s, AVPacket *in) -{ - AVPacket local_pkt, *pkt = &local_pkt; - int ret; - - if (!in) { - if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { - ret = s->oformat->write_packet(s, NULL); - flush_if_needed(s); - if (ret >= 0 && s->pb && s->pb->error < 0) - ret = s->pb->error; - return ret; - } - return 1; - } - - if (in->flags & AV_PKT_FLAG_UNCODED_FRAME) { - pkt = in; - } else { - /* We don't own in, so we have to make sure not to modify it. - * The following avoids copying in's data unnecessarily. - * Copying side data is unavoidable as a bitstream filter - * may change it, e.g. free it on errors. */ - pkt->buf = NULL; - pkt->data = in->data; - pkt->size = in->size; - ret = av_packet_copy_props(pkt, in); - if (ret < 0) - return ret; - if (in->buf) { - pkt->buf = av_buffer_ref(in->buf); - if (!pkt->buf) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - } - - ret = prepare_input_packet(s, pkt); - if (ret < 0) - goto fail; - - ret = do_packet_auto_bsf(s, pkt); - if (ret <= 0) - goto fail; - -#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX - ret = compute_muxer_pkt_fields(s, s->streams[pkt->stream_index], pkt); - - if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - goto fail; -#endif - - ret = write_packet(s, pkt); - -fail: - // Uncoded frames using the noninterleaved codepath are also freed here - av_packet_unref(pkt); - return ret; -} - #define CHUNK_START 0x1000 int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, @@ -1173,49 +1067,32 @@ int ff_interleaved_peek(AVFormatContext *s, int stream, static int interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush) { if (s->oformat->interleave_packet) { - int ret = s->oformat->interleave_packet(s, out, in, flush); - if (in) - av_packet_unref(in); - return ret; + return s->oformat->interleave_packet(s, out, in, flush); } else return ff_interleave_packet_per_dts(s, out, in, flush); } -int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) +static int check_bitstream(AVFormatContext *s, AVStream *st, AVPacket *pkt) { - int ret, flush = 0; - - if (pkt) { - AVStream *st = s->streams[pkt->stream_index]; - - ret = prepare_input_packet(s, pkt); - if (ret < 0) - goto fail; - - ret = do_packet_auto_bsf(s, pkt); - if (ret == 0) - return 0; - else if (ret < 0) - goto fail; - - if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_DEBUG, "av_interleaved_write_frame size:%d dts:%s pts:%s\n", - pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts)); + int ret; -#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX - if ((ret = compute_muxer_pkt_fields(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - goto fail; -#endif + if (!(s->flags & AVFMT_FLAG_AUTO_BSF)) + return 1; - if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { - ret = AVERROR(EINVAL); - goto fail; + if (s->oformat->check_bitstream) { + if (!st->internal->bitstream_checked) { + if ((ret = s->oformat->check_bitstream(s, pkt)) < 0) + return ret; + else if (ret == 1) + st->internal->bitstream_checked = 1; } - } else { - av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); - flush = 1; } + return 1; +} + +static int interleaved_write_packet(AVFormatContext *s, AVPacket *pkt, int flush) +{ for (;; ) { AVPacket opkt; int ret = interleave_packet(s, &opkt, pkt, flush); @@ -1231,32 +1108,165 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret < 0) return ret; } -fail: - av_packet_unref(pkt); +} + +static int write_packet_common(AVFormatContext *s, AVStream *st, AVPacket *pkt, int interleaved) +{ + int ret; + + if (s->debug & FF_FDEBUG_TS) + av_log(s, AV_LOG_DEBUG, "%s size:%d dts:%s pts:%s\n", __FUNCTION__, + pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts)); + +#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX + if ((ret = compute_muxer_pkt_fields(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) + return ret; +#endif + + if (interleaved) { + if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) + return AVERROR(EINVAL); + return interleaved_write_packet(s, pkt, 0); + } else { + return write_packet(s, pkt); + } +} + +static int write_packets_from_bsfs(AVFormatContext *s, AVStream *st, AVPacket *pkt, int interleaved) +{ + AVBSFContext *bsfc = st->internal->bsfc; + int ret; + + if ((ret = av_bsf_send_packet(bsfc, pkt)) < 0) { + av_log(s, AV_LOG_ERROR, + "Failed to send packet to filter %s for stream %d\n", + bsfc->filter->name, st->index); + return ret; + } + + do { + ret = av_bsf_receive_packet(bsfc, pkt); + if (ret < 0) { + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return 0; + av_log(s, AV_LOG_ERROR, "Error applying bitstream filters to an output " + "packet for stream #%d: %s\n", st->index, av_err2str(ret)); + if (!(s->error_recognition & AV_EF_EXPLODE) && ret != AVERROR(ENOMEM)) + continue; + return ret; + } + av_packet_rescale_ts(pkt, bsfc->time_base_out, st->time_base); + ret = write_packet_common(s, st, pkt, interleaved); + if (ret >= 0 && !interleaved) // a successful write_packet_common already unrefed pkt for interleaved + av_packet_unref(pkt); + } while (ret >= 0); + return ret; } -int av_write_trailer(AVFormatContext *s) +static int write_packets_common(AVFormatContext *s, AVPacket *pkt, int interleaved) { - int ret, i; + AVStream *st; + int ret = check_packet(s, pkt); + if (ret < 0) + return ret; + st = s->streams[pkt->stream_index]; - for (;; ) { - AVPacket pkt; - ret = interleave_packet(s, &pkt, NULL, 1); - if (ret < 0) - goto fail; - if (!ret) - break; + ret = prepare_input_packet(s, st, pkt); + if (ret < 0) + return ret; - ret = write_packet(s, &pkt); + ret = check_bitstream(s, st, pkt); + if (ret < 0) + return ret; + + if (st->internal->bsfc) { + return write_packets_from_bsfs(s, st, pkt, interleaved); + } else { + return write_packet_common(s, st, pkt, interleaved); + } +} - av_packet_unref(&pkt); +int av_write_frame(AVFormatContext *s, AVPacket *in) +{ + AVPacket local_pkt, *pkt = &local_pkt; + int ret; + if (!in) { + if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { + ret = s->oformat->write_packet(s, NULL); + flush_if_needed(s); + if (ret >= 0 && s->pb && s->pb->error < 0) + ret = s->pb->error; + return ret; + } + return 1; + } + + if (in->flags & AV_PKT_FLAG_UNCODED_FRAME) { + pkt = in; + } else { + /* We don't own in, so we have to make sure not to modify it. + * The following avoids copying in's data unnecessarily. + * Copying side data is unavoidable as a bitstream filter + * may change it, e.g. free it on errors. */ + pkt->buf = NULL; + pkt->data = in->data; + pkt->size = in->size; + ret = av_packet_copy_props(pkt, in); if (ret < 0) - goto fail; + return ret; + if (in->buf) { + pkt->buf = av_buffer_ref(in->buf); + if (!pkt->buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + } } + ret = write_packets_common(s, pkt, 0/*non-interleaved*/); + fail: + // Uncoded frames using the noninterleaved codepath are also freed here + av_packet_unref(pkt); + return ret; +} + +int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) +{ + int ret; + + if (pkt) { + ret = write_packets_common(s, pkt, 1/*interleaved*/); + if (ret < 0) + av_packet_unref(pkt); + return ret; + } else { + av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); + return interleaved_write_packet(s, NULL, 1/*flush*/); + } +} + +int av_write_trailer(AVFormatContext *s) +{ + int i, ret1, ret = 0; + AVPacket pkt = {0}; + av_init_packet(&pkt); + + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->internal->bsfc) { + ret1 = write_packets_from_bsfs(s, s->streams[i], &pkt, 1/*interleaved*/); + if (ret1 < 0) + av_packet_unref(&pkt); + if (ret >= 0) + ret = ret1; + } + } + ret1 = interleaved_write_packet(s, NULL, 1); + if (ret >= 0) + ret = ret1; + if (s->oformat->write_trailer) { if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); diff --git a/chromium/third_party/ffmpeg/libavformat/mvdec.c b/chromium/third_party/ffmpeg/libavformat/mvdec.c index 64166a84b1f..d5b400213df 100644 --- a/chromium/third_party/ffmpeg/libavformat/mvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mvdec.c @@ -268,7 +268,7 @@ static void read_index(AVIOContext *pb, AVStream *st) avio_skip(pb, 8); av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME); if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - timestamp += size / (st->codecpar->channels * 2); + timestamp += size / (st->codecpar->channels * 2LL); } else { timestamp++; } @@ -355,7 +355,7 @@ static int mv_read_header(AVFormatContext *avctx) avio_skip(pb, 8); av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME); av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME); - timestamp += asize / (ast->codecpar->channels * 2); + timestamp += asize / (ast->codecpar->channels * 2LL); } } else if (!version && avio_rb16(pb) == 3) { avio_skip(pb, 4); diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.c b/chromium/third_party/ffmpeg/libavformat/mxf.c index 7d154ca9d3e..e51fc48a842 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.c +++ b/chromium/third_party/ffmpeg/libavformat/mxf.c @@ -86,6 +86,55 @@ const MXFCodecUL ff_mxf_codec_tag_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, 0 }, }; +const MXFCodecUL ff_mxf_color_primaries_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x03,0x01,0x00,0x00 }, 14, AVCOL_PRI_SMPTE170M }, /* SMPTE 170M */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x03,0x02,0x00,0x00 }, 14, AVCOL_PRI_BT470BG }, /* ITU-R BT.470 PAL */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x03,0x03,0x00,0x00 }, 14, AVCOL_PRI_BT709 }, /* ITU-R BT.709 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x03,0x04,0x00,0x00 }, 14, AVCOL_PRI_BT2020 }, /* ITU-R BT.2020 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x03,0x05,0x00,0x00 }, 14, AVCOL_PRI_SMPTE428 }, /* SMPTE-DC28 DCDM */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x03,0x06,0x00,0x00 }, 14, AVCOL_PRI_SMPTE432 }, /* P3D65 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x03,0x08,0x00,0x00 }, 14, AVCOL_PRI_SMPTE428 }, /* Cinema Mezzanine */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x03,0x0a,0x00,0x00 }, 14, AVCOL_PRI_SMPTE431 }, /* P3DCI */ + /* alternate mappings for encoding */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x03,0x01,0x00,0x00 }, 14, AVCOL_PRI_SMPTE240M }, /* = AVCOL_PRI_SMPTE170M */ + + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AVCOL_PRI_UNSPECIFIED }, +}; + +const MXFCodecUL ff_mxf_color_trc_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00 }, 14, AVCOL_TRC_GAMMA22 }, /* ITU-R BT.470 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00 }, 14, AVCOL_TRC_BT709 }, /* ITU-R BT.709 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00 }, 14, AVCOL_TRC_SMPTE240M }, /* SMPTE 240M */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x04,0x00,0x00 }, 14, AVCOL_TRC_BT709 }, /* SMPTE 274/296M (must appear after ITU-R BT.709) */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00 }, 14, AVCOL_TRC_BT1361_ECG }, /* ITU-R BT.1361 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00 }, 14, AVCOL_TRC_LINEAR }, /* Linear */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00 }, 14, AVCOL_TRC_SMPTE428 }, /* SMPTE-DC28 DCDM */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x01,0x08,0x00,0x00 }, 14, AVCOL_TRC_IEC61966_2_4 }, /* IEC 61966-2-4 xvYCC */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0E,0x04,0x01,0x01,0x01,0x01,0x09,0x00,0x00 }, 14, AVCOL_TRC_BT2020_10 }, /* ITU-R BT.2020 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x01,0x0A,0x00,0x00 }, 14, AVCOL_TRC_SMPTE2084 }, /* SMPTE ST 2084 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x01,0x0B,0x00,0x00 }, 14, AVCOL_TRC_ARIB_STD_B67 }, /* Hybrid Log-Gamma OETF */ + /* alternate mappings for encoding */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00 }, 14, AVCOL_TRC_GAMMA28 }, /* = AVCOL_TRC_GAMMA22 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00 }, 14, AVCOL_TRC_SMPTE170M }, /* = AVCOL_TRC_BT709 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0E,0x04,0x01,0x01,0x01,0x01,0x09,0x00,0x00 }, 14, AVCOL_TRC_BT2020_12 }, /* = AVCOL_TRC_BT2020_10 */ + + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AVCOL_TRC_UNSPECIFIED }, +}; + +/* aka Coding Equations */ +const MXFCodecUL ff_mxf_color_space_uls[] = { + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x02,0x01,0x00,0x00 }, 14, AVCOL_SPC_BT470BG }, /* ITU-R BT.601 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x02,0x02,0x00,0x00 }, 14, AVCOL_SPC_BT709 }, /* ITU-R BT.709 */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x02,0x03,0x00,0x00 }, 14, AVCOL_SPC_SMPTE240M }, /* SMPTE 240M */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x02,0x04,0x00,0x00 }, 14, AVCOL_SPC_YCGCO }, /* YCgCo */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x02,0x05,0x00,0x00 }, 14, AVCOL_SPC_RGB }, /* GBR */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x01,0x01,0x02,0x06,0x00,0x00 }, 14, AVCOL_SPC_BT2020_NCL }, /* ITU-R BT.2020 Non-Constant Luminance */ + /* alternate mappings for encoding */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x02,0x03,0x00,0x00 }, 14, AVCOL_SPC_SMPTE170M }, /* = AVCOL_SPC_SMPTE240M */ + + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AVCOL_SPC_UNSPECIFIED }, +}; + 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 f2fff2781e8..fc587f19f00 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.h +++ b/chromium/third_party/ffmpeg/libavformat/mxf.h @@ -91,6 +91,9 @@ 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[]; +extern const MXFCodecUL ff_mxf_color_primaries_uls[]; +extern const MXFCodecUL ff_mxf_color_trc_uls[]; +extern const MXFCodecUL ff_mxf_color_space_uls[]; int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt); int ff_mxf_get_content_package_rate(AVRational time_base); diff --git a/chromium/third_party/ffmpeg/libavformat/mxfdec.c b/chromium/third_party/ffmpeg/libavformat/mxfdec.c index fdd0dd2a88a..4b56984b777 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfdec.c @@ -207,6 +207,9 @@ typedef struct MXFDescriptor { uint8_t *extradata; int extradata_size; enum AVPixelFormat pix_fmt; + UID color_primaries_ul; + UID color_trc_ul; + UID color_space_ul; } MXFDescriptor; typedef struct MXFIndexTableSegment { @@ -362,8 +365,9 @@ static void mxf_free_metadataset(MXFMetadataSet **ctx, int freectx) default: break; } - if (freectx) - av_freep(ctx); + if (freectx) { + av_freep(ctx); + } } static int64_t klv_decode_ber_length(AVIOContext *pb) @@ -821,15 +825,17 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size return 0; } -static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) +static int mxf_add_metadata_set(MXFContext *mxf, MXFMetadataSet **metadata_set) { MXFMetadataSet **tmp; tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets)); - if (!tmp) + if (!tmp) { + mxf_free_metadataset(metadata_set, 1); return AVERROR(ENOMEM); + } mxf->metadata_sets = tmp; - mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set; + mxf->metadata_sets[mxf->metadata_sets_count] = *metadata_set; mxf->metadata_sets_count++; return 0; } @@ -847,6 +853,7 @@ static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, i static int mxf_read_strong_ref_array(AVIOContext *pb, UID **refs, int *count) { *count = avio_rb32(pb); + av_free(*refs); *refs = av_calloc(*count, sizeof(UID)); if (!*refs) { *count = 0; @@ -866,6 +873,7 @@ static inline int mxf_read_utf16_string(AVIOContext *pb, int size, char** str, i return AVERROR(EINVAL); buf_size = size + size / 2 + 1; + av_free(*str); *str = av_malloc(buf_size); if (!*str) return AVERROR(ENOMEM); @@ -899,10 +907,8 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz case 0x1901: if (mxf->packages_refs) av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n"); - av_free(mxf->packages_refs); return mxf_read_strong_ref_array(pb, &mxf->packages_refs, &mxf->packages_count); case 0x1902: - av_free(mxf->essence_container_data_refs); return mxf_read_strong_ref_array(pb, &mxf->essence_container_data_refs, &mxf->essence_container_data_count); } return 0; @@ -1198,9 +1204,18 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int descriptor->aspect_ratio.num = avio_rb32(pb); descriptor->aspect_ratio.den = avio_rb32(pb); break; + case 0x3210: + avio_read(pb, descriptor->color_trc_ul, 16); + break; case 0x3212: descriptor->field_dominance = avio_r8(pb); break; + case 0x3219: + avio_read(pb, descriptor->color_primaries_ul, 16); + break; + case 0x321A: + avio_read(pb, descriptor->color_space_ul, 16); + break; case 0x3301: descriptor->component_depth = avio_rb32(pb); break; @@ -2477,6 +2492,9 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } if (descriptor->aspect_ratio.num && descriptor->aspect_ratio.den) st->display_aspect_ratio = descriptor->aspect_ratio; + st->codecpar->color_primaries = mxf_get_codec_ul(ff_mxf_color_primaries_uls, &descriptor->color_primaries_ul)->id; + st->codecpar->color_trc = mxf_get_codec_ul(ff_mxf_color_trc_uls, &descriptor->color_trc_ul)->id; + st->codecpar->color_space = mxf_get_codec_ul(ff_mxf_color_space_uls, &descriptor->color_space_ul)->id; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul); /* Only overwrite existing codec ID if it is unset or A-law, which is the default according to SMPTE RP 224. */ @@ -2710,6 +2728,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { static int mxf_metadataset_init(MXFMetadataSet *ctx, enum MXFMetadataSetType type) { + ctx->type = type; switch (type){ case MultipleDescriptor: case Descriptor: @@ -2730,7 +2749,8 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return AVERROR(ENOMEM); - mxf_metadataset_init(ctx, type); + if (ctx_size) + mxf_metadataset_init(ctx, type); while (avio_tell(pb) + 4 < klv_end && !avio_feof(pb)) { int ret; int tag = avio_rb16(pb); @@ -2766,7 +2786,6 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF * it extending past the end of the KLV though (zzuf5.mxf). */ if (avio_tell(pb) > klv_end) { if (ctx_size) { - ctx->type = type; mxf_free_metadataset(&ctx, 1); } @@ -2777,8 +2796,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF } else if (avio_tell(pb) <= next) /* only seek forward, else this can loop for a long time */ avio_seek(pb, next, SEEK_SET); } - if (ctx_size) ctx->type = type; - return ctx_size ? mxf_add_metadata_set(mxf, ctx) : 0; + return ctx_size ? mxf_add_metadata_set(mxf, &ctx) : 0; } /** @@ -3081,10 +3099,8 @@ static int mxf_handle_missing_index_segment(MXFContext *mxf, AVStream *st) if (!(segment = av_mallocz(sizeof(*segment)))) return AVERROR(ENOMEM); - if ((ret = mxf_add_metadata_set(mxf, segment))) { - mxf_free_metadataset((MXFMetadataSet**)&segment, 1); + if ((ret = mxf_add_metadata_set(mxf, (MXFMetadataSet**)&segment))) return ret; - } /* Make sure we have nonzero unique index_sid, body_sid will be ok, because * using the same SID for index is forbidden in MXF. */ diff --git a/chromium/third_party/ffmpeg/libavformat/mxfenc.c b/chromium/third_party/ffmpeg/libavformat/mxfenc.c index 23147e9b84d..a38fa6b9836 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfenc.c @@ -52,7 +52,6 @@ #include "libavcodec/h264_ps.h" #include "libavcodec/golomb.h" #include "libavcodec/internal.h" -#include "audiointerleave.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" @@ -79,7 +78,7 @@ typedef struct MXFIndexEntry { } MXFIndexEntry; typedef struct MXFStreamContext { - AudioInterleaveContext aic; + int64_t pkt_cnt; ///< pkt counter for muxed packets UID track_essence_element_key; int index; ///< index in mxf_essence_container_uls table const UID *codec_ul; @@ -554,11 +553,10 @@ static void mxf_write_metadata_key(AVIOContext *pb, unsigned int value) avio_wb24(pb, value); } -static const MXFCodecUL *mxf_get_data_definition_ul(int type) +static const MXFCodecUL *mxf_get_codec_ul_by_id(const MXFCodecUL *uls, int id) { - const MXFCodecUL *uls = ff_mxf_data_definition_uls; while (uls->uid[0]) { - if (type == uls->id) + if (id == uls->id) break; uls++; } @@ -848,7 +846,7 @@ static void mxf_write_common_fields(AVFormatContext *s, AVStream *st) if (st == mxf->timecode_track) avio_write(pb, smpte_12m_timecode_track_data_ul, 16); else { - const MXFCodecUL *data_def_ul = mxf_get_data_definition_ul(st->codecpar->codec_type); + const MXFCodecUL *data_def_ul = mxf_get_codec_ul_by_id(ff_mxf_data_definition_uls, st->codecpar->codec_type); avio_write(pb, data_def_ul->uid, 16); } @@ -1050,34 +1048,6 @@ static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0 static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 }; -static int get_trc(UID ul, enum AVColorTransferCharacteristic trc) -{ - switch (trc){ - case AVCOL_TRC_GAMMA28 : - case AVCOL_TRC_GAMMA22 : - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00}), 16); - return 0; - case AVCOL_TRC_BT709 : - case AVCOL_TRC_SMPTE170M : - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00}), 16); - return 0; - case AVCOL_TRC_SMPTE240M : - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00}), 16); - return 0; - case AVCOL_TRC_BT1361_ECG: - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00}), 16); - return 0; - case AVCOL_TRC_LINEAR : - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00}), 16); - return 0; - case AVCOL_TRC_SMPTE428 : - memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00}), 16); - return 0; - default: - return -1; - } -} - static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key) { MXFStreamContext *sc = st->priv_data; @@ -1086,10 +1056,14 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID int stored_height = (st->codecpar->height+15)/16*16; int display_height; int f1, f2; - UID transfer_ul = {0}; + const MXFCodecUL *color_primaries_ul; + const MXFCodecUL *color_trc_ul; + const MXFCodecUL *color_space_ul; int64_t pos = mxf_write_generic_desc(s, st, key); - get_trc(transfer_ul, st->codecpar->color_trc); + color_primaries_ul = mxf_get_codec_ul_by_id(ff_mxf_color_primaries_uls, st->codecpar->color_primaries); + color_trc_ul = mxf_get_codec_ul_by_id(ff_mxf_color_trc_uls, st->codecpar->color_trc); + color_space_ul = mxf_get_codec_ul_by_id(ff_mxf_color_space_uls, st->codecpar->color_space); if (st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO) { if (st->codecpar->height == 1080) @@ -1236,10 +1210,19 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID avio_wb32(pb, sc->aspect_ratio.num); avio_wb32(pb, sc->aspect_ratio.den); - //Transfer characteristic - if (transfer_ul[0]) { + if (color_primaries_ul->uid[0]) { + mxf_write_local_tag(pb, 16, 0x3219); + avio_write(pb, color_primaries_ul->uid, 16); + }; + + if (color_trc_ul->uid[0]) { mxf_write_local_tag(pb, 16, 0x3210); - avio_write(pb, transfer_ul, 16); + avio_write(pb, color_trc_ul->uid, 16); + }; + + if (color_space_ul->uid[0]) { + mxf_write_local_tag(pb, 16, 0x321A); + avio_write(pb, color_space_ul->uid, 16); }; mxf_write_local_tag(pb, 16, 0x3201); @@ -2172,14 +2155,14 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, { MXFContext *mxf = s->priv_data; MXFStreamContext *sc = st->priv_data; - H264SequenceParameterSet *sps = NULL; + H264SPS seq, *const sps = &seq; GetBitContext gb; const uint8_t *buf = pkt->data; const uint8_t *buf_end = pkt->data + pkt->size; const uint8_t *nal_end; uint32_t state = -1; int extra_size = 512; // support AVC Intra files without SPS/PPS header - int i, frame_size, slice_type, intra_only = 0; + int i, frame_size, slice_type, has_sps = 0, intra_only = 0, ret; for (;;) { buf = avpriv_find_start_code(buf, buf_end, &state); @@ -2194,11 +2177,12 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, break; nal_end = ff_avc_find_startcode(buf, buf_end); - sps = ff_avc_decode_sps(buf, nal_end - buf); - if (!sps) { + ret = ff_avc_decode_sps(sps, buf, nal_end - buf); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "error parsing sps\n"); return 0; } + has_sps = 1; sc->aspect_ratio.num = st->codecpar->width * sps->sar.num; sc->aspect_ratio.den = st->codecpar->height * sps->sar.den; @@ -2244,7 +2228,7 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, if (mxf->header_written) return 1; - if (!sps) + if (!has_sps) sc->interlaced = st->codecpar->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0; sc->codec_ul = NULL; frame_size = pkt->size + extra_size; @@ -2261,7 +2245,7 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, if (sc->interlaced) sc->field_dominance = 1; // top field first is mandatory for AVC Intra break; - } else if (sps && mxf_h264_codec_uls[i].frame_size == 0 && + } else if (has_sps && mxf_h264_codec_uls[i].frame_size == 0 && mxf_h264_codec_uls[i].profile == sps->profile_idc && (mxf_h264_codec_uls[i].intra_only < 0 || mxf_h264_codec_uls[i].intra_only == intra_only)) { @@ -2272,8 +2256,6 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, } } - av_free(sps); - if (!sc->codec_ul) { av_log(s, AV_LOG_ERROR, "h264 profile not supported\n"); return 0; @@ -2538,6 +2520,7 @@ static int mxf_write_header(AVFormatContext *s) if (mxf->signal_standard >= 0) sc->signal_standard = mxf->signal_standard; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + char bsf_arg[32]; if (st->codecpar->sample_rate != 48000) { av_log(s, AV_LOG_ERROR, "only 48khz is implemented\n"); return -1; @@ -2580,6 +2563,10 @@ static int mxf_write_header(AVFormatContext *s) av_rescale_rnd(st->codecpar->sample_rate, mxf->time_base.num, mxf->time_base.den, AV_ROUND_UP) * av_get_bits_per_sample(st->codecpar->codec_id) / 8; } + snprintf(bsf_arg, sizeof(bsf_arg), "r=%d/%d", mxf->tc.rate.num, mxf->tc.rate.den); + ret = ff_stream_add_bitstream_filter(st, "pcm_rechunk", bsf_arg); + if (ret < 0) + return ret; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0); if (e && !strcmp(e->value, "vbi_vanc_smpte_436M")) { @@ -2646,9 +2633,6 @@ static int mxf_write_header(AVFormatContext *s) return AVERROR(ENOMEM); mxf->timecode_track->index = -1; - if (ff_audio_interleave_init(s, 0, av_inv_q(mxf->tc.rate)) < 0) - return -1; - return 0; } @@ -3010,8 +2994,6 @@ static void mxf_deinit(AVFormatContext *s) { MXFContext *mxf = s->priv_data; - ff_audio_interleave_close(s); - av_freep(&mxf->index_entries); av_freep(&mxf->body_partition_offset); if (mxf->timecode_track) { @@ -3086,8 +3068,14 @@ static int mxf_compare_timestamps(AVFormatContext *s, const AVPacket *next, static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) { - return ff_audio_rechunk_interleave(s, out, pkt, flush, - mxf_interleave_get_packet, mxf_compare_timestamps); + int ret; + if (pkt) { + MXFStreamContext *sc = s->streams[pkt->stream_index]->priv_data; + pkt->pts = pkt->dts = sc->pkt_cnt++; + if ((ret = ff_interleave_add_packet(s, pkt, mxf_compare_timestamps)) < 0) + return ret; + } + return mxf_interleave_get_packet(s, out, NULL, flush); } #define MXF_COMMON_OPTIONS \ diff --git a/chromium/third_party/ffmpeg/libavformat/nutenc.c b/chromium/third_party/ffmpeg/libavformat/nutenc.c index 1d486258154..6d3bf6c21e2 100644 --- a/chromium/third_party/ffmpeg/libavformat/nutenc.c +++ b/chromium/third_party/ffmpeg/libavformat/nutenc.c @@ -277,11 +277,37 @@ static void build_frame_code(AVFormatContext *s) nut->frame_code['N'].flags = FLAG_INVALID; } +/** + * Get the length in bytes which is needed to store val as v. + */ +static int get_v_length(uint64_t val) +{ + int i = 1; + + while (val >>= 7) + i++; + + return i; +} + +/** + * Put val using a variable number of bytes. + */ +static void put_v(AVIOContext *bc, uint64_t val) +{ + int i = get_v_length(val); + + while (--i > 0) + avio_w8(bc, 128 | (uint8_t)(val >> (7*i))); + + avio_w8(bc, val & 127); +} + static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc, uint64_t val) { val *= nut->time_base_count; val += time_base - nut->time_base; - ff_put_v(bc, val); + put_v(bc, val); } /** * Store a string as vb. @@ -290,37 +316,34 @@ static void put_str(AVIOContext *bc, const char *string) { size_t len = strlen(string); - ff_put_v(bc, len); + put_v(bc, len); avio_write(bc, string, len); } static void put_s(AVIOContext *bc, int64_t val) { - ff_put_v(bc, 2 * FFABS(val) - (val > 0)); + put_v(bc, 2 * FFABS(val) - (val > 0)); } -//FIXME remove calculate_checksum static void put_packet(NUTContext *nut, AVIOContext *bc, AVIOContext *dyn_bc, - int calculate_checksum, uint64_t startcode) + uint64_t startcode) { uint8_t *dyn_buf = NULL; - int dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf); - int forw_ptr = dyn_size + 4 * calculate_checksum; + int dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf); + int forw_ptr = dyn_size + 4; if (forw_ptr > 4096) ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); avio_wb64(bc, startcode); - ff_put_v(bc, forw_ptr); + put_v(bc, forw_ptr); if (forw_ptr > 4096) avio_wl32(bc, ffio_get_checksum(bc)); - if (calculate_checksum) - ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); + ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); avio_write(bc, dyn_buf, dyn_size); - if (calculate_checksum) - avio_wl32(bc, ffio_get_checksum(bc)); + avio_wl32(bc, ffio_get_checksum(bc)); - av_free(dyn_buf); + ffio_reset_dyn_buf(dyn_bc); } static void write_mainheader(NUTContext *nut, AVIOContext *bc) @@ -329,16 +352,16 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) tmp_head_idx; int64_t tmp_match; - ff_put_v(bc, nut->version); + put_v(bc, nut->version); if (nut->version > 3) - ff_put_v(bc, nut->minor_version = 1); - ff_put_v(bc, nut->avf->nb_streams); - ff_put_v(bc, nut->max_distance); - ff_put_v(bc, nut->time_base_count); + put_v(bc, nut->minor_version = 1); + put_v(bc, nut->avf->nb_streams); + put_v(bc, nut->max_distance); + put_v(bc, nut->time_base_count); for (i = 0; i < nut->time_base_count; i++) { - ff_put_v(bc, nut->time_base[i].num); - ff_put_v(bc, nut->time_base[i].den); + put_v(bc, nut->time_base[i].num); + put_v(bc, nut->time_base[i].den); } tmp_pts = 0; @@ -382,25 +405,25 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) if (j != tmp_mul - tmp_size) tmp_fields = 6; - ff_put_v(bc, tmp_flags); - ff_put_v(bc, tmp_fields); + put_v(bc, tmp_flags); + put_v(bc, tmp_fields); if (tmp_fields > 0) put_s(bc, tmp_pts); - if (tmp_fields > 1) ff_put_v(bc, tmp_mul); - if (tmp_fields > 2) ff_put_v(bc, tmp_stream); - if (tmp_fields > 3) ff_put_v(bc, tmp_size); - if (tmp_fields > 4) ff_put_v(bc, 0 /*tmp_res*/); - if (tmp_fields > 5) ff_put_v(bc, j); - if (tmp_fields > 6) ff_put_v(bc, tmp_match); - if (tmp_fields > 7) ff_put_v(bc, tmp_head_idx); + if (tmp_fields > 1) put_v(bc, tmp_mul); + if (tmp_fields > 2) put_v(bc, tmp_stream); + if (tmp_fields > 3) put_v(bc, tmp_size); + if (tmp_fields > 4) put_v(bc, 0 /*tmp_res*/); + if (tmp_fields > 5) put_v(bc, j); + if (tmp_fields > 6) put_v(bc, tmp_match); + if (tmp_fields > 7) put_v(bc, tmp_head_idx); } - ff_put_v(bc, nut->header_count - 1); + put_v(bc, nut->header_count - 1); for (i = 1; i < nut->header_count; i++) { - ff_put_v(bc, nut->header_len[i]); + put_v(bc, nut->header_len[i]); avio_write(bc, nut->header[i], nut->header_len[i]); } // flags had been effectively introduced in version 4 if (nut->version > 3) - ff_put_v(bc, nut->flags); + put_v(bc, nut->flags); } static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc, @@ -409,14 +432,14 @@ static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc, NUTContext *nut = avctx->priv_data; AVCodecParameters *par = st->codecpar; - ff_put_v(bc, i); + put_v(bc, i); switch (par->codec_type) { - case AVMEDIA_TYPE_VIDEO: ff_put_v(bc, 0); break; - case AVMEDIA_TYPE_AUDIO: ff_put_v(bc, 1); break; - case AVMEDIA_TYPE_SUBTITLE: ff_put_v(bc, 2); break; - default: ff_put_v(bc, 3); break; + case AVMEDIA_TYPE_VIDEO: put_v(bc, 0); break; + case AVMEDIA_TYPE_AUDIO: put_v(bc, 1); break; + case AVMEDIA_TYPE_SUBTITLE: put_v(bc, 2); break; + default: put_v(bc, 3); break; } - ff_put_v(bc, 4); + put_v(bc, 4); if (par->codec_tag) { avio_wl32(bc, par->codec_tag); @@ -425,34 +448,34 @@ static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc, return AVERROR(EINVAL); } - ff_put_v(bc, nut->stream[i].time_base - nut->time_base); - ff_put_v(bc, nut->stream[i].msb_pts_shift); - ff_put_v(bc, nut->stream[i].max_pts_distance); - ff_put_v(bc, par->video_delay); + put_v(bc, nut->stream[i].time_base - nut->time_base); + put_v(bc, nut->stream[i].msb_pts_shift); + put_v(bc, nut->stream[i].max_pts_distance); + put_v(bc, par->video_delay); avio_w8(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ - ff_put_v(bc, par->extradata_size); + put_v(bc, par->extradata_size); avio_write(bc, par->extradata, par->extradata_size); switch (par->codec_type) { case AVMEDIA_TYPE_AUDIO: - ff_put_v(bc, par->sample_rate); - ff_put_v(bc, 1); - ff_put_v(bc, par->channels); + put_v(bc, par->sample_rate); + put_v(bc, 1); + put_v(bc, par->channels); break; case AVMEDIA_TYPE_VIDEO: - ff_put_v(bc, par->width); - ff_put_v(bc, par->height); + put_v(bc, par->width); + put_v(bc, par->height); if (st->sample_aspect_ratio.num <= 0 || st->sample_aspect_ratio.den <= 0) { - ff_put_v(bc, 0); - ff_put_v(bc, 0); + put_v(bc, 0); + put_v(bc, 0); } else { - ff_put_v(bc, st->sample_aspect_ratio.num); - ff_put_v(bc, st->sample_aspect_ratio.den); + put_v(bc, st->sample_aspect_ratio.num); + put_v(bc, st->sample_aspect_ratio.den); } - ff_put_v(bc, 0); /* csp type -- unknown */ + put_v(bc, 0); /* csp type -- unknown */ break; default: break; @@ -483,12 +506,12 @@ static int write_globalinfo(NUTContext *nut, AVIOContext *bc) while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) count += add_info(dyn_bc, t->key, t->value); - ff_put_v(bc, 0); //stream_if_plus1 - ff_put_v(bc, 0); //chapter_id - ff_put_v(bc, 0); //timestamp_start - ff_put_v(bc, 0); //length + put_v(bc, 0); //stream_if_plus1 + put_v(bc, 0); //chapter_id + put_v(bc, 0); //timestamp_start + put_v(bc, 0); //length - ff_put_v(bc, count); + put_v(bc, count); dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf); avio_write(bc, dyn_buf, dyn_size); @@ -524,12 +547,12 @@ static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id) { dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf); if (count) { - ff_put_v(bc, stream_id + 1); //stream_id_plus1 - ff_put_v(bc, 0); //chapter_id - ff_put_v(bc, 0); //timestamp_start - ff_put_v(bc, 0); //length + put_v(bc, stream_id + 1); //stream_id_plus1 + put_v(bc, 0); //chapter_id + put_v(bc, 0); //timestamp_start + put_v(bc, 0); //length - ff_put_v(bc, count); + put_v(bc, count); avio_write(bc, dyn_buf, dyn_size); } @@ -550,15 +573,15 @@ static int write_chapter(NUTContext *nut, AVIOContext *bc, int id) if (ret < 0) return ret; - ff_put_v(bc, 0); // stream_id_plus1 + put_v(bc, 0); // stream_id_plus1 put_s(bc, id + 1); // chapter_id put_tt(nut, nut->chapter[id].time_base, bc, ch->start); // chapter_start - ff_put_v(bc, ch->end - ch->start); // chapter_len + put_v(bc, ch->end - ch->start); // chapter_len while ((t = av_dict_get(ch->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) count += add_info(dyn_bc, t->key, t->value); - ff_put_v(bc, count); + put_v(bc, count); dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf); avio_write(bc, dyn_buf, dyn_size); @@ -575,11 +598,11 @@ static int write_index(NUTContext *nut, AVIOContext *bc) { put_tt(nut, nut->max_pts_tb, bc, nut->max_pts); - ff_put_v(bc, nut->sp_count); + put_v(bc, nut->sp_count); for (i=0; i<nut->sp_count; i++) { av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, (void**)next_node); - ff_put_v(bc, (next_node[1]->pos >> 4) - (dummy.pos>>4)); + put_v(bc, (next_node[1]->pos >> 4) - (dummy.pos>>4)); dummy.pos = next_node[1]->pos; } @@ -600,12 +623,12 @@ static int write_index(NUTContext *nut, AVIOContext *bc) { for (; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++) n++; - ff_put_v(bc, 1 + 2*flag + 4*n); + put_v(bc, 1 + 2 * flag + 4 * n); for (k= j - n; k<=j && k<nut->sp_count; k++) { if (nus->keyframe_pts[k] == AV_NOPTS_VALUE) continue; av_assert0(nus->keyframe_pts[k] > last_pts); - ff_put_v(bc, nus->keyframe_pts[k] - last_pts); + put_v(bc, nus->keyframe_pts[k] - last_pts); last_pts = nus->keyframe_pts[k]; } } @@ -630,55 +653,44 @@ static int write_headers(AVFormatContext *avctx, AVIOContext *bc) if (ret < 0) return ret; write_mainheader(nut, dyn_bc); - put_packet(nut, bc, dyn_bc, 1, MAIN_STARTCODE); + put_packet(nut, bc, dyn_bc, MAIN_STARTCODE); for (i = 0; i < nut->avf->nb_streams; i++) { - ret = avio_open_dyn_buf(&dyn_bc); - if (ret < 0) - return ret; ret = write_streamheader(avctx, dyn_bc, nut->avf->streams[i], i); if (ret < 0) { - ffio_free_dyn_buf(&dyn_bc); - return ret; + goto fail; } - put_packet(nut, bc, dyn_bc, 1, STREAM_STARTCODE); + put_packet(nut, bc, dyn_bc, STREAM_STARTCODE); } - ret = avio_open_dyn_buf(&dyn_bc); - if (ret < 0) - return ret; write_globalinfo(nut, dyn_bc); - put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); + put_packet(nut, bc, dyn_bc, INFO_STARTCODE); for (i = 0; i < nut->avf->nb_streams; i++) { - ret = avio_open_dyn_buf(&dyn_bc); - if (ret < 0) - return ret; ret = write_streaminfo(nut, dyn_bc, i); if (ret > 0) - put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); - else { - ffio_free_dyn_buf(&dyn_bc); - if (ret < 0) - return ret; + put_packet(nut, bc, dyn_bc, INFO_STARTCODE); + else if (ret < 0) { + goto fail; } } for (i = 0; i < nut->avf->nb_chapters; i++) { - ret = avio_open_dyn_buf(&dyn_bc); - if (ret < 0) - return ret; ret = write_chapter(nut, dyn_bc, i); if (ret < 0) { - ffio_free_dyn_buf(&dyn_bc); - return ret; + goto fail; } - put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); + put_packet(nut, bc, dyn_bc, INFO_STARTCODE); } nut->last_syncpoint_pos = INT_MIN; nut->header_count++; - return 0; + + ret = 0; +fail: + ffio_free_dyn_buf(&dyn_bc); + + return ret; } static int nut_write_header(AVFormatContext *s) @@ -876,7 +888,7 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int } put_s(dyn_bc, -2); put_str(dyn_bc, "bin"); - ff_put_v(dyn_bc, pkt->side_data[i].size); + put_v(dyn_bc, pkt->side_data[i].size); avio_write(dyn_bc, data, pkt->side_data[i].size); sm_data_count++; break; @@ -891,7 +903,7 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int put_str(dyn_bc, "ChannelLayout"); put_s(dyn_bc, -2); put_str(dyn_bc, "u64"); - ff_put_v(bc, 8); + put_v(dyn_bc, 8); avio_write(dyn_bc, data, 8); data+=8; sm_data_count++; } @@ -930,7 +942,7 @@ static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int } fail: - ff_put_v(bc, sm_data_count); + put_v(bc, sm_data_count); dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf); avio_write(bc, dyn_buf, dyn_size); av_freep(&dyn_buf); @@ -1016,13 +1028,14 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) if (ret < 0) goto fail; put_tt(nut, nus->time_base, dyn_bc, pkt->dts); - ff_put_v(dyn_bc, sp_pos != INT64_MAX ? (nut->last_syncpoint_pos - sp_pos) >> 4 : 0); + put_v(dyn_bc, sp_pos != INT64_MAX ? (nut->last_syncpoint_pos - sp_pos) >> 4 : 0); if (nut->flags & NUT_BROADCAST) { put_tt(nut, nus->time_base, dyn_bc, av_rescale_q(av_gettime(), AV_TIME_BASE_Q, *nus->time_base)); } - put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); + put_packet(nut, bc, dyn_bc, SYNCPOINT_STARTCODE); + ffio_free_dyn_buf(&dyn_bc); if (nut->write_index) { if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0) @@ -1073,18 +1086,18 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) continue; if (flags & FLAG_STREAM_ID) - length += ff_get_v_length(pkt->stream_index); + length += get_v_length(pkt->stream_index); if (data_size % fc->size_mul != fc->size_lsb) continue; if (flags & FLAG_SIZE_MSB) - length += ff_get_v_length(data_size / fc->size_mul); + length += get_v_length(data_size / fc->size_mul); if (flags & FLAG_CHECKSUM) length += 4; if (flags & FLAG_CODED_PTS) - length += ff_get_v_length(coded_pts); + length += get_v_length(coded_pts); if ( (flags & FLAG_CODED) && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx] + 1) { @@ -1116,13 +1129,13 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); avio_w8(bc, frame_code); if (flags & FLAG_CODED) { - ff_put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED)); + put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED)); flags = needed_flags; } - if (flags & FLAG_STREAM_ID) ff_put_v(bc, pkt->stream_index); - if (flags & FLAG_CODED_PTS) ff_put_v(bc, coded_pts); - if (flags & FLAG_SIZE_MSB ) ff_put_v(bc, data_size / fc->size_mul); - if (flags & FLAG_HEADER_IDX) ff_put_v(bc, header_idx = best_header_idx); + if (flags & FLAG_STREAM_ID) put_v(bc, pkt->stream_index); + if (flags & FLAG_CODED_PTS) put_v(bc, coded_pts); + if (flags & FLAG_SIZE_MSB ) put_v(bc, data_size / fc->size_mul); + if (flags & FLAG_HEADER_IDX) put_v(bc, header_idx = best_header_idx); if (flags & FLAG_CHECKSUM) avio_wl32(bc, ffio_get_checksum(bc)); else ffio_get_checksum(bc); @@ -1175,7 +1188,8 @@ static int nut_write_trailer(AVFormatContext *s) if (ret >= 0) { av_assert1(nut->write_index); // sp_count should be 0 if no index is going to be written write_index(nut, dyn_bc); - put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE); + put_packet(nut, bc, dyn_bc, INDEX_STARTCODE); + ffio_free_dyn_buf(&dyn_bc); } return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/oggdec.c b/chromium/third_party/ffmpeg/libavformat/oggdec.c index 15e86940767..52cd410d0f9 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggdec.c +++ b/chromium/third_party/ffmpeg/libavformat/oggdec.c @@ -31,6 +31,7 @@ #include <stdio.h> #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "avio_internal.h" #include "oggdec.h" #include "avformat.h" #include "internal.h" @@ -42,7 +43,6 @@ static const struct ogg_codec * const ogg_codecs[] = { &ff_skeleton_codec, #if 0 // These codecs are not supported by Chromium. - &ff_daala_codec, &ff_dirac_codec, &ff_speex_codec, #endif @@ -104,7 +104,13 @@ static int ogg_save(AVFormatContext *s) for (i = 0; i < ogg->nstreams; i++) { struct ogg_stream *os = ogg->streams + i; +// Chromium: always allocate |buf| using av_realloc(). +// av_mallocz() will use posix_memalign(), preventing reallocation. +#if 0 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); +#else + os->buf = av_realloc(NULL, os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); +#endif if (os->buf) memcpy(os->buf, ost->streams[i].buf, os->bufpos); else @@ -183,6 +189,7 @@ static int ogg_reset(AVFormatContext *s) if (start_pos <= s->internal->data_offset) { os->lastpts = 0; } + os->start_trimming = 0; os->end_trimming = 0; av_freep(&os->new_metadata); os->new_metadata_size = 0; @@ -211,60 +218,43 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size) * situation where a new audio stream spawn (identified with a new serial) and * must replace the previous one (track switch). */ -static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs) +static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic, int page_size, + int probing) { struct ogg *ogg = s->priv_data; struct ogg_stream *os; const struct ogg_codec *codec; int i = 0; - if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { - uint8_t magic[8]; - int64_t pos = avio_tell(s->pb); - avio_skip(s->pb, nsegs); - if (avio_read(s->pb, magic, sizeof(magic)) != sizeof(magic)) - return AVERROR_INVALIDDATA; - avio_seek(s->pb, pos, SEEK_SET); - codec = ogg_find_codec(magic, sizeof(magic)); - if (!codec) { - av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); - return AVERROR_INVALIDDATA; - } - for (i = 0; i < ogg->nstreams; i++) { - if (ogg->streams[i].codec == codec) - break; - } - if (i >= ogg->nstreams) - return ogg_new_stream(s, serial); - } else if (ogg->nstreams != 1) { + if (ogg->nstreams != 1) { avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg"); return AVERROR_PATCHWELCOME; } - os = &ogg->streams[i]; - - os->serial = serial; - return i; - -#if 0 - buf = os->buf; - bufsize = os->bufsize; - codec = os->codec; + /* Check for codecs */ + codec = ogg_find_codec(magic, page_size); + if (!codec && !probing) { + av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); + return AVERROR_INVALIDDATA; + } - if (!ogg->state || ogg->state->streams[i].private != os->private) - av_freep(&ogg->streams[i].private); + os = &ogg->streams[0]; + if (os->codec != codec) + return AVERROR(EINVAL); - /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We - * also re-use the ogg_stream allocated buffer */ - memset(os, 0, sizeof(*os)); os->serial = serial; - os->bufsize = bufsize; - os->buf = buf; - os->header = -1; os->codec = codec; + os->serial = serial; + os->lastpts = 0; + os->lastdts = 0; + os->start_trimming = 0; + os->end_trimming = 0; + + /* Chained files have extradata as a new packet */ + if (codec == &ff_opus_codec) + os->header = -1; return i; -#endif } static int ogg_new_stream(AVFormatContext *s, uint32_t serial) @@ -290,7 +280,13 @@ static int ogg_new_stream(AVFormatContext *s, uint32_t serial) memset(os, 0, sizeof(*os)); os->serial = serial; os->bufsize = DECODER_BUFFER_SIZE; +// Chromium: always allocate |buf| using av_realloc(). +// av_malloc() will use posix_memalign(), preventing reallocation. +#if 0 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); +#else + os->buf = av_realloc(NULL, os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); +#endif os->header = -1; os->start_granule = OGG_NOGRANULE_VALUE; if (!os->buf) @@ -309,27 +305,6 @@ static int ogg_new_stream(AVFormatContext *s, uint32_t serial) return idx; } -static int ogg_new_buf(struct ogg *ogg, int idx) -{ - struct ogg_stream *os = ogg->streams + idx; - uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); - int size = os->bufpos - os->pstart; - - if (!nb) - return AVERROR(ENOMEM); - - if (os->buf) { - memcpy(nb, os->buf + os->pstart, size); - av_free(os->buf); - } - - os->buf = nb; - os->bufpos = size; - os->pstart = 0; - - return 0; -} - static int data_packets_seen(const struct ogg *ogg) { int i; @@ -340,7 +315,21 @@ static int data_packets_seen(const struct ogg *ogg) return 0; } -static int ogg_read_page(AVFormatContext *s, int *sid) +static int buf_realloc(struct ogg_stream *os, int size) +{ + /* Even if invalid guarantee there's enough memory to read the page */ + if (os->bufsize - os->bufpos < size) { + uint8_t *nb = av_realloc(os->buf, 2*os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE); + if (!nb) + return AVERROR(ENOMEM); + os->buf = nb; + os->bufsize *= 2; + } + + return 0; +} + +static int ogg_read_page(AVFormatContext *s, int *sid, int probing) { AVIOContext *bc = s->pb; struct ogg *ogg = s->priv_data; @@ -349,8 +338,13 @@ static int ogg_read_page(AVFormatContext *s, int *sid) int flags, nsegs; uint64_t gp; uint32_t serial; - int size, idx; + uint32_t crc, crc_tmp; + int size = 0, idx; + int64_t version, page_pos; + int64_t start_pos; uint8_t sync[4]; + uint8_t segments[255]; + uint8_t *readout_buf; int sp = 0; ret = avio_read(bc, sync, 4); @@ -384,56 +378,109 @@ static int ogg_read_page(AVFormatContext *s, int *sid) return AVERROR_INVALIDDATA; } - if (avio_r8(bc) != 0) { /* version */ - av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n"); - return AVERROR_INVALIDDATA; - } + /* 0x4fa9b05f = av_crc(AV_CRC_32_IEEE, 0x0, "OggS", 4) */ + ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f); + + /* To rewind if checksum is bad/check magic on switches - this is the max packet size */ + ffio_ensure_seekback(bc, MAX_PAGE_SIZE); + start_pos = avio_tell(bc); + + version = avio_r8(bc); + flags = avio_r8(bc); + gp = avio_rl64(bc); + serial = avio_rl32(bc); + avio_skip(bc, 4); /* seq */ - flags = avio_r8(bc); - gp = avio_rl64(bc); - serial = avio_rl32(bc); - avio_skip(bc, 8); /* seq, crc */ - nsegs = avio_r8(bc); + crc_tmp = ffio_get_checksum(bc); + crc = avio_rb32(bc); + crc_tmp = ff_crc04C11DB7_update(crc_tmp, (uint8_t[4]){0}, 4); + ffio_init_checksum(bc, ff_crc04C11DB7_update, crc_tmp); - if (avio_feof(bc)) - return AVERROR_EOF; + nsegs = avio_r8(bc); + page_pos = avio_tell(bc) - 27; + + ret = avio_read(bc, segments, nsegs); + if (ret < nsegs) + return ret < 0 ? ret : AVERROR_EOF; + + for (i = 0; i < nsegs; i++) + size += segments[i]; idx = ogg_find_stream(ogg, serial); + if (idx >= 0) { + os = ogg->streams + idx; + + ret = buf_realloc(os, size); + if (ret < 0) + return ret; + + readout_buf = os->buf + os->bufpos; + } else { + readout_buf = av_malloc(size); + } + + ret = avio_read(bc, readout_buf, size); + if (ret < size) { + if (idx < 0) + av_free(readout_buf); + return ret < 0 ? ret : AVERROR_EOF; + } + + if (crc ^ ffio_get_checksum(bc)) { + av_log(s, AV_LOG_ERROR, "CRC mismatch!\n"); + if (idx < 0) + av_free(readout_buf); + avio_seek(bc, start_pos, SEEK_SET); + *sid = -1; + return 0; + } + + /* Since we're almost sure its a valid packet, checking the version after + * the checksum lets the demuxer be more tolerant */ + if (version) { + av_log(s, AV_LOG_ERROR, "Invalid Ogg vers!\n"); + if (idx < 0) + av_free(readout_buf); + avio_seek(bc, start_pos, SEEK_SET); + *sid = -1; + return 0; + } + + /* CRC is correct so we can be 99% sure there's an actual change here */ if (idx < 0) { if (data_packets_seen(ogg)) - idx = ogg_replace_stream(s, serial, nsegs); + idx = ogg_replace_stream(s, serial, readout_buf, size, probing); else idx = ogg_new_stream(s, serial); if (idx < 0) { av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n"); + av_free(readout_buf); return idx; } - } - os = ogg->streams + idx; - ogg->page_pos = - os->page_pos = avio_tell(bc) - 27; + os = ogg->streams + idx; - if (os->psize > 0) { - ret = ogg_new_buf(ogg, idx); - if (ret < 0) + ret = buf_realloc(os, size); + if (ret < 0) { + av_free(readout_buf); return ret; - } - - ret = avio_read(bc, os->segments, nsegs); - if (ret < nsegs) - return ret < 0 ? ret : AVERROR_EOF; - - os->nsegs = nsegs; - os->segp = 0; + } - size = 0; - for (i = 0; i < nsegs; i++) - size += os->segments[i]; + memcpy(os->buf + os->bufpos, readout_buf, size); + av_free(readout_buf); + } - if (!(flags & OGG_FLAG_BOS)) - os->got_data = 1; + ogg->page_pos = page_pos; + os->page_pos = page_pos; + os->nsegs = nsegs; + os->segp = 0; + os->got_data = !(flags & OGG_FLAG_BOS); + os->bufpos += size; + os->granule = gp; + os->flags = flags; + memcpy(os->segments, segments, nsegs); + memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (flags & OGG_FLAG_CONT || os->incomplete) { if (!os->psize) { @@ -453,26 +500,8 @@ static int ogg_read_page(AVFormatContext *s, int *sid) os->sync_pos = os->page_pos; } - if (os->bufsize - os->bufpos < 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); - av_free(os->buf); - os->buf = nb; - } - - ret = avio_read(bc, os->buf + os->bufpos, size); - if (ret < size) - return ret < 0 ? ret : AVERROR_EOF; - - os->bufpos += size; - os->granule = gp; - os->flags = flags; - - memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE); - if (sid) - *sid = idx; + /* This function is always called with sid != NULL */ + *sid = idx; return 0; } @@ -501,7 +530,7 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, idx = ogg->curidx; while (idx < 0) { - ret = ogg_read_page(s, &idx); + ret = ogg_read_page(s, &idx, 0); if (ret < 0) return ret; } @@ -652,8 +681,8 @@ static int ogg_get_length(AVFormatContext *s) avio_seek(s->pb, end, SEEK_SET); ogg->page_pos = -1; - while (!ogg_read_page(s, &i)) { - if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && + while (!ogg_read_page(s, &i, 1)) { + if (i >= 0 && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && ogg->streams[i].codec) { s->streams[i]->duration = ogg_gptopts(s, i, ogg->streams[i].granule, NULL); @@ -856,25 +885,25 @@ retry: pkt->duration = os->pduration; pkt->pos = fpos; - if (os->end_trimming) { + if (os->start_trimming || os->end_trimming) { uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); if(!side_data) return AVERROR(ENOMEM); + AV_WL32(side_data + 0, os->start_trimming); AV_WL32(side_data + 4, os->end_trimming); + os->start_trimming = 0; os->end_trimming = 0; } if (os->new_metadata) { - uint8_t *side_data = av_packet_new_side_data(pkt, - AV_PKT_DATA_METADATA_UPDATE, - os->new_metadata_size); - if(!side_data) - return AVERROR(ENOMEM); + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_METADATA_UPDATE, + os->new_metadata, os->new_metadata_size); + if (ret < 0) + return ret; - memcpy(side_data, os->new_metadata, os->new_metadata_size); - av_freep(&os->new_metadata); + os->new_metadata = NULL; os->new_metadata_size = 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/oggdec.h b/chromium/third_party/ffmpeg/libavformat/oggdec.h index 4a2b6ddee8f..629a1d62628 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggdec.h +++ b/chromium/third_party/ffmpeg/libavformat/oggdec.h @@ -84,6 +84,7 @@ struct ogg_stream { int got_start; int got_data; ///< 1 if the stream got some data (non-initial packets), 0 otherwise int nb_header; ///< set to the number of parsed headers + int start_trimming; ///< set the number of packets to drop from the start int end_trimming; ///< set the number of packets to drop from the end uint8_t *new_metadata; unsigned int new_metadata_size; @@ -114,7 +115,6 @@ struct ogg { #define OGG_NOGRANULE_VALUE (-1ull) extern const struct ogg_codec ff_celt_codec; -extern const struct ogg_codec ff_daala_codec; extern const struct ogg_codec ff_dirac_codec; extern const struct ogg_codec ff_flac_codec; extern const struct ogg_codec ff_ogm_audio_codec; diff --git a/chromium/third_party/ffmpeg/libavformat/oggenc.c b/chromium/third_party/ffmpeg/libavformat/oggenc.c index fbd14fedf9b..f5032759a64 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggenc.c +++ b/chromium/third_party/ffmpeg/libavformat/oggenc.c @@ -99,50 +99,32 @@ static const AVClass flavor ## _muxer_class = {\ .version = LIBAVUTIL_VERSION_INT,\ }; -static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset) -{ - int64_t pos = avio_tell(pb); - uint32_t checksum = ffio_get_checksum(pb); - avio_seek(pb, crc_offset, SEEK_SET); - avio_wb32(pb, checksum); - avio_seek(pb, pos, SEEK_SET); -} - -static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) +static void ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) { OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; - AVIOContext *pb; - int64_t crc_offset; - int ret, size; - uint8_t *buf; - - ret = avio_open_dyn_buf(&pb); - if (ret < 0) - return ret; - ffio_init_checksum(pb, ff_crc04C11DB7_update, 0); - ffio_wfourcc(pb, "OggS"); - avio_w8(pb, 0); - avio_w8(pb, page->flags | extra_flags); - avio_wl64(pb, page->granule); - avio_wl32(pb, oggstream->serial_num); - avio_wl32(pb, oggstream->page_counter++); - crc_offset = avio_tell(pb); - avio_wl32(pb, 0); // crc - avio_w8(pb, page->segments_count); - avio_write(pb, page->segments, page->segments_count); - avio_write(pb, page->data, page->size); - - ogg_update_checksum(s, pb, crc_offset); - - size = avio_close_dyn_buf(pb, &buf); - if (size < 0) - return size; - - avio_write(s->pb, buf, size); + uint8_t buf[4 + 1 + 1 + 8 + 4 + 4 + 4 + 1 + 255], *ptr = buf, *crc_pos; + const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE); + uint32_t crc; + + bytestream_put_le32(&ptr, MKTAG('O', 'g', 'g', 'S')); + bytestream_put_byte(&ptr, 0); + bytestream_put_byte(&ptr, page->flags | extra_flags); + bytestream_put_le64(&ptr, page->granule); + bytestream_put_le32(&ptr, oggstream->serial_num); + bytestream_put_le32(&ptr, oggstream->page_counter++); + crc_pos = ptr; + bytestream_put_le32(&ptr, 0); + bytestream_put_byte(&ptr, page->segments_count); + bytestream_put_buffer(&ptr, page->segments, page->segments_count); + + crc = av_crc(crc_table, 0, buf, ptr - buf); + crc = av_crc(crc_table, crc, page->data, page->size); + bytestream_put_be32(&crc_pos, crc); + + avio_write(s->pb, buf, ptr - buf); + avio_write(s->pb, page->data, page->size); avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); - av_free(buf); oggstream->page_count--; - return 0; } static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule) @@ -294,8 +276,9 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, AVChapter **chapters, unsigned int nb_chapters) { const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; + AVIOContext pb; int64_t size; - uint8_t *p, *p0; + uint8_t *p; ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); @@ -305,15 +288,14 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, p = av_mallocz(size); if (!p) return NULL; - p0 = p; - p += offset; - ff_vorbiscomment_write(&p, m, vendor, chapters, nb_chapters); + ffio_init_context(&pb, p + offset, size - offset, 1, NULL, NULL, NULL, NULL); + ff_vorbiscomment_write(&pb, *m, vendor, chapters, nb_chapters); if (framing_bit) - bytestream_put_byte(&p, 1); + avio_w8(&pb, 1); *header_len = size; - return p0; + return p; } static int ogg_build_flac_headers(AVCodecParameters *par, diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsedaala.c b/chromium/third_party/ffmpeg/libavformat/oggparsedaala.c deleted file mode 100644 index e944470aca3..00000000000 --- a/chromium/third_party/ffmpeg/libavformat/oggparsedaala.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Ogg Daala parser - * Copyright (C) 2015 Rostislav Pehlivanov <atomnuker gmail com> - * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara 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 - */ - -#include <stdlib.h> -#include "libavcodec/bytestream.h" -#include "avformat.h" -#include "internal.h" -#include "oggdec.h" - -struct DaalaPixFmtMap { - enum AVPixelFormat ffmpeg_fmt; - int depth; - int planes; - int xdec[4]; - int ydec[4]; -}; - -/* Currently supported formats only */ -static const struct DaalaPixFmtMap list_fmts[] = { - { AV_PIX_FMT_YUV420P, 8, 3, {0, 1, 1, 0}, {0, 1, 1, 0} }, - { AV_PIX_FMT_YUV444P, 8, 3, {0, 0, 0, 0}, {0, 0, 0, 0} } -}; - -typedef struct DaalaInfoHeader { - int init_d; - int fpr; - int gpshift; - int gpmask; - int version_maj; - int version_min; - int version_sub; - int frame_duration; - int keyframe_granule_shift; - struct DaalaPixFmtMap format; -} DaalaInfoHeader; - -static inline int daala_match_pix_fmt(struct DaalaPixFmtMap *fmt) -{ - int i, j; - for (i = 0; i < FF_ARRAY_ELEMS(list_fmts); i++) { - int match = 0; - if (fmt->depth != list_fmts[i].depth) - continue; - if (fmt->planes != list_fmts[i].planes) - continue; - for (j = 0; j < fmt->planes; j++) { - if (fmt->xdec[j] != list_fmts[i].xdec[j]) - continue; - if (fmt->ydec[j] != list_fmts[i].ydec[j]) - continue; - match++; - } - if (match == fmt->planes) - return list_fmts[i].ffmpeg_fmt; - } - return -1; -} - -static int daala_header(AVFormatContext *s, int idx) -{ - int i, err; - uint8_t *cdp; - GetByteContext gb; - AVRational timebase; - struct ogg *ogg = s->priv_data; - struct ogg_stream *os = ogg->streams + idx; - AVStream *st = s->streams[idx]; - int cds = st->codecpar->extradata_size + os->psize + 2; - DaalaInfoHeader *hdr = os->private; - - if (!(os->buf[os->pstart] & 0x80)) - return 0; - - if (!hdr) { - hdr = av_mallocz(sizeof(*hdr)); - if (!hdr) - return AVERROR(ENOMEM); - os->private = hdr; - } - - switch (os->buf[os->pstart]) { - case 0x80: - bytestream2_init(&gb, os->buf + os->pstart, os->psize); - bytestream2_skip(&gb, ff_daala_codec.magicsize); - - hdr->version_maj = bytestream2_get_byte(&gb); - hdr->version_min = bytestream2_get_byte(&gb); - hdr->version_sub = bytestream2_get_byte(&gb); - - st->codecpar->width = bytestream2_get_ne32(&gb); - st->codecpar->height = bytestream2_get_ne32(&gb); - - st->sample_aspect_ratio.num = bytestream2_get_ne32(&gb); - st->sample_aspect_ratio.den = bytestream2_get_ne32(&gb); - - timebase.num = bytestream2_get_ne32(&gb); - timebase.den = bytestream2_get_ne32(&gb); - if (timebase.num < 0 && timebase.den < 0) { - av_log(s, AV_LOG_WARNING, "Invalid timebase, assuming 30 FPS\n"); - timebase.num = 1; - timebase.den = 30; - } - avpriv_set_pts_info(st, 64, timebase.den, timebase.num); - - hdr->frame_duration = bytestream2_get_ne32(&gb); - hdr->gpshift = bytestream2_get_byte(&gb); - if (hdr->gpshift >= 32) { - av_log(s, AV_LOG_ERROR, "Too large gpshift %d (>= 32).\n", - hdr->gpshift); - hdr->gpshift = 0; - return AVERROR_INVALIDDATA; - } - hdr->gpmask = (1U << hdr->gpshift) - 1; - - hdr->format.depth = 8 + 2*(bytestream2_get_byte(&gb)-1); - - hdr->fpr = bytestream2_get_byte(&gb); - - hdr->format.planes = bytestream2_get_byte(&gb); - if (hdr->format.planes > 4) { - av_log(s, AV_LOG_ERROR, - "Invalid number of planes %d in daala pixel format map.\n", - hdr->format.planes); - return AVERROR_INVALIDDATA; - } - for (i = 0; i < hdr->format.planes; i++) { - hdr->format.xdec[i] = bytestream2_get_byte(&gb); - hdr->format.ydec[i] = bytestream2_get_byte(&gb); - } - - if ((st->codecpar->format = daala_match_pix_fmt(&hdr->format)) < 0) - av_log(s, AV_LOG_ERROR, "Unsupported pixel format - %i %i\n", - hdr->format.depth, hdr->format.planes); - - st->codecpar->codec_id = AV_CODEC_ID_DAALA; - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->need_parsing = AVSTREAM_PARSE_HEADERS; - - hdr->init_d = 1; - break; - case 0x81: - if (!hdr->init_d) - return AVERROR_INVALIDDATA; - ff_vorbis_stream_comment(s, st, - os->buf + os->pstart + ff_daala_codec.magicsize, - os->psize - ff_daala_codec.magicsize); - break; - case 0x82: - if (!hdr->init_d) - return AVERROR_INVALIDDATA; - break; - default: - av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]); - return AVERROR_INVALIDDATA; - break; - } - - if ((err = av_reallocp(&st->codecpar->extradata, - cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { - st->codecpar->extradata_size = 0; - return err; - } - - memset(st->codecpar->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE); - cdp = st->codecpar->extradata + st->codecpar->extradata_size; - *cdp++ = os->psize >> 8; - *cdp++ = os->psize & 0xff; - memcpy(cdp, os->buf + os->pstart, os->psize); - st->codecpar->extradata_size = cds; - - return 1; -} - -static uint64_t daala_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, - int64_t *dts) -{ - uint64_t iframe, pframe; - struct ogg *ogg = ctx->priv_data; - struct ogg_stream *os = ogg->streams + idx; - DaalaInfoHeader *hdr = os->private; - - if (!hdr) - return AV_NOPTS_VALUE; - - iframe = gp >> hdr->gpshift; - pframe = gp & hdr->gpmask; - - if (!pframe) - os->pflags |= AV_PKT_FLAG_KEY; - - if (dts) - *dts = iframe + pframe; - - return iframe + pframe; -} - -static int daala_packet(AVFormatContext *s, int idx) -{ - int seg, duration = 1; - struct ogg *ogg = s->priv_data; - struct ogg_stream *os = ogg->streams + idx; - int64_t pts; - - /* - * 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 set the first timestamp - */ - - if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { - for (seg = os->segp; seg < os->nsegs; seg++) - if (os->segments[seg] < 255) - duration++; - - pts = daala_gptopts(s, idx, os->granule, NULL); - if (pts != AV_NOPTS_VALUE) - pts -= duration; - os->lastpts = os->lastdts = pts; - if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { - s->streams[idx]->start_time = os->lastpts; - if (s->streams[idx]->duration != AV_NOPTS_VALUE) - s->streams[idx]->duration -= s->streams[idx]->start_time; - } - } - - /* parse packet duration */ - if (os->psize > 0) - os->pduration = 1; - - return 0; -} - -const struct ogg_codec ff_daala_codec = { - .name = "Daala", - .magic = "\200daala", - .magicsize = 6, - .header = daala_header, - .packet = daala_packet, - .gptopts = daala_gptopts, - .granule_is_start = 1, - .nb_header = 3, -}; diff --git a/chromium/third_party/ffmpeg/libavformat/oggparseopus.c b/chromium/third_party/ffmpeg/libavformat/oggparseopus.c index 56b53e74e8d..36d691e9aaf 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparseopus.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparseopus.c @@ -59,6 +59,7 @@ static int opus_header(AVFormatContext *avf, int idx) priv->pre_skip = AV_RL16(packet + 10); st->codecpar->initial_padding = priv->pre_skip; + os->start_trimming = priv->pre_skip; /*orig_sample_rate = AV_RL32(packet + 12);*/ /*gain = AV_RL16(packet + 16);*/ /*channel_map = AV_RL8 (packet + 18);*/ diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c index 27d2c686b69..0e8c25c030b 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c @@ -165,7 +165,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, av_freep(&tt); av_freep(&ct); if (ret > 0) - ret = ff_flac_parse_picture(as, pict, ret); + ret = ff_flac_parse_picture(as, pict, ret, 0); av_freep(&pict); if (ret < 0) { av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); @@ -287,7 +287,7 @@ static int vorbis_update_metadata(AVFormatContext *s, int idx) os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size); /* Send an empty dictionary to indicate that metadata has been cleared. */ } else { - os->new_metadata = av_malloc(1); + os->new_metadata = av_mallocz(1); os->new_metadata_size = 0; } @@ -385,7 +385,12 @@ static int vorbis_header(AVFormatContext *s, int idx) } } } else { - int ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); + int ret; + + if (priv->vp) + return AVERROR_INVALIDDATA; + + ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); if (ret < 0) { st->codecpar->extradata_size = 0; return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/omadec.c b/chromium/third_party/ffmpeg/libavformat/omadec.c index 9521b6d59e9..5675d86e75e 100644 --- a/chromium/third_party/ffmpeg/libavformat/omadec.c +++ b/chromium/third_party/ffmpeg/libavformat/omadec.c @@ -79,6 +79,13 @@ typedef struct OMAContext { int (*read_packet)(AVFormatContext *s, AVPacket *pkt); } OMAContext; +static int oma_read_close(AVFormatContext *s) +{ + OMAContext *oc = s->priv_data; + av_freep(&oc->av_des); + return 0; +} + static void hex_log(AVFormatContext *s, int level, const char *name, const uint8_t *value, int len) { @@ -217,14 +224,13 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) av_log(s, AV_LOG_INFO, "File is encrypted\n"); /* find GEOB metadata */ - while (em) { - if (!strcmp(em->tag, "GEOB") && - (geob = em->data) && - (!strcmp(geob->description, "OMG_LSI") || - !strcmp(geob->description, "OMG_BKLSI"))) { + for (; em; em = em->next) { + if (strcmp(em->tag, "GEOB")) + continue; + geob = &em->data.geob; + if (!strcmp(geob->description, "OMG_LSI") || + !strcmp(geob->description, "OMG_BKLSI")) break; - } - em = em->next; } if (!em) { av_log(s, AV_LOG_ERROR, "No encryption header found\n"); @@ -397,17 +403,20 @@ static int oma_read_header(AVFormatContext *s) OMAContext *oc = s->priv_data; ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0); - if ((ret = ff_id3v2_parse_chapters(s, &extra_meta)) < 0) { + if ((ret = ff_id3v2_parse_chapters(s, extra_meta)) < 0) { ff_id3v2_free_extra_meta(&extra_meta); return ret; } ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); - if (ret < EA3_HEADER_SIZE) + if (ret < EA3_HEADER_SIZE) { + ff_id3v2_free_extra_meta(&extra_meta); return -1; + } if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}), 3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) { + ff_id3v2_free_extra_meta(&extra_meta); av_log(s, AV_LOG_ERROR, "Couldn't find the EA3 header !\n"); return AVERROR_INVALIDDATA; } @@ -426,8 +435,10 @@ static int oma_read_header(AVFormatContext *s) codec_params = AV_RB24(&buf[33]); st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); + if (!st) { + ret = AVERROR(ENOMEM); + goto fail; + } st->start_time = 0; st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; @@ -442,7 +453,8 @@ static int oma_read_header(AVFormatContext *s) samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100; if (!samplerate) { av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } if (samplerate != 44100) avpriv_request_sample(s, "Sample rate %d", samplerate); @@ -460,7 +472,7 @@ static int oma_read_header(AVFormatContext *s) /* fake the ATRAC3 extradata * (wav format, makes stream copy to wav work) */ if ((ret = ff_alloc_extradata(st->codecpar, 14)) < 0) - return ret; + goto fail; edata = st->codecpar->extradata; AV_WL16(&edata[0], 1); // always 1 @@ -477,7 +489,8 @@ static int oma_read_header(AVFormatContext *s) if (!channel_id) { av_log(s, AV_LOG_ERROR, "Invalid ATRAC-X channel id: %"PRIu32"\n", channel_id); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->channel_layout = ff_oma_chid_to_native_layout[channel_id - 1]; st->codecpar->channels = ff_oma_chid_to_num_channels[channel_id - 1]; @@ -485,7 +498,8 @@ static int oma_read_header(AVFormatContext *s) samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100; if (!samplerate) { av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } st->codecpar->sample_rate = samplerate; st->codecpar->bit_rate = samplerate * framesize / (2048 / 8); @@ -525,12 +539,16 @@ static int oma_read_header(AVFormatContext *s) break; default: av_log(s, AV_LOG_ERROR, "Unsupported codec %d!\n", buf[32]); - return AVERROR(ENOSYS); + ret = AVERROR(ENOSYS); + goto fail; } st->codecpar->block_align = framesize; return 0; +fail: + oma_read_close(s); + return ret; } static int oma_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -592,13 +610,6 @@ wipe: return err; } -static int oma_read_close(AVFormatContext *s) -{ - OMAContext *oc = s->priv_data; - av_free(oc->av_des); - return 0; -} - AVInputFormat ff_oma_demuxer = { .name = "oma", .long_name = NULL_IF_CONFIG_SMALL("Sony OpenMG audio"), diff --git a/chromium/third_party/ffmpeg/libavformat/options.c b/chromium/third_party/ffmpeg/libavformat/options.c index e14510504f7..3160904fda9 100644 --- a/chromium/third_party/ffmpeg/libavformat/options.c +++ b/chromium/third_party/ffmpeg/libavformat/options.c @@ -21,6 +21,7 @@ #include "avio_internal.h" #include "internal.h" +#include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/opt.h" @@ -53,6 +54,8 @@ static void *format_child_next(void *obj, void *prev) return NULL; } +#if FF_API_CHILD_CLASS_NEXT +FF_DISABLE_DEPRECATION_WARNINGS static const AVClass *format_child_class_next(const AVClass *prev) { AVInputFormat *ifmt = NULL; @@ -80,6 +83,64 @@ static const AVClass *format_child_class_next(const AVClass *prev) return NULL; } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +enum { + CHILD_CLASS_ITER_AVIO = 0, + CHILD_CLASS_ITER_MUX, + CHILD_CLASS_ITER_DEMUX, + CHILD_CLASS_ITER_DONE, + +}; + +#define ITER_STATE_SHIFT 16 + +static const AVClass *format_child_class_iterate(void **iter) +{ + // we use the low 16 bits of iter as the value to be passed to + // av_(de)muxer_iterate() + void *val = (void*)(((uintptr_t)*iter) & ((1 << ITER_STATE_SHIFT) - 1)); + unsigned int state = ((uintptr_t)*iter) >> ITER_STATE_SHIFT; + const AVClass *ret = NULL; + + if (state == CHILD_CLASS_ITER_AVIO) { + ret = &ff_avio_class; + state++; + goto finish; + } + + if (state == CHILD_CLASS_ITER_MUX) { + const AVOutputFormat *ofmt; + + while ((ofmt = av_muxer_iterate(&val))) { + ret = ofmt->priv_class; + if (ret) + goto finish; + } + + val = NULL; + state++; + } + + if (state == CHILD_CLASS_ITER_DEMUX) { + const AVInputFormat *ifmt; + + while ((ifmt = av_demuxer_iterate(&val))) { + ret = ifmt->priv_class; + if (ret) + goto finish; + } + val = NULL; + state++; + } + +finish: + // make sure none av_(de)muxer_iterate does not set the high bits of val + av_assert0(!((uintptr_t)val >> ITER_STATE_SHIFT)); + *iter = (void*)((uintptr_t)val | (state << ITER_STATE_SHIFT)); + return ret; +} static AVClassCategory get_category(void *ptr) { @@ -94,7 +155,10 @@ static const AVClass av_format_context_class = { .option = avformat_options, .version = LIBAVUTIL_VERSION_INT, .child_next = format_child_next, +#if FF_API_CHILD_CLASS_NEXT .child_class_next = format_child_class_next, +#endif + .child_class_iterate = format_child_class_iterate, .category = AV_CLASS_CATEGORY_MUXER, .get_category = get_category, }; diff --git a/chromium/third_party/ffmpeg/libavformat/pjsdec.c b/chromium/third_party/ffmpeg/libavformat/pjsdec.c index 8a5cc04f841..1f1d51c4049 100644 --- a/chromium/third_party/ffmpeg/libavformat/pjsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/pjsdec.c @@ -67,7 +67,6 @@ static int pjs_read_header(AVFormatContext *s) { PJSContext *pjs = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); - int res = 0; if (!st) return AVERROR(ENOMEM); @@ -94,8 +93,10 @@ static int pjs_read_header(AVFormatContext *s) p[strcspn(p, "\"")] = 0; sub = ff_subtitles_queue_insert(&pjs->q, p, strlen(p), 0); - if (!sub) + if (!sub) { + ff_subtitles_queue_clean(&pjs->q); return AVERROR(ENOMEM); + } sub->pos = pos; sub->pts = pts_start; sub->duration = duration; @@ -103,7 +104,7 @@ static int pjs_read_header(AVFormatContext *s) } ff_subtitles_queue_finalize(s, &pjs->q); - return res; + return 0; } static int pjs_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/pp_bnk.c b/chromium/third_party/ffmpeg/libavformat/pp_bnk.c new file mode 100644 index 00000000000..8364de1fd9c --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/pp_bnk.c @@ -0,0 +1,292 @@ +/* + * Pro Pinball Series Soundbank (44c, 22c, 11c, 5c) demuxer. + * + * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.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 + */ +#include "avformat.h" +#include "internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" +#include "libavutil/internal.h" + +#define PP_BNK_MAX_READ_SIZE 4096 +#define PP_BNK_FILE_HEADER_SIZE 20 +#define PP_BNK_TRACK_SIZE 20 + +typedef struct PPBnkHeader { + uint32_t bank_id; /*< Bank ID, useless for our purposes. */ + uint32_t sample_rate; /*< Sample rate of the contained tracks. */ + uint32_t always1; /*< Unknown, always seems to be 1. */ + uint32_t track_count; /*< Number of tracks in the file. */ + uint32_t flags; /*< Flags. */ +} PPBnkHeader; + +typedef struct PPBnkTrack { + uint32_t id; /*< Track ID. Usually track[i].id == track[i-1].id + 1, but not always */ + uint32_t size; /*< Size of the data in bytes. */ + uint32_t sample_rate; /*< Sample rate. */ + uint32_t always1_1; /*< Unknown, always seems to be 1. */ + uint32_t always1_2; /*< Unknown, always seems to be 1. */ +} PPBnkTrack; + +typedef struct PPBnkCtxTrack { + int64_t data_offset; + uint32_t data_size; + uint32_t bytes_read; +} PPBnkCtxTrack; + +typedef struct PPBnkCtx { + int track_count; + PPBnkCtxTrack *tracks; + uint32_t current_track; +} PPBnkCtx; + +enum { + PP_BNK_FLAG_PERSIST = (1 << 0), /*< This is a large file, keep in memory. */ + PP_BNK_FLAG_MUSIC = (1 << 1), /*< This is music. */ + PP_BNK_FLAG_MASK = (PP_BNK_FLAG_PERSIST | PP_BNK_FLAG_MUSIC) +}; + +static void pp_bnk_parse_header(PPBnkHeader *hdr, const uint8_t *buf) +{ + hdr->bank_id = AV_RL32(buf + 0); + hdr->sample_rate = AV_RL32(buf + 4); + hdr->always1 = AV_RL32(buf + 8); + hdr->track_count = AV_RL32(buf + 12); + hdr->flags = AV_RL32(buf + 16); +} + +static void pp_bnk_parse_track(PPBnkTrack *trk, const uint8_t *buf) +{ + trk->id = AV_RL32(buf + 0); + trk->size = AV_RL32(buf + 4); + trk->sample_rate = AV_RL32(buf + 8); + trk->always1_1 = AV_RL32(buf + 12); + trk->always1_2 = AV_RL32(buf + 16); +} + +static int pp_bnk_probe(const AVProbeData *p) +{ + uint32_t sample_rate = AV_RL32(p->buf + 4); + uint32_t track_count = AV_RL32(p->buf + 12); + uint32_t flags = AV_RL32(p->buf + 16); + + if (track_count == 0 || track_count > INT_MAX) + return 0; + + if ((sample_rate != 5512) && (sample_rate != 11025) && + (sample_rate != 22050) && (sample_rate != 44100)) + return 0; + + /* Check the first track header. */ + if (AV_RL32(p->buf + 28) != sample_rate) + return 0; + + if ((flags & ~PP_BNK_FLAG_MASK) != 0) + return 0; + + return AVPROBE_SCORE_MAX / 4 + 1; +} + +static int pp_bnk_read_header(AVFormatContext *s) +{ + int64_t ret; + AVStream *st; + AVCodecParameters *par; + PPBnkCtx *ctx = s->priv_data; + uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)]; + PPBnkHeader hdr; + + if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0) + return ret; + else if (ret != PP_BNK_FILE_HEADER_SIZE) + return AVERROR(EIO); + + pp_bnk_parse_header(&hdr, buf); + + if (hdr.track_count == 0 || hdr.track_count > INT_MAX) + return AVERROR_INVALIDDATA; + + if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX) + return AVERROR_INVALIDDATA; + + if (hdr.always1 != 1) { + avpriv_request_sample(s, "Non-one header value"); + return AVERROR_PATCHWELCOME; + } + + ctx->track_count = hdr.track_count; + + if (!(ctx->tracks = av_malloc_array(hdr.track_count, sizeof(PPBnkCtxTrack)))) + return AVERROR(ENOMEM); + + /* Parse and validate each track. */ + for (int i = 0; i < hdr.track_count; i++) { + PPBnkTrack e; + PPBnkCtxTrack *trk = ctx->tracks + i; + + ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE); + if (ret < 0 && ret != AVERROR_EOF) + goto fail; + + /* Short byte-count or EOF, we have a truncated file. */ + if (ret != PP_BNK_TRACK_SIZE) { + av_log(s, AV_LOG_WARNING, "File truncated at %d/%u track(s)\n", + i, hdr.track_count); + ctx->track_count = i; + break; + } + + pp_bnk_parse_track(&e, buf); + + /* The individual sample rates of all tracks must match that of the file header. */ + if (e.sample_rate != hdr.sample_rate) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (e.always1_1 != 1 || e.always1_2 != 1) { + avpriv_request_sample(s, "Non-one track header values"); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + + trk->data_offset = avio_tell(s->pb); + trk->data_size = e.size; + trk->bytes_read = 0; + + /* + * Skip over the data to the next stream header. + * Sometimes avio_skip() doesn't detect EOF. If it doesn't, either: + * - the avio_read() above will, or + * - pp_bnk_read_packet() will read a truncated last track. + */ + if ((ret = avio_skip(s->pb, e.size)) == AVERROR_EOF) { + ctx->track_count = i + 1; + av_log(s, AV_LOG_WARNING, + "Track %d has truncated data, assuming track count == %d\n", + i, ctx->track_count); + break; + } else if (ret < 0) { + goto fail; + } + } + + /* File is only a header. */ + if (ctx->track_count == 0) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* Build the streams. */ + for (int i = 0; i < ctx->track_count; i++) { + if (!(st = avformat_new_stream(s, NULL))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + par = st->codecpar; + par->codec_type = AVMEDIA_TYPE_AUDIO; + par->codec_id = AV_CODEC_ID_ADPCM_IMA_CUNNING; + par->format = AV_SAMPLE_FMT_S16; + par->channel_layout = AV_CH_LAYOUT_MONO; + par->channels = 1; + par->sample_rate = hdr.sample_rate; + par->bits_per_coded_sample = 4; + par->bits_per_raw_sample = 16; + par->block_align = 1; + par->bit_rate = par->sample_rate * par->bits_per_coded_sample; + + avpriv_set_pts_info(st, 64, 1, par->sample_rate); + st->start_time = 0; + st->duration = ctx->tracks[i].data_size * 2; + } + + return 0; + +fail: + av_freep(&ctx->tracks); + return ret; +} + +static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + PPBnkCtx *ctx = s->priv_data; + + /* + * Read a packet from each track, round-robin style. + * This method is nasty, but needed to avoid "Too many packets buffered" errors. + */ + for (int i = 0; i < ctx->track_count; i++, ctx->current_track++) + { + int64_t ret; + int size; + PPBnkCtxTrack *trk; + + ctx->current_track %= ctx->track_count; + + trk = ctx->tracks + ctx->current_track; + + if (trk->bytes_read == trk->data_size) + continue; + + if ((ret = avio_seek(s->pb, trk->data_offset + trk->bytes_read, SEEK_SET)) < 0) + return ret; + else if (ret != trk->data_offset + trk->bytes_read) + return AVERROR(EIO); + + size = FFMIN(trk->data_size - trk->bytes_read, PP_BNK_MAX_READ_SIZE); + + if ((ret = av_get_packet(s->pb, pkt, size)) == AVERROR_EOF) { + /* If we've hit EOF, don't attempt this track again. */ + trk->data_size = trk->bytes_read; + continue; + } else if (ret < 0) { + return ret; + } + + trk->bytes_read += ret; + pkt->flags &= ~AV_PKT_FLAG_CORRUPT; + pkt->stream_index = ctx->current_track++; + pkt->duration = ret * 2; + return 0; + } + + /* If we reach here, we're done. */ + return AVERROR_EOF; +} + +static int pp_bnk_read_close(AVFormatContext *s) +{ + PPBnkCtx *ctx = s->priv_data; + + av_freep(&ctx->tracks); + + return 0; +} + +AVInputFormat ff_pp_bnk_demuxer = { + .name = "pp_bnk", + .long_name = NULL_IF_CONFIG_SMALL("Pro Pinball Series Soundbank"), + .priv_data_size = sizeof(PPBnkCtx), + .read_probe = pp_bnk_probe, + .read_header = pp_bnk_read_header, + .read_packet = pp_bnk_read_packet, + .read_close = pp_bnk_read_close +}; diff --git a/chromium/third_party/ffmpeg/libavformat/prompeg.c b/chromium/third_party/ffmpeg/libavformat/prompeg.c index 9770a916a2b..59faa824bb3 100644 --- a/chromium/third_party/ffmpeg/libavformat/prompeg.c +++ b/chromium/third_party/ffmpeg/libavformat/prompeg.c @@ -291,8 +291,7 @@ static int prompeg_open(URLContext *h, const char *uri, int flags) { } if (s->ttl > 0) { - snprintf(buf, sizeof (buf), "%d", s->ttl); - av_dict_set(&udp_opts, "ttl", buf, 0); + av_dict_set_int(&udp_opts, "ttl", s->ttl, 0); } ff_url_join(buf, sizeof (buf), "udp", NULL, hostname, rtp_port + 2, NULL); @@ -388,7 +387,7 @@ static int prompeg_write(URLContext *h, const uint8_t *buf, int size) { PrompegFec *fec_tmp; uint8_t *bitstring = NULL; int col_idx, col_out_idx, row_idx; - int ret, written = 0; + int ret = 0; if (s->init && ((ret = prompeg_init(h, buf, size)) < 0)) goto end; @@ -404,7 +403,6 @@ static int prompeg_write(URLContext *h, const uint8_t *buf, int size) { if (!s->first || s->packet_idx > 0) { if ((ret = prompeg_write_fec(h, s->fec_row, PROMPEG_FEC_ROW)) < 0) goto end; - written += ret; } memcpy(s->fec_row->bitstring, bitstring, s->bitstring_size); s->fec_row->sn = AV_RB16(buf + 2); @@ -435,7 +433,6 @@ static int prompeg_write(URLContext *h, const uint8_t *buf, int size) { col_out_idx = s->packet_idx / s->d; if ((ret = prompeg_write_fec(h, s->fec_col[col_out_idx], PROMPEG_FEC_COL)) < 0) goto end; - written += ret; } if (++s->packet_idx >= s->packet_idx_max) { @@ -444,7 +441,7 @@ static int prompeg_write(URLContext *h, const uint8_t *buf, int size) { s->first = 0; } - ret = written; + ret = size; end: av_free(bitstring); diff --git a/chromium/third_party/ffmpeg/libavformat/protocols.c b/chromium/third_party/ffmpeg/libavformat/protocols.c index f1b8eab0fd6..7df18fbb3b9 100644 --- a/chromium/third_party/ffmpeg/libavformat/protocols.c +++ b/chromium/third_party/ffmpeg/libavformat/protocols.c @@ -73,6 +73,7 @@ extern const URLProtocol ff_libzmq_protocol; #include "libavformat/protocol_list.c" +#if FF_API_CHILD_CLASS_NEXT const AVClass *ff_urlcontext_child_class_next(const AVClass *prev) { int i; @@ -91,7 +92,22 @@ const AVClass *ff_urlcontext_child_class_next(const AVClass *prev) return url_protocols[i]->priv_data_class; return NULL; } +#endif +const AVClass *ff_urlcontext_child_class_iterate(void **iter) +{ + const AVClass *ret = NULL; + uintptr_t i; + + for (i = (uintptr_t)*iter; url_protocols[i]; i++) { + ret = url_protocols[i]->priv_data_class; + if (ret) + break; + } + + *iter = (void*)(uintptr_t)(url_protocols[i] ? i + 1 : i); + return ret; +} const char *avio_enum_protocols(void **opaque, int output) { diff --git a/chromium/third_party/ffmpeg/libavformat/rawdec.c b/chromium/third_party/ffmpeg/libavformat/rawdec.c index fee016cc7f0..10c37c5cb91 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rawdec.c @@ -123,6 +123,8 @@ const AVOption ff_rawvideo_options[] = { { "raw_packet_size", "", OFFSET(raw_packet_size), AV_OPT_TYPE_INT, {.i64 = RAW_PACKET_SIZE }, 1, INT_MAX, DEC}, { NULL }, }; +#undef OFFSET +#define OFFSET(x) offsetof(FFRawDemuxerContext, x) const AVOption ff_raw_options[] = { { "raw_packet_size", "", OFFSET(raw_packet_size), AV_OPT_TYPE_INT, {.i64 = RAW_PACKET_SIZE }, 1, INT_MAX, DEC}, { NULL }, diff --git a/chromium/third_party/ffmpeg/libavformat/rawdec.h b/chromium/third_party/ffmpeg/libavformat/rawdec.h index 85e0790c86e..34c8adcb199 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawdec.h +++ b/chromium/third_party/ffmpeg/libavformat/rawdec.h @@ -95,7 +95,7 @@ static const AVClass name ## _demuxer_class = {\ }; #define FF_DEF_RAWSUB_DEMUXER(shortname, longname, probe, ext, id, flag)\ -FF_RAWVIDEO_DEMUXER_CLASS(shortname)\ +FF_RAWSUB_DEMUXER_CLASS(shortname)\ AVInputFormat ff_ ## shortname ## _demuxer = {\ .name = #shortname,\ .long_name = NULL_IF_CONFIG_SMALL(longname),\ diff --git a/chromium/third_party/ffmpeg/libavformat/riff.c b/chromium/third_party/ffmpeg/libavformat/riff.c index bf6a8f47f85..162e2b1bf20 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.c +++ b/chromium/third_party/ffmpeg/libavformat/riff.c @@ -493,6 +493,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MVDV, MKTAG('M', 'V', 'D', 'V') }, { AV_CODEC_ID_MVHA, MKTAG('M', 'V', 'H', 'A') }, { AV_CODEC_ID_MV30, MKTAG('M', 'V', '3', '0') }, + { AV_CODEC_ID_NOTCHLC, MKTAG('n', 'l', 'c', '1') }, { AV_CODEC_ID_NONE, 0 } }; diff --git a/chromium/third_party/ffmpeg/libavformat/riff.h b/chromium/third_party/ffmpeg/libavformat/riff.h index 21078b77c8e..127138d2bca 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.h +++ b/chromium/third_party/ffmpeg/libavformat/riff.h @@ -46,7 +46,7 @@ void ff_end_tag(AVIOContext *pb, int64_t start); */ int ff_get_bmp_header(AVIOContext *pb, AVStream *st, uint32_t *size); -void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int ignore_extradata); +void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int ignore_extradata, int rgb_frame_is_flipped); /** * Tell ff_put_wav_header() to use WAVEFORMATEX even for PCM codecs. diff --git a/chromium/third_party/ffmpeg/libavformat/riffenc.c b/chromium/third_party/ffmpeg/libavformat/riffenc.c index c04d55c4230..04a21fcffaa 100644 --- a/chromium/third_party/ffmpeg/libavformat/riffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/riffenc.c @@ -207,11 +207,12 @@ int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb, /* BITMAPINFOHEADER header */ void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, - int for_asf, int ignore_extradata) + int for_asf, int ignore_extradata, int rgb_frame_is_flipped) { - int keep_height = par->extradata_size >= 9 && - !memcmp(par->extradata + par->extradata_size - 9, "BottomUp", 9); - int extradata_size = par->extradata_size - 9*keep_height; + int flipped_extradata = (par->extradata_size >= 9 && + !memcmp(par->extradata + par->extradata_size - 9, "BottomUp", 9)); + int keep_height = flipped_extradata || rgb_frame_is_flipped; + int extradata_size = par->extradata_size - 9*flipped_extradata; enum AVPixelFormat pix_fmt = par->format; int pal_avi; diff --git a/chromium/third_party/ffmpeg/libavformat/rtmpcrypt.c b/chromium/third_party/ffmpeg/libavformat/rtmpcrypt.c index 253b8ca2ce1..a835ab263f5 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmpcrypt.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmpcrypt.c @@ -240,7 +240,7 @@ static int rtmpe_close(URLContext *h) RTMPEContext *rt = h->priv_data; ff_dh_free(rt->dh); - ffurl_close(rt->stream); + ffurl_closep(&rt->stream); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtmphttp.c b/chromium/third_party/ffmpeg/libavformat/rtmphttp.c index ef6146ca864..c920c19ab5b 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmphttp.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmphttp.c @@ -176,7 +176,7 @@ static int rtmp_http_close(URLContext *h) } av_freep(&rt->out_data); - ffurl_close(rt->stream); + ffurl_closep(&rt->stream); return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c index 42aacbd1b99..d9741bc622c 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c @@ -163,7 +163,7 @@ static int add_tracked_method(RTMPContext *rt, const char *name, int id) if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) { rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2; - if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size * + if ((err = av_reallocp_array(&rt->tracked_methods, rt->tracked_methods_size, sizeof(*rt->tracked_methods))) < 0) { rt->nb_tracked_methods = 0; rt->tracked_methods_size = 0; @@ -2511,7 +2511,7 @@ static int rtmp_close(URLContext *h) free_tracked_methods(rt); av_freep(&rt->flv_data); - ffurl_close(rt->stream); + ffurl_closep(&rt->stream); return ret; } @@ -2824,8 +2824,7 @@ reconnect: if (rt->do_reconnect) { int i; - ffurl_close(rt->stream); - rt->stream = NULL; + ffurl_closep(&rt->stream); rt->do_reconnect = 0; rt->nb_invokes = 0; for (i = 0; i < 2; i++) diff --git a/chromium/third_party/ffmpeg/libavformat/rtpenc.c b/chromium/third_party/ffmpeg/libavformat/rtpenc.c index 63047beccc8..9ef7e9094dd 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpenc.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpenc.c @@ -589,7 +589,7 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) break; case AV_CODEC_ID_H263: if (s->flags & FF_RTP_FLAG_RFC2190) { - int mb_info_size = 0; + int mb_info_size; const uint8_t *mb_info = av_packet_get_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, &mb_info_size); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpproto.c b/chromium/third_party/ffmpeg/libavformat/rtpproto.c index 1f0a82ac7e5..19e940d01e6 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpproto.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpproto.c @@ -301,8 +301,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) goto fail; } if (s->ttl > 0) { - snprintf(buf, sizeof (buf), "%d", s->ttl); - av_dict_set(&fec_opts, "ttl", buf, 0); + av_dict_set_int(&fec_opts, "ttl", s->ttl, 0); } } @@ -363,10 +362,8 @@ static int rtp_open(URLContext *h, const char *uri, int flags) return 0; fail: - if (s->rtp_hd) - ffurl_close(s->rtp_hd); - if (s->rtcp_hd) - ffurl_close(s->rtcp_hd); + ffurl_closep(&s->rtp_hd); + ffurl_closep(&s->rtcp_hd); ffurl_closep(&s->fec_hd); av_free(fec_protocol); av_dict_free(&fec_opts); @@ -506,8 +503,8 @@ static int rtp_close(URLContext *h) ff_ip_reset_filters(&s->filters); - ffurl_close(s->rtp_hd); - ffurl_close(s->rtcp_hd); + ffurl_closep(&s->rtp_hd); + ffurl_closep(&s->rtcp_hd); ffurl_closep(&s->fec_hd); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtsp.c b/chromium/third_party/ffmpeg/libavformat/rtsp.c index b2b3f320113..5d8491b74ba 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtsp.c +++ b/chromium/third_party/ffmpeg/libavformat/rtsp.c @@ -763,9 +763,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets) ff_rtp_parse_close(rtsp_st->transport_priv); } rtsp_st->transport_priv = NULL; - if (rtsp_st->rtp_handle) - ffurl_close(rtsp_st->rtp_handle); - rtsp_st->rtp_handle = NULL; + ffurl_closep(&rtsp_st->rtp_handle); } } @@ -1666,9 +1664,10 @@ fail: void ff_rtsp_close_connections(AVFormatContext *s) { RTSPState *rt = s->priv_data; - if (rt->rtsp_hd_out != rt->rtsp_hd) ffurl_close(rt->rtsp_hd_out); - ffurl_close(rt->rtsp_hd); - rt->rtsp_hd = rt->rtsp_hd_out = NULL; + if (rt->rtsp_hd_out != rt->rtsp_hd) + ffurl_closep(&rt->rtsp_hd_out); + rt->rtsp_hd_out = NULL; + ffurl_closep(&rt->rtsp_hd); } int ff_rtsp_connect(AVFormatContext *s) @@ -2496,8 +2495,7 @@ static int rtp_read_header(AVFormatContext *s) break; } getsockname(ffurl_get_file_handle(in), (struct sockaddr*) &addr, &addrlen); - ffurl_close(in); - in = NULL; + ffurl_closep(&in); par = avcodec_parameters_alloc(); if (!par) { @@ -2571,8 +2569,7 @@ fail_nobuf: av_bprint_finalize(&sdp, NULL); fail: avcodec_parameters_free(&par); - if (in) - ffurl_close(in); + ffurl_closep(&in); ff_network_close(); return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtspdec.c b/chromium/third_party/ffmpeg/libavformat/rtspdec.c index bd2e8f47f1a..dfa29913bff 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtspdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rtspdec.c @@ -289,9 +289,7 @@ static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl) } else { do { AVDictionary *opts = NULL; - char buf[256]; - snprintf(buf, sizeof(buf), "%d", rt->buffer_size); - av_dict_set(&opts, "buffer_size", buf, 0); + av_dict_set_int(&opts, "buffer_size", rt->buffer_size, 0); ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL); av_log(s, AV_LOG_TRACE, "Opening: %s", url); ret = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, diff --git a/chromium/third_party/ffmpeg/libavformat/samidec.c b/chromium/third_party/ffmpeg/libavformat/samidec.c index fd98393086b..3070ef9bacf 100644 --- a/chromium/third_party/ffmpeg/libavformat/samidec.c +++ b/chromium/third_party/ffmpeg/libavformat/samidec.c @@ -108,6 +108,8 @@ static int sami_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &sami->q); end: + if (res < 0) + ff_subtitles_queue_clean(&sami->q); av_bprint_finalize(&buf, NULL); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/sapdec.c b/chromium/third_party/ffmpeg/libavformat/sapdec.c index b3644b436b5..eec73aa2f45 100644 --- a/chromium/third_party/ffmpeg/libavformat/sapdec.c +++ b/chromium/third_party/ffmpeg/libavformat/sapdec.c @@ -54,8 +54,7 @@ static int sap_read_close(AVFormatContext *s) struct SAPState *sap = s->priv_data; if (sap->sdp_ctx) avformat_close_input(&sap->sdp_ctx); - if (sap->ann_fd) - ffurl_close(sap->ann_fd); + ffurl_closep(&sap->ann_fd); av_freep(&sap->sdp); ff_network_close(); return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/sapenc.c b/chromium/third_party/ffmpeg/libavformat/sapenc.c index f9afab0c33e..dc1c2104082 100644 --- a/chromium/third_party/ffmpeg/libavformat/sapenc.c +++ b/chromium/third_party/ffmpeg/libavformat/sapenc.c @@ -60,8 +60,7 @@ static int sap_write_close(AVFormatContext *s) } av_freep(&sap->ann); - if (sap->ann_fd) - ffurl_close(sap->ann_fd); + ffurl_closep(&sap->ann_fd); ff_network_close(); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/sbgdec.c b/chromium/third_party/ffmpeg/libavformat/sbgdec.c index de1de271bbe..c11244ef3df 100644 --- a/chromium/third_party/ffmpeg/libavformat/sbgdec.c +++ b/chromium/third_party/ffmpeg/libavformat/sbgdec.c @@ -474,6 +474,8 @@ static int parse_timestamp(struct sbg_parser *p, while (lex_char(p, '+')) { if (!lex_time(p, &dt)) return AVERROR_INVALIDDATA; + if (av_sat_add64(rel, dt) - dt != rel) + return AVERROR_INVALIDDATA; rel += dt; r = 1; } diff --git a/chromium/third_party/ffmpeg/libavformat/sccdec.c b/chromium/third_party/ffmpeg/libavformat/sccdec.c index b9042b39ac9..751dee7c6c1 100644 --- a/chromium/third_party/ffmpeg/libavformat/sccdec.c +++ b/chromium/third_party/ffmpeg/libavformat/sccdec.c @@ -63,10 +63,9 @@ static int scc_read_header(AVFormatContext *s) { SCCContext *scc = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); - char line[4096], line2[4096]; - int64_t ts_start, ts_end; - int count = 0, ret = 0; - ptrdiff_t len2, len; + char line2[4096], line[4096]; + int64_t pos, ts, next_ts = AV_NOPTS_VALUE; + ptrdiff_t len; uint8_t out[4096]; FFTextReader tr; @@ -78,83 +77,107 @@ static int scc_read_header(AVFormatContext *s) st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_EIA_608; - while (!ff_text_eof(&tr)) { - int64_t current_pos, next_pos; + while (!ff_text_eof(&tr) || next_ts == AV_NOPTS_VALUE || line2[0]) { char *saveptr = NULL, *lline; - int hh1, mm1, ss1, fs1, i; - int hh2, mm2, ss2, fs2; + int hh, mm, ss, fs, i; AVPacket *sub; - if (count == 0) { - current_pos = ff_text_pos(&tr); + if (next_ts == AV_NOPTS_VALUE) { while (!ff_text_eof(&tr)) { len = ff_subtitles_read_line(&tr, line, sizeof(line)); - if (len > 13) + if (len <= 13) + continue; + if (!strncmp(line, "Scenarist_SCC V1.0", 18)) + continue; + if (av_sscanf(line, "%d:%d:%d%*[:;]%d", &hh, &mm, &ss, &fs) == 4) break; } - } - if (!strncmp(line, "Scenarist_SCC V1.0", 18)) - continue; - if (av_sscanf(line, "%d:%d:%d%*[:;]%d", &hh1, &mm1, &ss1, &fs1) != 4) - continue; + ts = (hh * 3600LL + mm * 60LL + ss) * 1000LL + fs * 33; - ts_start = (hh1 * 3600LL + mm1 * 60LL + ss1) * 1000LL + fs1 * 33; + while (!ff_text_eof(&tr)) { + len = ff_subtitles_read_line(&tr, line2, sizeof(line2)); + if (len <= 13) + continue; - next_pos = ff_text_pos(&tr); - while (!ff_text_eof(&tr)) { - len2 = ff_subtitles_read_line(&tr, line2, sizeof(line2)); - if (len2 > 13) - break; + if (av_sscanf(line2, "%d:%d:%d%*[:;]%d", &hh, &mm, &ss, &fs) == 4) + break; + } + } else { + memmove(line, line2, sizeof(line)); + line2[0] = 0; + + while (!ff_text_eof(&tr)) { + len = ff_subtitles_read_line(&tr, line2, sizeof(line2)); + if (len <= 13) + continue; + + if (av_sscanf(line2, "%d:%d:%d%*[:;]%d", &hh, &mm, &ss, &fs) == 4) + break; + } } - if (av_sscanf(line2, "%d:%d:%d%*[:;]%d", &hh2, &mm2, &ss2, &fs2) != 4) - continue; - ts_end = (hh2 * 3600LL + mm2 * 60LL + ss2) * 1000LL + fs2 * 33; - count++; + next_ts = (hh * 3600LL + mm * 60LL + ss) * 1000LL + fs * 33; -try_again: + pos = ff_text_pos(&tr); lline = (char *)&line; lline += 12; for (i = 0; i < 4095; i += 3) { char *ptr = av_strtok(lline, " ", &saveptr); char c1, c2, c3, c4; + uint8_t o1, o2; if (!ptr) break; if (av_sscanf(ptr, "%c%c%c%c", &c1, &c2, &c3, &c4) != 4) break; + o1 = convert(c2) | (convert(c1) << 4); + o2 = convert(c4) | (convert(c3) << 4); lline = NULL; + + if (i > 12 && o1 == 0x94 && o2 == 0x20 && saveptr && + (av_strncasecmp(saveptr, "942f", 4) && !av_strncasecmp(saveptr, "942c", 4))) { + + out[i] = 0; + + sub = ff_subtitles_queue_insert(&scc->q, out, i, 0); + if (!sub) + goto fail; + + sub->pos = pos; + pos += i; + sub->pts = ts; + sub->duration = i * 11; + ts += sub->duration; + i = 0; + } + out[i+0] = 0xfc; - out[i+1] = convert(c2) | (convert(c1) << 4); - out[i+2] = convert(c4) | (convert(c3) << 4); + out[i+1] = o1; + out[i+2] = o2; } + out[i] = 0; sub = ff_subtitles_queue_insert(&scc->q, out, i, 0); if (!sub) - return AVERROR(ENOMEM); - - sub->pos = current_pos; - sub->pts = ts_start; - sub->duration = ts_end - ts_start; - memmove(line, line2, sizeof(line)); - current_pos = next_pos; - line2[0] = 0; - } + goto fail; - if (line[0]) { - ts_start = ts_end; - ts_end += 1200; - goto try_again; + sub->pos = pos; + sub->pts = ts; + sub->duration = next_ts - ts; + ts = next_ts; } ff_subtitles_queue_finalize(s, &scc->q); - return ret; + return 0; +fail: + ff_subtitles_queue_clean(&scc->q); + return AVERROR(ENOMEM); } static int scc_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/sdp.c b/chromium/third_party/ffmpeg/libavformat/sdp.c index 34e9839b67a..2ce1a62262d 100644 --- a/chromium/third_party/ffmpeg/libavformat/sdp.c +++ b/chromium/third_party/ffmpeg/libavformat/sdp.c @@ -212,7 +212,7 @@ static char *extradata2psets(AVFormatContext *s, AVCodecParameters *par) p += strlen(p); r = r1; } - if (sps && sps_end - sps >= 4) { + if (sps && sps_end - sps >= 4 && p - psets <= MAX_PSET_SIZE - strlen(profile_string) - 7) { memcpy(p, profile_string, strlen(profile_string)); p += strlen(p); ff_data_to_hex(p, sps + 1, 3, 0); diff --git a/chromium/third_party/ffmpeg/libavformat/segafilm.c b/chromium/third_party/ffmpeg/libavformat/segafilm.c index 777606bcb64..4d14b81d163 100644 --- a/chromium/third_party/ffmpeg/libavformat/segafilm.c +++ b/chromium/third_party/ffmpeg/libavformat/segafilm.c @@ -40,8 +40,8 @@ typedef struct film_sample { int stream; - int64_t sample_offset; unsigned int sample_size; + int64_t sample_offset; int64_t pts; int keyframe; } film_sample; diff --git a/chromium/third_party/ffmpeg/libavformat/segafilmenc.c b/chromium/third_party/ffmpeg/libavformat/segafilmenc.c index 93c482ef7d8..42249d4effe 100644 --- a/chromium/third_party/ffmpeg/libavformat/segafilmenc.c +++ b/chromium/third_party/ffmpeg/libavformat/segafilmenc.c @@ -29,87 +29,28 @@ * http://wiki.multimedia.cx/index.php?title=Sega_FILM */ +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavcodec/bytestream.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" -typedef struct FILMPacket { - int audio; - int keyframe; - int32_t pts; - int32_t duration; - int32_t size; - int32_t index; - struct FILMPacket *next; -} FILMPacket; - typedef struct FILMOutputContext { + AVIOContext *header; + unsigned index; int audio_index; int video_index; - int64_t stab_pos; - FILMPacket *start; - FILMPacket *last; - int64_t packet_count; } FILMOutputContext; -static int film_write_packet_to_header(AVFormatContext *format_context, FILMPacket *pkt) -{ - AVIOContext *pb = format_context->pb; - /* The bits in these two 32-bit integers contain info about the contents of this sample */ - int32_t info1 = 0; - int32_t info2 = 0; - - if (pkt->audio) { - /* Always the same, carries no more information than "this is audio" */ - info1 = 0xFFFFFFFF; - info2 = 1; - } else { - info1 = pkt->pts; - info2 = pkt->duration; - /* The top bit being set indicates a key frame */ - if (!pkt->keyframe) - info1 |= 1U << 31; - } - - /* Write the 16-byte sample info packet to the STAB chunk in the header */ - avio_wb32(pb, pkt->index); - avio_wb32(pb, pkt->size); - avio_wb32(pb, info1); - avio_wb32(pb, info2); - - return 0; -} - static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt) { - FILMPacket *metadata; AVIOContext *pb = format_context->pb; FILMOutputContext *film = format_context->priv_data; - int encoded_buf_size = 0; + int encoded_buf_size, size = pkt->size; + uint32_t info1, info2; enum AVCodecID codec_id; - /* Track the metadata used to write the header and add it to the linked list */ - metadata = av_mallocz(sizeof(FILMPacket)); - if (!metadata) - return AVERROR(ENOMEM); - metadata->audio = pkt->stream_index == film->audio_index; - metadata->keyframe = pkt->flags & AV_PKT_FLAG_KEY; - metadata->pts = pkt->pts; - metadata->duration = pkt->duration; - metadata->size = pkt->size; - if (film->last == NULL) { - metadata->index = 0; - } else { - metadata->index = film->last->index + film->last->size; - film->last->next = metadata; - } - metadata->next = NULL; - if (film->start == NULL) - film->start = metadata; - film->packet_count++; - film->last = metadata; - codec_id = format_context->streams[pkt->stream_index]->codecpar->codec_id; /* Sega Cinepak has an extra two-byte header; write dummy data there, @@ -120,15 +61,14 @@ static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt) if (encoded_buf_size != pkt->size && (pkt->size % encoded_buf_size) != 0) { avio_write(pb, pkt->data, pkt->size); } else { - uint8_t padding[2] = {0, 0}; /* In Sega Cinepak, the reported size in the Cinepak header is * 8 bytes too short. However, the size in the STAB section of the header * is correct, taking into account the extra two bytes. */ AV_WB24(&pkt->data[1], pkt->size - 8 + 2); - metadata->size += 2; + size += 2; avio_write(pb, pkt->data, 10); - avio_write(pb, padding, 2); + avio_wb16(pb, 0); avio_write(pb, &pkt->data[10], pkt->size - 10); } } else { @@ -136,7 +76,27 @@ static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt) avio_write(pb, pkt->data, pkt->size); } - return 0; + /* Add the 16-byte sample info entry to the dynamic buffer + * for the STAB chunk in the header */ + pb = film->header; + avio_wb32(pb, film->index); + film->index += size; + avio_wb32(pb, size); + if (film->audio_index == pkt->stream_index) { + /* Always the same, carries no more information than "this is audio" */ + info1 = 0xFFFFFFFF; + info2 = 1; + } else { + info1 = pkt->pts; + info2 = pkt->duration; + /* The top bit being set indicates a key frame */ + if (!(pkt->flags & AV_PKT_FLAG_KEY)) + info1 |= 1U << 31; + } + avio_wb32(pb, info1); + avio_wb32(pb, info2); + + return pb->error; } static int get_audio_codec_id(enum AVCodecID codec_id) @@ -156,12 +116,10 @@ static int get_audio_codec_id(enum AVCodecID codec_id) static int film_init(AVFormatContext *format_context) { FILMOutputContext *film = format_context->priv_data; + int ret; + film->audio_index = -1; film->video_index = -1; - film->stab_pos = 0; - film->packet_count = 0; - film->start = NULL; - film->last = NULL; for (int i = 0; i < format_context->nb_streams; i++) { AVStream *st = format_context->streams[i]; @@ -202,11 +160,15 @@ static int film_init(AVFormatContext *format_context) av_log(format_context, AV_LOG_ERROR, "No video stream present.\n"); return AVERROR(EINVAL); } + if ((ret = avio_open_dyn_buf(&film->header)) < 0) + return ret; + ffio_fill(film->header, 0, 16 + 32 + 16); return 0; } -static int shift_data(AVFormatContext *format_context, int64_t shift_size) +static int write_header(AVFormatContext *format_context, uint8_t *header, + unsigned header_size) { int ret = 0; int64_t pos, pos_end; @@ -215,11 +177,12 @@ static int shift_data(AVFormatContext *format_context, int64_t shift_size) int read_size[2]; AVIOContext *read_pb; - buf = av_malloc(shift_size * 2); + buf = av_malloc(header_size); if (!buf) return AVERROR(ENOMEM); read_buf[0] = buf; - read_buf[1] = buf + shift_size; + read_buf[1] = header; + read_size[1] = header_size; /* Write the header at the beginning of the file, shifting all content as necessary; * based on the approach used by MOV faststart. */ @@ -232,25 +195,20 @@ static int shift_data(AVFormatContext *format_context, int64_t shift_size) return ret; } - /* mark the end of the shift to up to the last data we wrote, and get ready - * for writing */ - pos_end = avio_tell(format_context->pb); - avio_seek(format_context->pb, shift_size, SEEK_SET); + /* Mark the end of the shift to up to the last data we are going to write, + * and get ready for writing */ + pos_end = avio_tell(format_context->pb) + header_size; + pos = avio_seek(format_context->pb, 0, SEEK_SET); /* start reading at where the new header will be placed */ avio_seek(read_pb, 0, SEEK_SET); - pos = avio_tell(read_pb); -#define READ_BLOCK do { \ - read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], shift_size); \ - read_buf_id ^= 1; \ -} while (0) - - /* shift data by chunk of at most shift_size */ - READ_BLOCK; + /* shift data by chunk of at most header_size */ do { int n; - READ_BLOCK; + read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], + header_size); + read_buf_id ^= 1; n = read_size[read_buf_id]; if (n <= 0) break; @@ -266,79 +224,75 @@ static int shift_data(AVFormatContext *format_context, int64_t shift_size) static int film_write_header(AVFormatContext *format_context) { int ret = 0; - int64_t sample_table_size, stabsize, headersize; - AVIOContext *pb = format_context->pb; + unsigned stabsize, headersize, packet_count; FILMOutputContext *film = format_context->priv_data; - FILMPacket *prev, *packet; AVStream *video = NULL; + uint8_t *header, *ptr; /* Calculate how much we need to reserve for the header; * this is the amount the rest of the data will be shifted up by. */ - sample_table_size = film->packet_count * 16; - stabsize = 16 + sample_table_size; + headersize = avio_get_dyn_buf(film->header, &header); + if (headersize < 64) { + av_assert1(film->header->error < 0); + return film->header->error; + } + packet_count = (headersize - 64) / 16; + stabsize = 16 + 16 * packet_count; headersize = 16 + /* FILM header base */ 32 + /* FDSC chunk */ stabsize; - ret = shift_data(format_context, headersize); - if (ret < 0) - return ret; - /* Seek back to the beginning to start writing the header now */ - avio_seek(pb, 0, SEEK_SET); - - /* First, write the FILM header; this is very simple */ - - ffio_wfourcc(pb, "FILM"); - avio_wb32(pb, 48 + stabsize); + /* Write the header at the position in the buffer reserved for it. + * First, write the FILM header; this is very simple */ + ptr = header; + bytestream_put_be32(&ptr, MKBETAG('F', 'I', 'L', 'M')); + bytestream_put_be32(&ptr, headersize); /* This seems to be okay to hardcode, since this muxer targets 1.09 features; * videos produced by this muxer are readable by 1.08 and lower players. */ - ffio_wfourcc(pb, "1.09"); - /* I have no idea what this field does, might be reserved */ - avio_wb32(pb, 0); + bytestream_put_be32(&ptr, MKBETAG('1', '.', '0', '9')); + /* I have no idea what the next four bytes do, might be reserved */ + ptr += 4; /* Next write the FDSC (file description) chunk */ - ffio_wfourcc(pb, "FDSC"); - avio_wb32(pb, 0x20); /* Size of FDSC chunk */ + bytestream_put_be32(&ptr, MKBETAG('F', 'D', 'S', 'C')); + bytestream_put_be32(&ptr, 0x20); /* Size of FDSC chunk */ video = format_context->streams[film->video_index]; /* The only two supported codecs; raw video is rare */ switch (video->codecpar->codec_id) { case AV_CODEC_ID_CINEPAK: - ffio_wfourcc(pb, "cvid"); + bytestream_put_be32(&ptr, MKBETAG('c', 'v', 'i', 'd')); break; case AV_CODEC_ID_RAWVIDEO: - ffio_wfourcc(pb, "raw "); + bytestream_put_be32(&ptr, MKBETAG('r', 'a', 'w', ' ')); break; } - avio_wb32(pb, video->codecpar->height); - avio_wb32(pb, video->codecpar->width); - avio_w8(pb, 24); /* Bits per pixel - observed to always be 24 */ + bytestream_put_be32(&ptr, video->codecpar->height); + bytestream_put_be32(&ptr, video->codecpar->width); + bytestream_put_byte(&ptr, 24); /* Bits per pixel - observed to always be 24 */ if (film->audio_index > -1) { AVStream *audio = format_context->streams[film->audio_index]; int audio_codec = get_audio_codec_id(audio->codecpar->codec_id); - avio_w8(pb, audio->codecpar->channels); /* Audio channels */ - avio_w8(pb, audio->codecpar->bits_per_coded_sample); /* Audio bit depth */ - avio_w8(pb, audio_codec); /* Compression - 0 is PCM, 2 is ADX */ - avio_wb16(pb, audio->codecpar->sample_rate); /* Audio sampling rate */ + bytestream_put_byte(&ptr, audio->codecpar->channels); /* Audio channels */ + bytestream_put_byte(&ptr, audio->codecpar->bits_per_coded_sample); /* Audio bit depth */ + bytestream_put_byte(&ptr, audio_codec); /* Compression - 0 is PCM, 2 is ADX */ + bytestream_put_be16(&ptr, audio->codecpar->sample_rate); /* Audio sampling rate */ } else { - /* Set all these fields to 0 if there's no audio */ - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_wb16(pb, 0); + /* If there is no audio, all the audio fields should be set to zero. + * ffio_fill() already did this for us. */ + ptr += 1 + 1 + 1 + 2; } /* I have no idea what this pair of fields does either, might be reserved */ - avio_wb32(pb, 0); - avio_wb16(pb, 0); + ptr += 4 + 2; /* Finally, write the STAB (sample table) chunk */ - ffio_wfourcc(pb, "STAB"); - avio_wb32(pb, 16 + (film->packet_count * 16)); + bytestream_put_be32(&ptr, MKBETAG('S', 'T', 'A', 'B')); + bytestream_put_be32(&ptr, stabsize); /* Framerate base frequency. Here we're assuming that the frame rate is even. * In real world Sega FILM files, there are usually a couple of approaches: * a) framerate base frequency is the same as the framerate, and ticks @@ -348,19 +302,14 @@ static int film_write_header(AVFormatContext *format_context) * The latter occurs even in cases where the frame rate is even; for example, in * Lunar: Silver Star Story, the base frequency is 600 and each frame, the ticks * are incremented by 25 for an evenly spaced framerate of 24fps. */ - avio_wb32(pb, av_q2d(av_inv_q(video->time_base))); + bytestream_put_be32(&ptr, av_q2d(av_inv_q(video->time_base))); - avio_wb32(pb, film->packet_count); + bytestream_put_be32(&ptr, packet_count); - /* Finally, write out each packet's data to the header */ - packet = film->start; - while (packet != NULL) { - film_write_packet_to_header(format_context, packet); - prev = packet; - packet = packet->next; - av_freep(&prev); - } - film->start = film->last = NULL; + /* Finally, shift the data and write out the header. */ + ret = write_header(format_context, header, headersize); + if (ret < 0) + return ret; return 0; } @@ -368,13 +317,8 @@ static int film_write_header(AVFormatContext *format_context) static void film_deinit(AVFormatContext *format_context) { FILMOutputContext *film = format_context->priv_data; - FILMPacket *packet = film->start; - while (packet != NULL) { - FILMPacket *next = packet->next; - av_free(packet); - packet = next; - } - film->start = film->last = NULL; + + ffio_free_dyn_buf(&film->header); } AVOutputFormat ff_segafilm_muxer = { diff --git a/chromium/third_party/ffmpeg/libavformat/segment.c b/chromium/third_party/ffmpeg/libavformat/segment.c index 32c09827eb6..f67456fa571 100644 --- a/chromium/third_party/ffmpeg/libavformat/segment.c +++ b/chromium/third_party/ffmpeg/libavformat/segment.c @@ -162,12 +162,11 @@ static int segment_mux_init(AVFormatContext *s) oc->flags = s->flags; for (i = 0; i < s->nb_streams; i++) { - AVStream *st; - AVCodecParameters *ipar, *opar; + AVStream *st, *ist = s->streams[i]; + AVCodecParameters *ipar = ist->codecpar, *opar; if (!(st = avformat_new_stream(oc, NULL))) return AVERROR(ENOMEM); - ipar = s->streams[i]->codecpar; opar = st->codecpar; avcodec_parameters_copy(opar, ipar); if (!oc->oformat->codec_tag || @@ -177,16 +176,17 @@ static int segment_mux_init(AVFormatContext *s) } else { opar->codec_tag = 0; } - st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; - st->time_base = s->streams[i]->time_base; - st->avg_frame_rate = s->streams[i]->avg_frame_rate; + st->sample_aspect_ratio = ist->sample_aspect_ratio; + st->time_base = ist->time_base; + st->avg_frame_rate = ist->avg_frame_rate; + st->disposition = ist->disposition; #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS - if (s->streams[i]->codecpar->codec_tag == MKTAG('t','m','c','d')) - st->codec->time_base = s->streams[i]->codec->time_base; + if (ipar->codec_tag == MKTAG('t','m','c','d')) + st->codec->time_base = ist->codec->time_base; FF_ENABLE_DEPRECATION_WARNINGS #endif - av_dict_copy(&st->metadata, s->streams[i]->metadata, 0); + av_dict_copy(&st->metadata, ist->metadata, 0); } return 0; @@ -873,7 +873,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EINVAL); if (!st->codecpar->extradata_size) { - int pkt_extradata_size = 0; + int pkt_extradata_size; uint8_t *pkt_extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &pkt_extradata_size); if (pkt_extradata && pkt_extradata_size > 0) { ret = ff_alloc_extradata(st->codecpar, pkt_extradata_size); diff --git a/chromium/third_party/ffmpeg/libavformat/sierravmd.c b/chromium/third_party/ffmpeg/libavformat/sierravmd.c index 531fc415316..40bcb779861 100644 --- a/chromium/third_party/ffmpeg/libavformat/sierravmd.c +++ b/chromium/third_party/ffmpeg/libavformat/sierravmd.c @@ -174,6 +174,8 @@ static int vmd_read_header(AVFormatContext *s) avpriv_set_pts_info(vst, 33, num, den); avpriv_set_pts_info(st, 33, num, den); } + if (!s->nb_streams) + return AVERROR_INVALIDDATA; toc_offset = AV_RL32(&vmd->vmd_header[812]); vmd->frame_count = AV_RL16(&vmd->vmd_header[6]); @@ -241,6 +243,8 @@ static int vmd_read_header(AVFormatContext *s) current_audio_pts++; break; case 2: /* Video Chunk */ + if (!vst) + break; vmd->frame_table[total_frames].frame_offset = current_offset; vmd->frame_table[total_frames].stream_index = vmd->video_stream_index; vmd->frame_table[total_frames].frame_size = size; diff --git a/chromium/third_party/ffmpeg/libavformat/smacker.c b/chromium/third_party/ffmpeg/libavformat/smacker.c index 8b1e185817e..9966a670553 100644 --- a/chromium/third_party/ffmpeg/libavformat/smacker.c +++ b/chromium/third_party/ffmpeg/libavformat/smacker.c @@ -48,16 +48,17 @@ typedef struct SmackerContext { uint32_t *frm_size; uint8_t *frm_flags; /* internal variables */ + int64_t next_frame_pos; int cur_frame; + int videoindex; + int indexes[7]; + int duration_size[7]; /* current frame for demuxing */ + uint32_t frame_size; + int flags; + int next_audio_index; + int new_palette; uint8_t pal[768]; - int indexes[7]; - int videoindex; - uint8_t *bufs[7]; - int buf_sizes[7]; - int stream_id[7]; - int curstream; - int64_t nextpos; int64_t aud_pts[7]; } SmackerContext; @@ -197,6 +198,8 @@ static int smacker_read_header(AVFormatContext *s) if (par->bits_per_coded_sample == 16 && par->codec_id == AV_CODEC_ID_PCM_U8) par->codec_id = AV_CODEC_ID_PCM_S16LE; + else + smk->duration_size[i] = 4; avpriv_set_pts_info(ast, 64, 1, par->sample_rate * par->channels * par->bits_per_coded_sample / 8); } @@ -205,85 +208,75 @@ static int smacker_read_header(AVFormatContext *s) avio_rl32(pb); /* padding */ /* setup data */ - smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size)); - smk->frm_flags = av_malloc(smk->frames); - if (!smk->frm_size || !smk->frm_flags) { - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); + st->priv_data = av_malloc_array(smk->frames, sizeof(*smk->frm_size) + + sizeof(*smk->frm_flags)); + if (!st->priv_data) return AVERROR(ENOMEM); - } + smk->frm_size = st->priv_data; + smk->frm_flags = (void*)(smk->frm_size + smk->frames); /* read frame info */ for (i = 0; i < smk->frames; i++) { smk->frm_size[i] = avio_rl32(pb); } - for (i = 0; i < smk->frames; i++) { - smk->frm_flags[i] = avio_r8(pb); - } - - /* load trees to extradata, they will be unpacked by decoder */ - ret = avio_read(pb, par->extradata + 16, par->extradata_size - 16); - if (ret != par->extradata_size - 16) { - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); - return AVERROR(EIO); + if ((ret = ffio_read_size(pb, smk->frm_flags, smk->frames)) < 0 || + /* load trees to extradata, they will be unpacked by decoder */ + (ret = ffio_read_size(pb, par->extradata + 16, + par->extradata_size - 16)) < 0) { + return ret; } - smk->curstream = -1; - smk->nextpos = avio_tell(pb); - return 0; } - static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) { SmackerContext *smk = s->priv_data; int flags; int ret; - int i; - int frame_size = 0; - int palchange = 0; if (avio_feof(s->pb) || smk->cur_frame >= smk->frames) return AVERROR_EOF; /* if we demuxed all streams, pass another frame */ - if(smk->curstream < 0) { - avio_seek(s->pb, smk->nextpos, 0); - frame_size = smk->frm_size[smk->cur_frame] & (~3); + if (!smk->next_audio_index) { + smk->frame_size = smk->frm_size[smk->cur_frame] & (~3); + smk->next_frame_pos = avio_tell(s->pb) + smk->frame_size; flags = smk->frm_flags[smk->cur_frame]; + smk->flags = flags >> 1; /* handle palette change event */ - if(flags & SMACKER_PAL){ + if (flags & SMACKER_PAL) { int size, sz, t, off, j, pos; uint8_t *pal = smk->pal; uint8_t oldpal[768]; memcpy(oldpal, pal, 768); size = avio_r8(s->pb); - size = size * 4 - 1; - if(size + 1 > frame_size) - return AVERROR_INVALIDDATA; - frame_size -= size; - frame_size--; + size = size * 4; + if (size > smk->frame_size) { + ret = AVERROR_INVALIDDATA; + goto next_frame; + } + smk->frame_size -= size--; sz = 0; pos = avio_tell(s->pb) + size; - while(sz < 256){ + while (sz < 256) { t = avio_r8(s->pb); - if(t & 0x80){ /* skip palette entries */ - sz += (t & 0x7F) + 1; + if (t & 0x80) { /* skip palette entries */ + sz += (t & 0x7F) + 1; pal += ((t & 0x7F) + 1) * 3; - } else if(t & 0x40){ /* copy with offset */ + } else if (t & 0x40) { /* copy with offset */ off = avio_r8(s->pb); j = (t & 0x3F) + 1; if (off + j > 0x100) { av_log(s, AV_LOG_ERROR, "Invalid palette update, offset=%d length=%d extends beyond palette size\n", off, j); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto next_frame; } off *= 3; - while(j-- && sz < 256) { + while (j-- && sz < 256) { *pal++ = oldpal[off + 0]; *pal++ = oldpal[off + 1]; *pal++ = oldpal[off + 2]; @@ -298,77 +291,97 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) } } avio_seek(s->pb, pos, 0); - palchange |= 1; + smk->new_palette = 1; } - flags >>= 1; - smk->curstream = -1; - /* if audio chunks are present, put them to stack and retrieve later */ - for(i = 0; i < 7; i++) { - if(flags & 1) { - uint32_t size; - int err; - - size = avio_rl32(s->pb) - 4; - if (!size || size + 4LL > frame_size) { - av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); - return AVERROR_INVALIDDATA; - } - frame_size -= size; - frame_size -= 4; - smk->curstream++; - if ((err = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) { - smk->buf_sizes[smk->curstream] = 0; - return err; - } - smk->buf_sizes[smk->curstream] = size; - ret = avio_read(s->pb, smk->bufs[smk->curstream], size); - if(ret != size) - return AVERROR(EIO); - smk->stream_id[smk->curstream] = smk->indexes[i]; + } + + for (int i = smk->next_audio_index; i < 7; i++) { + if (smk->flags & (1 << i)) { + uint32_t size; + + size = avio_rl32(s->pb); + if ((int)size < 4 + smk->duration_size[i] || size > smk->frame_size) { + av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); + ret = AVERROR_INVALIDDATA; + goto next_frame; } - flags >>= 1; + smk->frame_size -= size; + size -= 4; + + if (smk->indexes[i] < 0 || + s->streams[smk->indexes[i]]->discard >= AVDISCARD_ALL) { + smk->aud_pts[i] += smk->duration_size[i] ? avio_rl32(s->pb) + : size; + avio_skip(s->pb, size - smk->duration_size[i]); + continue; + } + if ((ret = av_get_packet(s->pb, pkt, size)) != size) { + ret = ret < 0 ? ret : AVERROR_INVALIDDATA; + goto next_frame; + } + pkt->stream_index = smk->indexes[i]; + pkt->pts = smk->aud_pts[i]; + pkt->duration = smk->duration_size[i] ? AV_RL32(pkt->data) + : size; + smk->aud_pts[i] += pkt->duration; + smk->next_audio_index = i + 1; + return 0; } - if (frame_size < 0 || frame_size >= INT_MAX/2) - return AVERROR_INVALIDDATA; - if ((ret = av_new_packet(pkt, frame_size + 769)) < 0) - return ret; - if(smk->frm_size[smk->cur_frame] & 1) - palchange |= 2; - pkt->data[0] = palchange; - memcpy(pkt->data + 1, smk->pal, 768); - ret = avio_read(s->pb, pkt->data + 769, frame_size); - if(ret != frame_size) - return AVERROR(EIO); - pkt->stream_index = smk->videoindex; - pkt->pts = smk->cur_frame; - pkt->size = ret + 769; - smk->cur_frame++; - smk->nextpos = avio_tell(s->pb); - } else { - if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream]) - return AVERROR_INVALIDDATA; - if ((ret = av_new_packet(pkt, smk->buf_sizes[smk->curstream])) < 0) - return ret; - memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); - pkt->size = smk->buf_sizes[smk->curstream]; - pkt->stream_index = smk->stream_id[smk->curstream]; - pkt->pts = smk->aud_pts[smk->curstream]; - smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); - smk->curstream--; } + if (s->streams[smk->videoindex]->discard >= AVDISCARD_ALL) { + ret = FFERROR_REDO; + goto next_frame; + } + if (smk->frame_size >= INT_MAX/2) { + ret = AVERROR_INVALIDDATA; + goto next_frame; + } + if ((ret = av_new_packet(pkt, smk->frame_size + 769)) < 0) + goto next_frame; + flags = smk->new_palette; + if (smk->frm_size[smk->cur_frame] & 1) + flags |= 2; + pkt->data[0] = flags; + memcpy(pkt->data + 1, smk->pal, 768); + ret = ffio_read_size(s->pb, pkt->data + 769, smk->frame_size); + if (ret < 0) + goto next_frame; + pkt->stream_index = smk->videoindex; + pkt->pts = smk->cur_frame; + smk->next_audio_index = 0; + smk->new_palette = 0; + smk->cur_frame++; + return 0; +next_frame: + avio_seek(s->pb, smk->next_frame_pos, SEEK_SET); + smk->next_audio_index = 0; + smk->cur_frame++; + return ret; } -static int smacker_read_close(AVFormatContext *s) +static int smacker_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) { SmackerContext *smk = s->priv_data; - int i; + int64_t ret; + + /* only rewinding to start is supported */ + if (timestamp != 0) { + av_log(s, AV_LOG_ERROR, + "Random seeks are not supported (can only seek to start).\n"); + return AVERROR(EINVAL); + } + + if ((ret = avio_seek(s->pb, s->internal->data_offset, SEEK_SET)) < 0) + return ret; - for(i = 0; i < 7; i++) - av_freep(&smk->bufs[i]); - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); + smk->cur_frame = 0; + smk->next_audio_index = 0; + smk->new_palette = 0; + memset(smk->pal, 0, sizeof(smk->pal)); + memset(smk->aud_pts, 0, sizeof(smk->aud_pts)); return 0; } @@ -380,5 +393,5 @@ AVInputFormat ff_smacker_demuxer = { .read_probe = smacker_probe, .read_header = smacker_read_header, .read_packet = smacker_read_packet, - .read_close = smacker_read_close, + .read_seek = smacker_read_seek, }; diff --git a/chromium/third_party/ffmpeg/libavformat/smjpegdec.c b/chromium/third_party/ffmpeg/libavformat/smjpegdec.c index 5bc04921fe0..a4e1f957ed8 100644 --- a/chromium/third_party/ffmpeg/libavformat/smjpegdec.c +++ b/chromium/third_party/ffmpeg/libavformat/smjpegdec.c @@ -51,6 +51,9 @@ static int smjpeg_read_header(AVFormatContext *s) uint32_t version, htype, hlength, duration; char *comment; + sc->audio_stream_index = + sc->video_stream_index = -1; + avio_skip(pb, 8); // magic version = avio_rb32(pb); if (version) @@ -147,6 +150,8 @@ static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) dtype = avio_rl32(s->pb); switch (dtype) { case SMJPEG_SNDD: + if (sc->audio_stream_index < 0) + return AVERROR_INVALIDDATA; timestamp = avio_rb32(s->pb); size = avio_rb32(s->pb); ret = av_get_packet(s->pb, pkt, size); @@ -155,6 +160,8 @@ static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pos = pos; break; case SMJPEG_VIDD: + if (sc->video_stream_index < 0) + return AVERROR_INVALIDDATA; timestamp = avio_rb32(s->pb); size = avio_rb32(s->pb); ret = av_get_packet(s->pb, pkt, size); diff --git a/chromium/third_party/ffmpeg/libavformat/smoothstreamingenc.c b/chromium/third_party/ffmpeg/libavformat/smoothstreamingenc.c index 0e4f531f90d..ba5cc27ca01 100644 --- a/chromium/third_party/ffmpeg/libavformat/smoothstreamingenc.c +++ b/chromium/third_party/ffmpeg/libavformat/smoothstreamingenc.c @@ -49,7 +49,6 @@ typedef struct Fragment { typedef struct OutputStream { AVFormatContext *ctx; - int ctx_inited; char dirname[1024]; uint8_t iobuf[32768]; URLContext *out; // Current output stream where all output is written @@ -99,14 +98,9 @@ static int64_t ism_seek(void *opaque, int64_t offset, int whence) if (whence != SEEK_SET) return AVERROR(ENOSYS); if (os->tail_out) { - if (os->out) { - ffurl_close(os->out); - } - if (os->out2) { - ffurl_close(os->out2); - } + ffurl_closep(&os->out); + ffurl_closep(&os->out2); os->out = os->tail_out; - os->out2 = NULL; os->tail_out = NULL; } if (offset >= os->cur_start_pos) { @@ -175,12 +169,9 @@ static void ism_free(AVFormatContext *s) return; for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - ffurl_close(os->out); - ffurl_close(os->out2); - ffurl_close(os->tail_out); - os->out = os->out2 = os->tail_out = NULL; - if (os->ctx && os->ctx_inited) - av_write_trailer(os->ctx); + ffurl_closep(&os->out); + ffurl_closep(&os->out2); + ffurl_closep(&os->tail_out); if (os->ctx && os->ctx->pb) avio_context_free(&os->ctx->pb); avformat_free_context(os->ctx); @@ -295,21 +286,18 @@ static int ism_write_header(AVFormatContext *s) ff_const59 AVOutputFormat *oformat; if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { - ret = AVERROR(errno); av_log(s, AV_LOG_ERROR, "mkdir failed\n"); - goto fail; + return AVERROR(errno); } oformat = av_guess_format("ismv", NULL, NULL); if (!oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; + return AVERROR_MUXER_NOT_FOUND; } c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams)); if (!c->streams) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } for (i = 0; i < s->nb_streams; i++) { @@ -327,22 +315,21 @@ static int ism_write_header(AVFormatContext *s) } if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) { - ret = AVERROR(errno); av_log(s, AV_LOG_ERROR, "mkdir failed\n"); - goto fail; + return AVERROR(errno); } os->ctx = ctx = avformat_alloc_context(); - if (!ctx || ff_copy_whiteblacklists(ctx, s) < 0) { - ret = AVERROR(ENOMEM); - goto fail; + if (!ctx) { + return AVERROR(ENOMEM); } + if ((ret = ff_copy_whiteblacklists(ctx, s)) < 0) + return ret; ctx->oformat = oformat; ctx->interrupt_callback = s->interrupt_callback; if (!(st = avformat_new_stream(ctx, NULL))) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; @@ -350,8 +337,7 @@ static int ism_write_header(AVFormatContext *s) ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, ism_write, ism_seek); if (!ctx->pb) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } av_dict_set_int(&opts, "ism_lookahead", c->lookahead_count, 0); @@ -359,9 +345,8 @@ static int ism_write_header(AVFormatContext *s) ret = avformat_write_header(ctx, &opts); av_dict_free(&opts); if (ret < 0) { - goto fail; + return ret; } - os->ctx_inited = 1; avio_flush(ctx->pb); s->streams[i]->time_base = st->time_base; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -373,8 +358,7 @@ static int ism_write_header(AVFormatContext *s) os->fourcc = "WVC1"; } else { av_log(s, AV_LOG_ERROR, "Unsupported video codec\n"); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } } else { c->has_audio = 1; @@ -387,8 +371,7 @@ static int ism_write_header(AVFormatContext *s) os->audio_tag = 0x0162; } else { av_log(s, AV_LOG_ERROR, "Unsupported audio codec\n"); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } os->packet_size = st->codecpar->block_align ? st->codecpar->block_align : 4; } @@ -397,15 +380,13 @@ static int ism_write_header(AVFormatContext *s) if (!c->has_video && c->min_frag_duration <= 0) { av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n"); - ret = AVERROR(EINVAL); - goto fail; + return AVERROR(EINVAL); } ret = write_manifest(s, 0); + if (ret < 0) + return ret; -fail: - if (ret) - ism_free(s); - return ret; + return 0; } static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size) @@ -464,7 +445,7 @@ static int add_fragment(OutputStream *os, const char *file, const char *infofile Fragment *frag; if (os->nb_fragments >= os->fragments_size) { os->fragments_size = (os->fragments_size + 1) * 2; - if ((err = av_reallocp(&os->fragments, sizeof(*os->fragments) * + if ((err = av_reallocp_array(&os->fragments, sizeof(*os->fragments), os->fragments_size)) < 0) { os->fragments_size = 0; os->nb_fragments = 0; @@ -537,8 +518,7 @@ static int ism_flush(AVFormatContext *s, int final) if (!os->out || os->tail_out) return AVERROR(EIO); - ffurl_close(os->out); - os->out = NULL; + ffurl_closep(&os->out); size = os->tail_pos - os->cur_start_pos; if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0) break; @@ -635,7 +615,6 @@ static int ism_write_trailer(AVFormatContext *s) rmdir(s->url); } - ism_free(s); return 0; } @@ -668,5 +647,6 @@ AVOutputFormat ff_smoothstreaming_muxer = { .write_header = ism_write_header, .write_packet = ism_write_packet, .write_trailer = ism_write_trailer, + .deinit = ism_free, .priv_class = &ism_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/srtdec.c b/chromium/third_party/ffmpeg/libavformat/srtdec.c index 40d324b44d1..d6ff00ba6d3 100644 --- a/chromium/third_party/ffmpeg/libavformat/srtdec.c +++ b/chromium/third_party/ffmpeg/libavformat/srtdec.c @@ -207,6 +207,8 @@ static int srt_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &srt->q); end: + if (res < 0) + ff_subtitles_queue_clean(&srt->q); av_bprint_finalize(&buf, NULL); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/srtpproto.c b/chromium/third_party/ffmpeg/libavformat/srtpproto.c index 5e6e5164d75..13e2245015f 100644 --- a/chromium/third_party/ffmpeg/libavformat/srtpproto.c +++ b/chromium/third_party/ffmpeg/libavformat/srtpproto.c @@ -59,8 +59,7 @@ static int srtp_close(URLContext *h) SRTPProtoContext *s = h->priv_data; ff_srtp_free(&s->srtp_out); ff_srtp_free(&s->srtp_in); - ffurl_close(s->rtp_hd); - s->rtp_hd = NULL; + ffurl_closep(&s->rtp_hd); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/stldec.c b/chromium/third_party/ffmpeg/libavformat/stldec.c index d6e0713f8c1..fb67407ac56 100644 --- a/chromium/third_party/ffmpeg/libavformat/stldec.c +++ b/chromium/third_party/ffmpeg/libavformat/stldec.c @@ -97,8 +97,10 @@ static int stl_read_header(AVFormatContext *s) if (pts_start != AV_NOPTS_VALUE) { AVPacket *sub; sub = ff_subtitles_queue_insert(&stl->q, p, strlen(p), 0); - if (!sub) + if (!sub) { + ff_subtitles_queue_clean(&stl->q); return AVERROR(ENOMEM); + } sub->pos = pos; sub->pts = pts_start; sub->duration = duration; diff --git a/chromium/third_party/ffmpeg/libavformat/subfile.c b/chromium/third_party/ffmpeg/libavformat/subfile.c index 5d8659c8c42..300672e657d 100644 --- a/chromium/third_party/ffmpeg/libavformat/subfile.c +++ b/chromium/third_party/ffmpeg/libavformat/subfile.c @@ -86,7 +86,7 @@ static int subfile_open(URLContext *h, const char *filename, int flags, return ret; c->pos = c->start; if ((ret = slave_seek(h)) < 0) { - ffurl_close(c->h); + ffurl_closep(&c->h); return ret; } return 0; @@ -95,7 +95,7 @@ static int subfile_open(URLContext *h, const char *filename, int flags, static int subfile_close(URLContext *h) { SubfileContext *c = h->priv_data; - return ffurl_close(c->h); + return ffurl_closep(&c->h); } static int subfile_read(URLContext *h, unsigned char *buf, int size) diff --git a/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c b/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c index 1360d9b7d9e..f2eee294a1c 100644 --- a/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c +++ b/chromium/third_party/ffmpeg/libavformat/subviewer1dec.c @@ -77,8 +77,10 @@ static int subviewer1_read_header(AVFormatContext *s) sub->duration = pts_start - sub->pts; } else { sub = ff_subtitles_queue_insert(&subviewer1->q, line, len, 0); - if (!sub) + if (!sub) { + ff_subtitles_queue_clean(&subviewer1->q); return AVERROR(ENOMEM); + } sub->pos = pos; sub->pts = pts_start; sub->duration = -1; diff --git a/chromium/third_party/ffmpeg/libavformat/subviewerdec.c b/chromium/third_party/ffmpeg/libavformat/subviewerdec.c index 83378eab5f9..fdca3a48205 100644 --- a/chromium/third_party/ffmpeg/libavformat/subviewerdec.c +++ b/chromium/third_party/ffmpeg/libavformat/subviewerdec.c @@ -172,6 +172,8 @@ static int subviewer_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &subviewer->q); end: + if (res < 0) + ff_subtitles_queue_clean(&subviewer->q); av_bprint_finalize(&header, NULL); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/swfenc.c b/chromium/third_party/ffmpeg/libavformat/swfenc.c index 84f924eda52..9da4aad9597 100644 --- a/chromium/third_party/ffmpeg/libavformat/swfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/swfenc.c @@ -256,7 +256,7 @@ static int swf_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Invalid (too large) frame rate %d/%d\n", rate, rate_base); return AVERROR(EINVAL); } - avio_wl16(pb, (rate * 256) / rate_base); /* frame rate */ + avio_wl16(pb, (rate * 256LL) / rate_base); /* frame rate */ swf->duration_pos = avio_tell(pb); avio_wl16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ diff --git a/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c b/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c index 5572bfd9316..3255819e77c 100644 --- a/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/tedcaptionsdec.c @@ -275,10 +275,13 @@ static int parse_file(AVIOContext *pb, FFDemuxSubtitlesQueue *subs) static av_cold int tedcaptions_read_header(AVFormatContext *avf) { TEDCaptionsDemuxer *tc = avf->priv_data; - AVStream *st; + AVStream *st = avformat_new_stream(avf, NULL); int ret, i; AVPacket *last; + if (!st) + return AVERROR(ENOMEM); + ret = parse_file(avf->pb, &tc->subs); if (ret < 0) { if (ret == AVERROR_INVALIDDATA) @@ -292,9 +295,6 @@ static av_cold int tedcaptions_read_header(AVFormatContext *avf) tc->subs.subs[i].pts += tc->start_time; last = &tc->subs.subs[tc->subs.nb_subs - 1]; - st = avformat_new_stream(avf, NULL); - if (!st) - return AVERROR(ENOMEM); st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_TEXT; avpriv_set_pts_info(st, 64, 1, 1000); diff --git a/chromium/third_party/ffmpeg/libavformat/tee.c b/chromium/third_party/ffmpeg/libavformat/tee.c index f2b11fcb359..c5c59975e6b 100644 --- a/chromium/third_party/ffmpeg/libavformat/tee.c +++ b/chromium/third_party/ffmpeg/libavformat/tee.c @@ -295,7 +295,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) goto end; } - ret = ff_format_output_open(avf2, filename, NULL); + ret = ff_format_output_open(avf2, filename, &options); if (ret < 0) { av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave, av_err2str(ret)); diff --git a/chromium/third_party/ffmpeg/libavformat/thp.c b/chromium/third_party/ffmpeg/libavformat/thp.c index 332ed791284..bcc3febaa19 100644 --- a/chromium/third_party/ffmpeg/libavformat/thp.c +++ b/chromium/third_party/ffmpeg/libavformat/thp.c @@ -75,6 +75,8 @@ static int thp_read_header(AVFormatContext *s) avio_rb32(pb); /* Max samples. */ thp->fps = av_d2q(av_int2float(avio_rb32(pb)), INT_MAX); + if (thp->fps.den <= 0 || thp->fps.num < 0) + return AVERROR_INVALIDDATA; thp->framecnt = avio_rb32(pb); thp->first_framesz = avio_rb32(pb); pb->maxsize = avio_rb32(pb); @@ -93,6 +95,9 @@ static int thp_read_header(AVFormatContext *s) avio_seek (pb, thp->compoff, SEEK_SET); thp->compcount = avio_rb32(pb); + if (thp->compcount > FF_ARRAY_ELEMS(thp->components)) + return AVERROR_INVALIDDATA; + /* Read the list of component types. */ avio_read(pb, thp->components, 16); @@ -145,6 +150,9 @@ static int thp_read_header(AVFormatContext *s) } } + if (!thp->vst) + return AVERROR_INVALIDDATA; + return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c b/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c index e41156cc30e..0c4ef34f5fc 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_gnutls.c @@ -100,8 +100,7 @@ static int tls_close(URLContext *h) gnutls_deinit(c->session); if (c->cred) gnutls_certificate_free_credentials(c->cred); - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); + ffurl_closep(&c->tls_shared.tcp); ff_gnutls_deinit(); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/tls_libtls.c b/chromium/third_party/ffmpeg/libavformat/tls_libtls.c index ba83b56ffe2..dff7f2d9fb4 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_libtls.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_libtls.c @@ -44,8 +44,7 @@ static int ff_tls_close(URLContext *h) tls_close(p->ctx); tls_free(p->ctx); } - if (p->tls_shared.tcp) - ffurl_close(p->tls_shared.tcp); + ffurl_closep(&p->tls_shared.tcp); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/tls_openssl.c b/chromium/third_party/ffmpeg/libavformat/tls_openssl.c index e305b2465a0..002197fa76d 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_openssl.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_openssl.c @@ -142,8 +142,7 @@ static int tls_close(URLContext *h) } if (c->ctx) SSL_CTX_free(c->ctx); - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); + ffurl_closep(&c->tls_shared.tcp); #if OPENSSL_VERSION_NUMBER >= 0x1010000fL if (c->url_bio_method) BIO_meth_free(c->url_bio_method); diff --git a/chromium/third_party/ffmpeg/libavformat/tls_schannel.c b/chromium/third_party/ffmpeg/libavformat/tls_schannel.c index 4f0badcb8dd..4bfaa852284 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_schannel.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_schannel.c @@ -138,8 +138,7 @@ static int tls_close(URLContext *h) av_freep(&c->dec_buf); c->dec_buf_size = c->dec_buf_offset = 0; - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); + ffurl_closep(&c->tls_shared.tcp); return 0; } @@ -392,7 +391,12 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) int size, ret; int min_enc_buf_size = len + SCHANNEL_FREE_BUFFER_SIZE; - if (len <= c->dec_buf_offset) + /* If we have some left-over data from previous network activity, + * return it first in case it is enough. It may contain + * data that is required to know whether this connection + * is still required or not, esp. in case of HTTP keep-alive + * connections. */ + if (c->dec_buf_offset > 0) goto cleanup; if (c->sspi_close_notify) @@ -424,7 +428,7 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) c->enc_buf_offset += ret; } - while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK && c->dec_buf_offset < len) { + while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK) { /* input buffer */ init_sec_buffer(&inbuf[0], SECBUFFER_DATA, c->enc_buf, c->enc_buf_offset); diff --git a/chromium/third_party/ffmpeg/libavformat/tls_securetransport.c b/chromium/third_party/ffmpeg/libavformat/tls_securetransport.c index 37380541b11..3250b230517 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls_securetransport.c +++ b/chromium/third_party/ffmpeg/libavformat/tls_securetransport.c @@ -251,8 +251,7 @@ static int tls_close(URLContext *h) } if (c->ca_array) CFRelease(c->ca_array); - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); + ffurl_closep(&c->tls_shared.tcp); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/ttaenc.c b/chromium/third_party/ffmpeg/libavformat/ttaenc.c index 4860aab4c13..becd3e71536 100644 --- a/chromium/third_party/ffmpeg/libavformat/ttaenc.c +++ b/chromium/third_party/ffmpeg/libavformat/ttaenc.c @@ -145,10 +145,8 @@ static int tta_write_trailer(AVFormatContext *s) /* Write Seek table */ crc = ffio_get_checksum(tta->seek_table) ^ UINT32_MAX; avio_wl32(tta->seek_table, crc); - size = avio_close_dyn_buf(tta->seek_table, &ptr); + size = avio_get_dyn_buf(tta->seek_table, &ptr); avio_write(s->pb, ptr, size); - tta->seek_table = NULL; - av_free(ptr); /* Write audio data */ tta_queue_flush(s); diff --git a/chromium/third_party/ffmpeg/libavformat/ty.c b/chromium/third_party/ffmpeg/libavformat/ty.c index 738a22e7de6..c8e1067c0e8 100644 --- a/chromium/third_party/ffmpeg/libavformat/ty.c +++ b/chromium/third_party/ffmpeg/libavformat/ty.c @@ -72,11 +72,6 @@ typedef enum { TIVO_AUDIO_MPEG } TiVo_audio; -typedef struct TySeqTable { - uint64_t timestamp; - uint8_t chunk_bitmask[8]; -} TySeqTable; - typedef struct TYDemuxContext { unsigned cur_chunk; unsigned cur_chunk_pos; @@ -90,7 +85,6 @@ typedef struct TYDemuxContext { int pes_buf_cnt; /* how many bytes in our buffer */ size_t ac3_pkt_size; /* length of ac3 pkt we've seen so far */ uint64_t last_ty_pts; /* last TY timestamp we've seen */ - unsigned seq_table_size; /* number of entries in SEQ table */ int64_t first_audio_pts; int64_t last_audio_pts; @@ -99,8 +93,6 @@ typedef struct TYDemuxContext { TyRecHdr *rec_hdrs; /* record headers array */ int cur_rec; /* current record in this chunk */ int num_recs; /* number of recs in this chunk */ - int seq_rec; /* record number where seq start is */ - TySeqTable *seq_table; /* table of SEQ entries from mstr chk */ int first_chunk; uint8_t chunk[CHUNK_SIZE]; @@ -339,58 +331,6 @@ static int ty_read_header(AVFormatContext *s) return 0; } -/* parse a master chunk, filling the SEQ table and other variables. - * We assume the stream is currently pointing to it. - */ -static void parse_master(AVFormatContext *s) -{ - TYDemuxContext *ty = s->priv_data; - unsigned map_size; /* size of bitmask, in bytes */ - unsigned i, j; - - /* Note that the entries in the SEQ table in the stream may have - different sizes depending on the bits per entry. We store them - all in the same size structure, so we have to parse them out one - by one. If we had a dynamic structure, we could simply read the - entire table directly from the stream into memory in place. */ - - /* clear the SEQ table */ - av_freep(&ty->seq_table); - - /* parse header info */ - - map_size = AV_RB32(ty->chunk + 20); /* size of bitmask, in bytes */ - i = AV_RB32(ty->chunk + 28); /* size of SEQ table, in bytes */ - - ty->seq_table_size = i / (8LL + map_size); - - if (ty->seq_table_size == 0) { - ty->seq_table = NULL; - return; - } - - /* parse all the entries */ - ty->seq_table = av_calloc(ty->seq_table_size, sizeof(TySeqTable)); - if (ty->seq_table == NULL) { - ty->seq_table_size = 0; - return; - } - - ty->cur_chunk_pos = 32; - for (j = 0; j < ty->seq_table_size; j++) { - if (ty->cur_chunk_pos >= CHUNK_SIZE - 8) - return; - ty->seq_table[j].timestamp = AV_RB64(ty->chunk + ty->cur_chunk_pos); - ty->cur_chunk_pos += 8; - if (map_size > 8) { - av_log(s, AV_LOG_ERROR, "Unsupported SEQ bitmap size in master chunk.\n"); - ty->cur_chunk_pos += map_size; - } else { - memcpy(ty->seq_table[j].chunk_bitmask, ty->chunk + ty->cur_chunk_pos, map_size); - } - } -} - static int get_chunk(AVFormatContext *s) { TYDemuxContext *ty = s->priv_data; @@ -413,7 +353,7 @@ static int get_chunk(AVFormatContext *s) /* check if it's a PART Header */ if (AV_RB32(ty->chunk) == TIVO_PES_FILEID) { - parse_master(s); /* parse master chunk */ + /* skip master chunk and read new chunk */ return get_chunk(s); } @@ -421,14 +361,9 @@ static int get_chunk(AVFormatContext *s) if (ty->chunk[3] & 0x80) { /* 16 bit rec cnt */ ty->num_recs = num_recs = (ty->chunk[1] << 8) + ty->chunk[0]; - ty->seq_rec = (ty->chunk[3] << 8) + ty->chunk[2]; - if (ty->seq_rec != 0xffff) { - ty->seq_rec &= ~0x8000; - } } else { /* 8 bit reclen - TiVo 1.3 format */ ty->num_recs = num_recs = ty->chunk[0]; - ty->seq_rec = ty->chunk[1]; } ty->cur_rec = 0; ty->first_chunk = 0; @@ -770,7 +705,6 @@ static int ty_read_close(AVFormatContext *s) { TYDemuxContext *ty = s->priv_data; - av_freep(&ty->seq_table); av_freep(&ty->rec_hdrs); return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/udp.c b/chromium/third_party/ffmpeg/libavformat/udp.c index ad6992c57db..30d80414337 100644 --- a/chromium/third_party/ffmpeg/libavformat/udp.c +++ b/chromium/third_party/ffmpeg/libavformat/udp.c @@ -852,7 +852,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) goto fail; } } else { - /* set udp recv buffer size to the requested value (default 64K) */ + /* set udp recv buffer size to the requested value (default UDP_RX_BUF_SIZE) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { ff_log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); diff --git a/chromium/third_party/ffmpeg/libavformat/url.c b/chromium/third_party/ffmpeg/libavformat/url.c index 596fb49cfcf..3c858f0257c 100644 --- a/chromium/third_party/ffmpeg/libavformat/url.c +++ b/chromium/third_party/ffmpeg/libavformat/url.c @@ -21,11 +21,13 @@ #include "avformat.h" +#include "internal.h" #include "config.h" #include "url.h" #if CONFIG_NETWORK #include "network.h" #endif +#include "libavutil/avassert.h" #include "libavutil/avstring.h" /** @@ -77,73 +79,219 @@ int ff_url_join(char *str, int size, const char *proto, return strlen(str); } -void ff_make_absolute_url(char *buf, int size, const char *base, - const char *rel) +static const char *find_delim(const char *delim, const char *cur, const char *end) { - char *sep, *path_query; - /* Absolute path, relative to the current server */ - if (base && strstr(base, "://") && rel[0] == '/') { - if (base != buf) - av_strlcpy(buf, base, size); - sep = strstr(buf, "://"); - if (sep) { - /* Take scheme from base url */ - if (rel[1] == '/') { - sep[1] = '\0'; - } else { - /* Take scheme and host from base url */ - sep += 3; - sep = strchr(sep, '/'); - if (sep) - *sep = '\0'; - } + while (cur < end && !strchr(delim, *cur)) + cur++; + return cur; +} + +int ff_url_decompose(URLComponents *uc, const char *url, const char *end) +{ + const char *cur, *aend, *p; + + av_assert0(url); + if (!end) + end = url + strlen(url); + cur = uc->url = url; + + /* scheme */ + uc->scheme = cur; + p = find_delim(":/", cur, end); /* lavf "schemes" can contain options */ + if (*p == ':') + cur = p + 1; + + /* authority */ + uc->authority = cur; + if (end - cur >= 2 && cur[0] == '/' && cur[1] == '/') { + cur += 2; + aend = find_delim("/?#", cur, end); + + /* userinfo */ + uc->userinfo = cur; + p = find_delim("@", cur, aend); + if (*p == '@') + cur = p + 1; + + /* host */ + uc->host = cur; + if (*cur == '[') { /* hello IPv6, thanks for using colons! */ + p = find_delim("]", cur, aend); + if (*p != ']') + return AVERROR(EINVAL); + if (p + 1 < aend && p[1] != ':') + return AVERROR(EINVAL); + cur = p + 1; + } else { + cur = find_delim(":", cur, aend); } - av_strlcat(buf, rel, size); - return; + + /* port */ + uc->port = cur; + cur = aend; + } else { + uc->userinfo = uc->host = uc->port = cur; } - /* If rel actually is an absolute url, just copy it */ - if (!base || strstr(rel, "://") || rel[0] == '/') { - av_strlcpy(buf, rel, size); - return; + + /* path */ + uc->path = cur; + cur = find_delim("?#", cur, end); + + /* query */ + uc->query = cur; + if (*cur == '?') + cur = find_delim("#", cur, end); + + /* fragment */ + uc->fragment = cur; + + uc->end = end; + return 0; +} + +static int append_path(char *root, char *out_end, char **rout, + const char *in, const char *in_end) +{ + char *out = *rout; + const char *d, *next; + + if (in < in_end && *in == '/') + in++; /* already taken care of */ + while (in < in_end) { + d = find_delim("/", in, in_end); + next = d + (d < in_end && *d == '/'); + if (d - in == 1 && in[0] == '.') { + /* skip */ + } else if (d - in == 2 && in[0] == '.' && in[1] == '.') { + av_assert1(out[-1] == '/'); + if (out - root > 1) + while (out > root && (--out)[-1] != '/'); + } else { + if (out_end - out < next - in) + return AVERROR(ENOMEM); + memmove(out, in, next - in); + out += next - in; + } + in = next; } - if (base != buf) - av_strlcpy(buf, base, size); - - /* Strip off any query string from base */ - path_query = strchr(buf, '?'); - if (path_query) - *path_query = '\0'; - - /* Is relative path just a new query part? */ - if (rel[0] == '?') { - av_strlcat(buf, rel, size); - return; + *rout = out; + return 0; +} + +int ff_make_absolute_url(char *buf, int size, const char *base, + const char *rel) +{ + URLComponents ub, uc; + char *out, *out_end, *path; + const char *keep, *base_path_end; + int use_base_path, simplify_path = 0, ret; + + /* This is tricky. + For HTTP, http://server/site/page + ../media/file + should resolve into http://server/media/file + but for filesystem access, dir/playlist + ../media/file + should resolve into dir/../media/file + because dir could be a symlink, and .. points to + the actual parent of the target directory. + + We'll consider that URLs with an actual scheme and authority, + i.e. starting with scheme://, need parent dir simplification, + while bare paths or pseudo-URLs starting with proto: without + the double slash do not. + + For real URLs, the processing is similar to the algorithm described + here: + https://tools.ietf.org/html/rfc3986#section-5 + */ + + if (!size) + return AVERROR(ENOMEM); + out = buf; + out_end = buf + size - 1; + + if (!base) + base = ""; + if ((ret = ff_url_decompose(&ub, base, NULL) < 0) || + (ret = ff_url_decompose(&uc, rel, NULL) < 0)) + goto error; + + keep = ub.url; +#define KEEP(component, also) do { \ + if (uc.url_component_end_##component == uc.url && \ + ub.url_component_end_##component > keep) { \ + keep = ub.url_component_end_##component; \ + also \ + } \ + } while (0) + KEEP(scheme, ); + KEEP(authority_full, simplify_path = 1;); + KEEP(path,); + KEEP(query,); + KEEP(fragment,); +#undef KEEP +#define COPY(start, end) do { \ + size_t len = end - start; \ + if (len > out_end - out) { \ + ret = AVERROR(ENOMEM); \ + goto error; \ + } \ + memmove(out, start, len); \ + out += len; \ + } while (0) + COPY(ub.url, keep); + COPY(uc.url, uc.path); + + use_base_path = URL_COMPONENT_HAVE(ub, path) && keep <= ub.path; + if (uc.path > uc.url) + use_base_path = 0; + if (URL_COMPONENT_HAVE(uc, path) && uc.path[0] == '/') + use_base_path = 0; + if (use_base_path) { + base_path_end = ub.url_component_end_path; + if (URL_COMPONENT_HAVE(uc, path)) + while (base_path_end > ub.path && base_path_end[-1] != '/') + base_path_end--; } + if (keep > ub.path) + simplify_path = 0; + if (URL_COMPONENT_HAVE(uc, scheme)) + simplify_path = 0; + if (URL_COMPONENT_HAVE(uc, authority)) + simplify_path = 1; + /* No path at all, leave it */ + if (!use_base_path && !URL_COMPONENT_HAVE(uc, path)) + simplify_path = 0; - /* Remove the file name from the base url */ - sep = strrchr(buf, '/'); - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - while (av_strstart(rel, "../", NULL) && sep) { - /* Remove the path delimiter at the end */ - sep[0] = '\0'; - sep = strrchr(buf, '/'); - /* If the next directory name to pop off is "..", break here */ - if (!strcmp(sep ? &sep[1] : buf, "..")) { - /* Readd the slash we just removed */ - av_strlcat(buf, "/", size); - break; + if (simplify_path) { + const char *root = "/"; + COPY(root, root + 1); + path = out; + if (use_base_path) { + ret = append_path(path, out_end, &out, ub.path, base_path_end); + if (ret < 0) + goto error; + } + if (URL_COMPONENT_HAVE(uc, path)) { + ret = append_path(path, out_end, &out, uc.path, uc.url_component_end_path); + if (ret < 0) + goto error; } - /* Cut off the directory name */ - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - rel += 3; + } else { + if (use_base_path) + COPY(ub.path, base_path_end); + COPY(uc.path, uc.url_component_end_path); } - av_strlcat(buf, rel, size); + + COPY(uc.url_component_end_path, uc.end); +#undef COPY + *out = 0; + return 0; + +error: + snprintf(buf, size, "invalid:%s", + ret == AVERROR(ENOMEM) ? "truncated" : + ret == AVERROR(EINVAL) ? "syntax_error" : ""); + return ret; } AVIODirEntry *ff_alloc_dir_entry(void) diff --git a/chromium/third_party/ffmpeg/libavformat/url.h b/chromium/third_party/ffmpeg/libavformat/url.h index 4750bfff825..e33edf0cb98 100644 --- a/chromium/third_party/ffmpeg/libavformat/url.h +++ b/chromium/third_party/ffmpeg/libavformat/url.h @@ -312,8 +312,8 @@ int ff_url_join(char *str, int size, const char *proto, * @param base the base url, may be equal to buf. * @param rel the new url, which is interpreted relative to base */ -void ff_make_absolute_url(char *buf, int size, const char *base, - const char *rel); +int ff_make_absolute_url(char *buf, int size, const char *base, + const char *rel); /** * Allocate directory entry with default values. @@ -322,7 +322,11 @@ void ff_make_absolute_url(char *buf, int size, const char *base, */ AVIODirEntry *ff_alloc_dir_entry(void); +#if FF_API_CHILD_CLASS_NEXT const AVClass *ff_urlcontext_child_class_next(const AVClass *prev); +#endif + +const AVClass *ff_urlcontext_child_class_iterate(void **iter); /** * Construct a list of protocols matching a given whitelist and/or blacklist. @@ -340,4 +344,45 @@ const AVClass *ff_urlcontext_child_class_next(const AVClass *prev); const URLProtocol **ffurl_get_protocols(const char *whitelist, const char *blacklist); +typedef struct URLComponents { + const char *url; /**< whole URL, for reference */ + const char *scheme; /**< possibly including lavf-specific options */ + const char *authority; /**< "//" if it is a real URL */ + const char *userinfo; /**< including final '@' if present */ + const char *host; + const char *port; /**< including initial ':' if present */ + const char *path; + const char *query; /**< including initial '?' if present */ + const char *fragment; /**< including initial '#' if present */ + const char *end; +} URLComponents; + +#define url_component_end_scheme authority +#define url_component_end_authority userinfo +#define url_component_end_userinfo host +#define url_component_end_host port +#define url_component_end_port path +#define url_component_end_path query +#define url_component_end_query fragment +#define url_component_end_fragment end +#define url_component_end_authority_full path + +#define URL_COMPONENT_HAVE(uc, component) \ + ((uc).url_component_end_##component > (uc).component) + +/** + * Parse an URL to find the components. + * + * Each component runs until the start of the next component, + * possibly including a mandatory delimiter. + * + * @param uc structure to fill with pointers to the components. + * @param url URL to parse. + * @param end end of the URL, or NULL to parse to the end of string. + * + * @return >= 0 for success or an AVERROR code, especially if the URL is + * malformed. + */ +int ff_url_decompose(URLComponents *uc, const char *url, const char *end); + #endif /* AVFORMAT_URL_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/utils.c b/chromium/third_party/ffmpeg/libavformat/utils.c index f3bea05cf49..7e2954bbb17 100644 --- a/chromium/third_party/ffmpeg/libavformat/utils.c +++ b/chromium/third_party/ffmpeg/libavformat/utils.c @@ -219,7 +219,7 @@ static const AVCodec *find_probe_decoder(AVFormatContext *s, const AVStream *st, const AVCodec *probe_codec = NULL; void *iter = NULL; while ((probe_codec = av_codec_iterate(&iter))) { - if (probe_codec->id == codec_id && + if (probe_codec->id == codec->id && av_codec_is_decoder(probe_codec) && !(probe_codec->capabilities & (AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_EXPERIMENTAL))) { return probe_codec; @@ -638,11 +638,11 @@ FF_ENABLE_DEPRECATION_WARNINGS if (id3v2_extra_meta) { if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || !strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) { - if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) + if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0) goto close; - if ((ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0) + if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) goto close; - if ((ret = ff_id3v2_parse_priv(s, &id3v2_extra_meta)) < 0) + if ((ret = ff_id3v2_parse_priv(s, id3v2_extra_meta)) < 0) goto close; } else av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n"); @@ -1011,7 +1011,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } -static int is_intra_only(enum AVCodecID id) +int ff_is_intra_only(enum AVCodecID id) { const AVCodecDescriptor *d = avcodec_descriptor_get(id); if (!d) @@ -1174,7 +1174,7 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, } static void update_initial_durations(AVFormatContext *s, AVStream *st, - int stream_index, int duration) + int stream_index, int64_t duration) { AVPacketList *pktl = s->internal->packet_buffer ? s->internal->packet_buffer : s->internal->parse_queue; int64_t cur_dts = RELATIVE_TS_BASE; @@ -1410,7 +1410,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), st->index, st->id); /* update flags */ - if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA || is_intra_only(st->codecpar->codec_id)) + if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA || ff_is_intra_only(st->codecpar->codec_id)) pkt->flags |= AV_PKT_FLAG_KEY; #if FF_API_CONVERGENCE_DURATION FF_DISABLE_DEPRECATION_WARNINGS @@ -2783,7 +2783,7 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) st = ic->streams[i]; if ( st->time_base.num <= INT64_MAX / ic->bit_rate && st->duration == AV_NOPTS_VALUE) { - duration = av_rescale(8 * filesize, st->time_base.den, + duration = av_rescale(filesize, 8LL * st->time_base.den, ic->bit_rate * (int64_t) st->time_base.num); st->duration = duration; @@ -2985,16 +2985,16 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->time_base.den) - av_log(ic, AV_LOG_TRACE, "stream %d: start_time: %0.3f duration: %0.3f\n", i, - (double) st->start_time * av_q2d(st->time_base), - (double) st->duration * av_q2d(st->time_base)); + av_log(ic, AV_LOG_TRACE, "stream %d: start_time: %s duration: %s\n", i, + av_ts2timestr(st->start_time, &st->time_base), + av_ts2timestr(st->duration, &st->time_base)); } av_log(ic, AV_LOG_TRACE, - "format: start_time: %0.3f duration: %0.3f (estimate from %s) bitrate=%"PRId64" kb/s\n", - (double) ic->start_time / AV_TIME_BASE, - (double) ic->duration / AV_TIME_BASE, - duration_estimate_name(ic->duration_estimation_method), - (int64_t)ic->bit_rate / 1000); + "format: start_time: %s duration: %s (estimate from %s) bitrate=%"PRId64" kb/s\n", + av_ts2timestr(ic->start_time, &AV_TIME_BASE_Q), + av_ts2timestr(ic->duration, &AV_TIME_BASE_Q), + duration_estimate_name(ic->duration_estimation_method), + (int64_t)ic->bit_rate / 1000); } } @@ -4133,8 +4133,8 @@ FF_ENABLE_DEPRECATION_WARNINGS avcodec_string(buf, sizeof(buf), st->internal->avctx, 0); av_log(ic, AV_LOG_WARNING, "Could not find codec parameters for stream %d (%s): %s\n" - "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n", - i, buf, errmsg); + "Consider increasing the value for the 'analyzeduration' (%"PRId64") and 'probesize' (%"PRId64") options\n", + i, buf, errmsg, ic->max_analyze_duration, ic->probesize); } else { ret = 0; } @@ -5508,6 +5508,8 @@ uint8_t *av_stream_get_side_data(const AVStream *st, return st->side_data[i].data; } } + if (size) + *size = 0; return NULL; } diff --git a/chromium/third_party/ffmpeg/libavformat/version.h b/chromium/third_party/ffmpeg/libavformat/version.h index 719cda6b980..aa309ecc773 100644 --- a/chromium/third_party/ffmpeg/libavformat/version.h +++ b/chromium/third_party/ffmpeg/libavformat/version.h @@ -32,8 +32,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 58 -#define LIBAVFORMAT_VERSION_MINOR 42 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 51 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/chromium/third_party/ffmpeg/libavformat/vividas.c b/chromium/third_party/ffmpeg/libavformat/vividas.c index 4f54a4302e1..36c007b0d26 100644 --- a/chromium/third_party/ffmpeg/libavformat/vividas.c +++ b/chromium/third_party/ffmpeg/libavformat/vividas.c @@ -432,19 +432,20 @@ static int track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *bu AVIOContext pb0, *pb = &pb0; int i; int64_t filesize = avio_size(s->pb); + uint64_t n_sb_blocks_tmp; ffio_init_context(pb, buf, size, 0, NULL, NULL, NULL, NULL); ffio_read_varlen(pb); // track_index_len avio_r8(pb); // 'c' - viv->n_sb_blocks = ffio_read_varlen(pb); - if (viv->n_sb_blocks < 0 || viv->n_sb_blocks > size / 2) - goto error; - viv->sb_blocks = av_calloc(viv->n_sb_blocks, sizeof(VIV_SB_block)); + n_sb_blocks_tmp = ffio_read_varlen(pb); + if (n_sb_blocks_tmp > size / 2) + return AVERROR_INVALIDDATA; + viv->sb_blocks = av_calloc(n_sb_blocks_tmp, sizeof(*viv->sb_blocks)); if (!viv->sb_blocks) { - viv->n_sb_blocks = 0; return AVERROR(ENOMEM); } + viv->n_sb_blocks = n_sb_blocks_tmp; off = 0; poff = 0; @@ -454,7 +455,7 @@ static int track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *bu uint64_t n_packets_tmp = ffio_read_varlen(pb); if (size_tmp > INT_MAX || n_packets_tmp > INT_MAX) - goto error; + return AVERROR_INVALIDDATA; viv->sb_blocks[i].byte_offset = off; viv->sb_blocks[i].packet_offset = poff; @@ -470,15 +471,13 @@ static int track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *bu } if (filesize > 0 && poff > filesize) - goto error; + return AVERROR_INVALIDDATA; viv->sb_entries = av_calloc(maxnp, sizeof(VIV_SB_entry)); + if (!viv->sb_entries) + return AVERROR(ENOMEM); return 0; -error: - viv->n_sb_blocks = 0; - av_freep(&viv->sb_blocks); - return AVERROR_INVALIDDATA; } static void load_sb_block(AVFormatContext *s, VividasDemuxContext *viv, unsigned expected_size) @@ -607,7 +606,7 @@ static int viv_read_header(AVFormatContext *s) ret = track_index(viv, s, buf, v); av_free(buf); if (ret < 0) - return ret; + goto fail; viv->sb_offset = avio_tell(pb); if (viv->n_sb_blocks > 0) { @@ -618,6 +617,9 @@ static int viv_read_header(AVFormatContext *s) } return 0; +fail: + av_freep(&viv->sb_blocks); + return ret; } static int viv_read_packet(AVFormatContext *s, @@ -646,7 +648,7 @@ static int viv_read_packet(AVFormatContext *s, pkt->stream_index = 1; astream = s->streams[pkt->stream_index]; - pkt->pts = av_rescale(viv->audio_sample, astream->time_base.den, astream->time_base.num) / astream->codecpar->sample_rate; + pkt->pts = av_rescale_q(viv->audio_sample, av_make_q(1, astream->codecpar->sample_rate), astream->time_base); viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codecpar->channels; pkt->flags |= AV_PKT_FLAG_KEY; viv->current_audio_subpacket++; diff --git a/chromium/third_party/ffmpeg/libavformat/vorbiscomment.c b/chromium/third_party/ffmpeg/libavformat/vorbiscomment.c index fb5c655a23f..a929634cc04 100644 --- a/chromium/third_party/ffmpeg/libavformat/vorbiscomment.c +++ b/chromium/third_party/ffmpeg/libavformat/vorbiscomment.c @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "avio.h" #include "avformat.h" #include "metadata.h" #include "vorbiscomment.h" -#include "libavcodec/bytestream.h" #include "libavutil/dict.h" /** @@ -38,7 +38,7 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = { { 0 } }; -int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string, +int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string, AVChapter **chapters, unsigned int nb_chapters) { int64_t len = 8; @@ -62,31 +62,31 @@ int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string, return len; } -int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, +int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, const char *vendor_string, AVChapter **chapters, unsigned int nb_chapters) { int cm_count = 0; - bytestream_put_le32(p, strlen(vendor_string)); - bytestream_put_buffer(p, vendor_string, strlen(vendor_string)); + avio_wl32(pb, strlen(vendor_string)); + avio_write(pb, vendor_string, strlen(vendor_string)); if (chapters && nb_chapters) { for (int i = 0; i < nb_chapters; i++) { cm_count += av_dict_count(chapters[i]->metadata) + 1; } } - if (*m) { - int count = av_dict_count(*m) + cm_count; + if (m) { + int count = av_dict_count(m) + cm_count; AVDictionaryEntry *tag = NULL; - bytestream_put_le32(p, count); - while ((tag = av_dict_get(*m, "", tag, AV_DICT_IGNORE_SUFFIX))) { + avio_wl32(pb, count); + while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { int64_t len1 = strlen(tag->key); int64_t len2 = strlen(tag->value); if (len1+1+len2 > UINT32_MAX) return AVERROR(EINVAL); - bytestream_put_le32(p, len1+1+len2); - bytestream_put_buffer(p, tag->key, len1); - bytestream_put_byte(p, '='); - bytestream_put_buffer(p, tag->value, len2); + avio_wl32(pb, len1 + 1 + len2); + avio_write(pb, tag->key, len1); + avio_w8(pb, '='); + avio_write(pb, tag->value, len2); } for (int i = 0; i < nb_chapters; i++) { AVChapter *chp = chapters[i]; @@ -101,11 +101,11 @@ int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, s = s % 60; snprintf(chapter_number, sizeof(chapter_number), "%03d", i); snprintf(chapter_time, sizeof(chapter_time), "%02d:%02d:%02d.%03d", h, m, s, ms); - bytestream_put_le32(p, 10+1+12); - bytestream_put_buffer(p, "CHAPTER", 7); - bytestream_put_buffer(p, chapter_number, 3); - bytestream_put_byte(p, '='); - bytestream_put_buffer(p, chapter_time, 12); + avio_wl32(pb, 10 + 1 + 12); + avio_write(pb, "CHAPTER", 7); + avio_write(pb, chapter_number, 3); + avio_w8(pb, '='); + avio_write(pb, chapter_time, 12); tag = NULL; while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { @@ -113,18 +113,18 @@ int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, int64_t len2 = strlen(tag->value); if (len1+1+len2+10 > UINT32_MAX) return AVERROR(EINVAL); - bytestream_put_le32(p, 10+len1+1+len2); - bytestream_put_buffer(p, "CHAPTER", 7); - bytestream_put_buffer(p, chapter_number, 3); + avio_wl32(pb, 10 + len1 + 1 + len2); + avio_write(pb, "CHAPTER", 7); + avio_write(pb, chapter_number, 3); if (!strcmp(tag->key, "title")) - bytestream_put_buffer(p, "NAME", 4); + avio_write(pb, "NAME", 4); else - bytestream_put_buffer(p, tag->key, len1); - bytestream_put_byte(p, '='); - bytestream_put_buffer(p, tag->value, len2); + avio_write(pb, tag->key, len1); + avio_w8(pb, '='); + avio_write(pb, tag->value, len2); } } } else - bytestream_put_le32(p, 0); + avio_wl32(pb, 0); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/vorbiscomment.h b/chromium/third_party/ffmpeg/libavformat/vorbiscomment.h index 4ff3dd6c278..7cacd0b2a09 100644 --- a/chromium/third_party/ffmpeg/libavformat/vorbiscomment.h +++ b/chromium/third_party/ffmpeg/libavformat/vorbiscomment.h @@ -34,22 +34,21 @@ * For no string, set to an empty string. * @return The length in bytes. */ -int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string, +int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string, AVChapter **chapters, unsigned int nb_chapters); /** - * Write a VorbisComment into a buffer. The buffer, p, must have enough - * data to hold the whole VorbisComment. The minimum size required can be - * obtained by passing the same AVDictionary and vendor_string to + * Write a VorbisComment into an AVIOContext. The output size can be obtained + * in advance by passing the same chapters, AVDictionary and vendor_string to * ff_vorbiscomment_length() * - * @param p The buffer in which to write. + * @param pb The AVIOContext to write the output. * @param m The metadata struct to write. * @param vendor_string The vendor string to write. * @param chapters The chapters to write. * @param nb_chapters The number of chapters to write. */ -int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, +int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, const char *vendor_string, AVChapter **chapters, unsigned int nb_chapters); diff --git a/chromium/third_party/ffmpeg/libavformat/vplayerdec.c b/chromium/third_party/ffmpeg/libavformat/vplayerdec.c index e3e7b4efb82..ca23ec76ac5 100644 --- a/chromium/third_party/ffmpeg/libavformat/vplayerdec.c +++ b/chromium/third_party/ffmpeg/libavformat/vplayerdec.c @@ -83,8 +83,10 @@ static int vplayer_read_header(AVFormatContext *s) AVPacket *sub; sub = ff_subtitles_queue_insert(&vplayer->q, p, strlen(p), 0); - if (!sub) + if (!sub) { + ff_subtitles_queue_clean(&vplayer->q); return AVERROR(ENOMEM); + } sub->pos = pos; sub->pts = pts_start; sub->duration = -1; diff --git a/chromium/third_party/ffmpeg/libavformat/wavdec.c b/chromium/third_party/ffmpeg/libavformat/wavdec.c index 3297f59a5f9..d6ae54f7218 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wavdec.c @@ -509,9 +509,9 @@ static int wav_read_header(AVFormatContext *s) ID3v2ExtraMeta *id3v2_extra_meta = NULL; ff_id3v2_read_dict(pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (id3v2_extra_meta) { - ff_id3v2_parse_apic(s, &id3v2_extra_meta); - ff_id3v2_parse_chapters(s, &id3v2_extra_meta); - ff_id3v2_parse_priv(s, &id3v2_extra_meta); + ff_id3v2_parse_apic(s, id3v2_extra_meta); + ff_id3v2_parse_chapters(s, id3v2_extra_meta); + ff_id3v2_parse_priv(s, id3v2_extra_meta); } ff_id3v2_free_extra_meta(&id3v2_extra_meta); } diff --git a/chromium/third_party/ffmpeg/libavformat/wavenc.c b/chromium/third_party/ffmpeg/libavformat/wavenc.c index f6f5710802d..1027f107eed 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavenc.c +++ b/chromium/third_party/ffmpeg/libavformat/wavenc.c @@ -434,10 +434,9 @@ static int wav_write_trailer(AVFormatContext *s) "Filesize %"PRId64" invalid for wav, output file will be broken\n", file_size); } - - number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration, - s->streams[0]->codecpar->sample_rate * (int64_t)s->streams[0]->time_base.num, - s->streams[0]->time_base.den); + number_of_samples = av_rescale_q(wav->maxpts - wav->minpts + wav->last_duration, + s->streams[0]->time_base, + av_make_q(1, s->streams[0]->codecpar->sample_rate)); if(s->streams[0]->codecpar->codec_tag != 0x01) { /* Update num_samps in fact chunk */ diff --git a/chromium/third_party/ffmpeg/libavformat/webm_chunk.c b/chromium/third_party/ffmpeg/libavformat/webm_chunk.c index 17495099756..f1bee5fa9ff 100644 --- a/chromium/third_party/ffmpeg/libavformat/webm_chunk.c +++ b/chromium/third_party/ffmpeg/libavformat/webm_chunk.c @@ -44,6 +44,7 @@ typedef struct WebMChunkContext { uint64_t duration_written; int64_t prev_pts; AVFormatContext *avf; + int header_written; } WebMChunkContext; static int webm_chunk_init(AVFormatContext *s) @@ -101,6 +102,15 @@ static int webm_chunk_init(AVFormatContext *s) avpriv_set_pts_info(st, ost->pts_wrap_bits, ost->time_base.num, ost->time_base.den); + if (wc->http_method) + if ((ret = av_dict_set(&dict, "method", wc->http_method, 0)) < 0) + return ret; + ret = s->io_open(s, &oc->pb, oc->url, AVIO_FLAG_WRITE, &dict); + av_dict_free(&dict); + if (ret < 0) + return ret; + oc->pb->seekable = 0; + if ((ret = av_dict_set_int(&dict, "dash", 1, 0)) < 0 || (ret = av_dict_set_int(&dict, "cluster_time_limit", wc->chunk_duration, 0)) < 0 || @@ -147,19 +157,10 @@ static int webm_chunk_write_header(AVFormatContext *s) WebMChunkContext *wc = s->priv_data; AVFormatContext *oc = wc->avf; int ret; - AVDictionary *options = NULL; - if (wc->http_method) - if ((ret = av_dict_set(&options, "method", wc->http_method, 0)) < 0) - return ret; - ret = s->io_open(s, &oc->pb, oc->url, AVIO_FLAG_WRITE, &options); - av_dict_free(&options); - if (ret < 0) - return ret; - - oc->pb->seekable = 0; ret = avformat_write_header(oc, NULL); ff_format_io_close(s, &oc->pb); + wc->header_written = 1; if (ret < 0) return ret; return 0; @@ -270,7 +271,10 @@ static void webm_chunk_deinit(AVFormatContext *s) if (!wc->avf) return; - ffio_free_dyn_buf(&wc->avf->pb); + if (wc->header_written) + ffio_free_dyn_buf(&wc->avf->pb); + else + ff_format_io_close(s, &wc->avf->pb); avformat_free_context(wc->avf); wc->avf = NULL; } diff --git a/chromium/third_party/ffmpeg/libavformat/webmdashenc.c b/chromium/third_party/ffmpeg/libavformat/webmdashenc.c index 465485c90ca..04f8cbe39df 100644 --- a/chromium/third_party/ffmpeg/libavformat/webmdashenc.c +++ b/chromium/third_party/ffmpeg/libavformat/webmdashenc.c @@ -79,19 +79,20 @@ static double get_duration(AVFormatContext *s) static int write_header(AVFormatContext *s) { WebMDashMuxContext *w = s->priv_data; + AVIOContext *pb = s->pb; double min_buffer_time = 1.0; - avio_printf(s->pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - avio_printf(s->pb, "<MPD\n"); - avio_printf(s->pb, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); - avio_printf(s->pb, " xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n"); - avio_printf(s->pb, " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n"); - avio_printf(s->pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static"); + avio_printf(pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + avio_printf(pb, "<MPD\n"); + avio_printf(pb, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); + avio_printf(pb, " xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n"); + avio_printf(pb, " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n"); + avio_printf(pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static"); if (!w->is_live) { - avio_printf(s->pb, " mediaPresentationDuration=\"PT%gS\"\n", + avio_printf(pb, " mediaPresentationDuration=\"PT%gS\"\n", get_duration(s)); } - avio_printf(s->pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time); - avio_printf(s->pb, " profiles=\"%s\"%s", + avio_printf(pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time); + avio_printf(pb, " profiles=\"%s\"%s", w->is_live ? "urn:mpeg:dash:profile:isoff-live:2011" : "urn:webm:dash:profile:webm-on-demand:2012", w->is_live ? "\n" : ">\n"); if (w->is_live) { @@ -105,14 +106,14 @@ static int write_header(AVFormatContext *s) if (s->flags & AVFMT_FLAG_BITEXACT) { av_strlcpy(gmt_iso, "", 1); } - avio_printf(s->pb, " availabilityStartTime=\"%s\"\n", gmt_iso); - avio_printf(s->pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth); - avio_printf(s->pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period); - avio_printf(s->pb, ">\n"); + avio_printf(pb, " availabilityStartTime=\"%s\"\n", gmt_iso); + avio_printf(pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth); + avio_printf(pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period); + avio_printf(pb, ">\n"); if (w->utc_timing_url) { - avio_printf(s->pb, "<UTCTiming\n"); - avio_printf(s->pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n"); - avio_printf(s->pb, " value=\"%s\"/>\n", w->utc_timing_url); + avio_printf(pb, "<UTCTiming\n"); + avio_printf(pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n"); + avio_printf(pb, " value=\"%s\"/>\n", w->utc_timing_url); } } return 0; @@ -123,7 +124,8 @@ static void write_footer(AVFormatContext *s) avio_printf(s->pb, "</MPD>\n"); } -static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as) { +static int subsegment_alignment(AVFormatContext *s, const AdaptationSet *as) +{ int i; AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata, CUE_TIMESTAMPS, NULL, 0); @@ -136,16 +138,19 @@ static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as) { return 1; } -static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) { +static int bitstream_switching(AVFormatContext *s, const AdaptationSet *as) +{ int i; - AVDictionaryEntry *gold_track_num = av_dict_get(s->streams[as->streams[0]]->metadata, + const AVStream *gold_st = s->streams[as->streams[0]]; + AVDictionaryEntry *gold_track_num = av_dict_get(gold_st->metadata, TRACK_NUMBER, NULL, 0); - AVCodecParameters *gold_par = s->streams[as->streams[0]]->codecpar; + AVCodecParameters *gold_par = gold_st->codecpar; if (!gold_track_num) return 0; for (i = 1; i < as->nb_streams; i++) { - AVDictionaryEntry *track_num = av_dict_get(s->streams[as->streams[i]]->metadata, + const AVStream *st = s->streams[as->streams[i]]; + AVDictionaryEntry *track_num = av_dict_get(st->metadata, TRACK_NUMBER, NULL, 0); - AVCodecParameters *par = s->streams[as->streams[i]]->codecpar; + AVCodecParameters *par = st->codecpar; if (!track_num || strncmp(gold_track_num->value, track_num->value, strlen(gold_track_num->value)) || gold_par->codec_id != par->codec_id || @@ -161,60 +166,65 @@ static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) { * Writes a Representation within an Adaptation Set. Returns 0 on success and * < 0 on failure. */ -static int write_representation(AVFormatContext *s, AVStream *stream, char *id, +static int write_representation(AVFormatContext *s, AVStream *st, char *id, int output_width, int output_height, - int output_sample_rate) { + int output_sample_rate) +{ WebMDashMuxContext *w = s->priv_data; - AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0); - AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0); - AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0); - AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0); - AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0); + AVIOContext *pb = s->pb; + const AVCodecParameters *par = st->codecpar; + AVDictionaryEntry *bandwidth = av_dict_get(st->metadata, BANDWIDTH, NULL, 0); const char *bandwidth_str; - if ((w->is_live && (!filename)) || - (!w->is_live && (!irange || !cues_start || !cues_end || !filename || !bandwidth))) { - return AVERROR_INVALIDDATA; - } - avio_printf(s->pb, "<Representation id=\"%s\"", id); - // if bandwidth for live was not provided, use a default - if (w->is_live && !bandwidth) { - bandwidth_str = (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? "128000" : "1000000"; - } else { + avio_printf(pb, "<Representation id=\"%s\"", id); + if (bandwidth) { bandwidth_str = bandwidth->value; + } else if (w->is_live) { + // if bandwidth for live was not provided, use a default + bandwidth_str = (par->codec_type == AVMEDIA_TYPE_AUDIO) ? "128000" : "1000000"; + } else { + return AVERROR(EINVAL); } - avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth_str); - if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_width) - avio_printf(s->pb, " width=\"%d\"", stream->codecpar->width); - if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_height) - avio_printf(s->pb, " height=\"%d\"", stream->codecpar->height); - if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && output_sample_rate) - avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codecpar->sample_rate); + avio_printf(pb, " bandwidth=\"%s\"", bandwidth_str); + if (par->codec_type == AVMEDIA_TYPE_VIDEO && output_width) + avio_printf(pb, " width=\"%d\"", par->width); + if (par->codec_type == AVMEDIA_TYPE_VIDEO && output_height) + avio_printf(pb, " height=\"%d\"", par->height); + if (par->codec_type == AVMEDIA_TYPE_AUDIO && output_sample_rate) + avio_printf(pb, " audioSamplingRate=\"%d\"", par->sample_rate); if (w->is_live) { // For live streams, Codec and Mime Type always go in the Representation tag. - avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(stream->codecpar->codec_id)); - avio_printf(s->pb, " mimeType=\"%s/webm\"", - stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); + avio_printf(pb, " codecs=\"%s\"", get_codec_name(par->codec_id)); + avio_printf(pb, " mimeType=\"%s/webm\"", + par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); // For live streams, subsegments always start with key frames. So this // is always 1. - avio_printf(s->pb, " startsWithSAP=\"1\""); - avio_printf(s->pb, ">"); + avio_printf(pb, " startsWithSAP=\"1\""); + avio_printf(pb, ">"); } else { - avio_printf(s->pb, ">\n"); - avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value); - avio_printf(s->pb, "<SegmentBase\n"); - avio_printf(s->pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value); - avio_printf(s->pb, "<Initialization\n"); - avio_printf(s->pb, " range=\"0-%s\" />\n", irange->value); - avio_printf(s->pb, "</SegmentBase>\n"); + AVDictionaryEntry *irange = av_dict_get(st->metadata, INITIALIZATION_RANGE, NULL, 0); + AVDictionaryEntry *cues_start = av_dict_get(st->metadata, CUES_START, NULL, 0); + AVDictionaryEntry *cues_end = av_dict_get(st->metadata, CUES_END, NULL, 0); + AVDictionaryEntry *filename = av_dict_get(st->metadata, FILENAME, NULL, 0); + if (!irange || !cues_start || !cues_end || !filename) + return AVERROR(EINVAL); + + avio_printf(pb, ">\n"); + avio_printf(pb, "<BaseURL>%s</BaseURL>\n", filename->value); + avio_printf(pb, "<SegmentBase\n"); + avio_printf(pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value); + avio_printf(pb, "<Initialization\n"); + avio_printf(pb, " range=\"0-%s\" />\n", irange->value); + avio_printf(pb, "</SegmentBase>\n"); } - avio_printf(s->pb, "</Representation>\n"); + avio_printf(pb, "</Representation>\n"); return 0; } /* * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise. */ -static int check_matching_width(AVFormatContext *s, AdaptationSet *as) { +static int check_matching_width(AVFormatContext *s, const AdaptationSet *as) +{ int first_width, i; if (as->nb_streams < 2) return 1; first_width = s->streams[as->streams[0]]->codecpar->width; @@ -227,7 +237,8 @@ static int check_matching_width(AVFormatContext *s, AdaptationSet *as) { /* * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise. */ -static int check_matching_height(AVFormatContext *s, AdaptationSet *as) { +static int check_matching_height(AVFormatContext *s, const AdaptationSet *as) +{ int first_height, i; if (as->nb_streams < 2) return 1; first_height = s->streams[as->streams[0]]->codecpar->height; @@ -240,7 +251,8 @@ static int check_matching_height(AVFormatContext *s, AdaptationSet *as) { /* * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise. */ -static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as) { +static int check_matching_sample_rate(AVFormatContext *s, const AdaptationSet *as) +{ int first_sample_rate, i; if (as->nb_streams < 2) return 1; first_sample_rate = s->streams[as->streams[0]]->codecpar->sample_rate; @@ -250,7 +262,8 @@ static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as) { return 1; } -static void free_adaptation_sets(AVFormatContext *s) { +static void free_adaptation_sets(AVFormatContext *s) +{ WebMDashMuxContext *w = s->priv_data; int i; for (i = 0; i < w->nb_as; i++) { @@ -261,70 +274,24 @@ static void free_adaptation_sets(AVFormatContext *s) { } /* - * Parses a live header filename and computes the representation id, - * initialization pattern and the media pattern. Pass NULL if you don't want to - * compute any of those 3. Returns 0 on success and non-zero on failure. + * Parses a live header filename and returns the position of the '_' and '.' + * delimiting <file_description> and <representation_id>. * * Name of the header file should conform to the following pattern: * <file_description>_<representation_id>.hdr where <file_description> can be * anything. The chunks should be named according to the following pattern: * <file_description>_<representation_id>_<chunk_number>.chk */ -static int parse_filename(char *filename, char **representation_id, - char **initialization_pattern, char **media_pattern) { - char *underscore_pos = NULL; - char *period_pos = NULL; - char *temp_pos = NULL; - char *filename_str = av_strdup(filename); - int ret = 0; - - if (!filename_str) { - ret = AVERROR(ENOMEM); - goto end; - } - temp_pos = av_stristr(filename_str, "_"); - while (temp_pos) { - underscore_pos = temp_pos + 1; - temp_pos = av_stristr(temp_pos + 1, "_"); - } - if (!underscore_pos) { - ret = AVERROR_INVALIDDATA; - goto end; - } - period_pos = av_stristr(underscore_pos, "."); - if (!period_pos) { - ret = AVERROR_INVALIDDATA; - goto end; - } - *(underscore_pos - 1) = 0; - if (representation_id) { - *representation_id = av_malloc(period_pos - underscore_pos + 1); - if (!(*representation_id)) { - ret = AVERROR(ENOMEM); - goto end; - } - av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1); - } - if (initialization_pattern) { - *initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr", - filename_str); - if (!(*initialization_pattern)) { - ret = AVERROR(ENOMEM); - goto end; - } - } - if (media_pattern) { - *media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk", - filename_str); - if (!(*media_pattern)) { - ret = AVERROR(ENOMEM); - goto end; - } - } - -end: - av_freep(&filename_str); - return ret; +static int split_filename(char *filename, char **underscore_pos, + char **period_pos) +{ + *underscore_pos = strrchr(filename, '_'); + if (!*underscore_pos) + return AVERROR(EINVAL); + *period_pos = strchr(*underscore_pos, '.'); + if (!*period_pos) + return AVERROR(EINVAL); + return 0; } /* @@ -334,8 +301,10 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) { WebMDashMuxContext *w = s->priv_data; AdaptationSet *as = &w->as[as_index]; - AVCodecParameters *par = s->streams[as->streams[0]]->codecpar; + const AVStream *st = s->streams[as->streams[0]]; + AVCodecParameters *par = st->codecpar; AVDictionaryEntry *lang; + AVIOContext *pb = s->pb; int i; static const char boolean[2][6] = { "false", "true" }; int subsegmentStartsWithSAP = 1; @@ -346,30 +315,31 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) // in the Representation tag. int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1; if (par->codec_type == AVMEDIA_TYPE_VIDEO) { - width_in_as = !w->is_live && check_matching_width(s, as); + width_in_as = !w->is_live && check_matching_width (s, as); height_in_as = !w->is_live && check_matching_height(s, as); } else { sample_rate_in_as = !w->is_live && check_matching_sample_rate(s, as); } - avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id); - avio_printf(s->pb, " mimeType=\"%s/webm\"", + avio_printf(pb, "<AdaptationSet id=\"%s\"", as->id); + avio_printf(pb, " mimeType=\"%s/webm\"", par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(par->codec_id)); + avio_printf(pb, " codecs=\"%s\"", get_codec_name(par->codec_id)); - lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0); - if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value); + lang = av_dict_get(st->metadata, "language", NULL, 0); + if (lang) + avio_printf(pb, " lang=\"%s\"", lang->value); if (par->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as) - avio_printf(s->pb, " width=\"%d\"", par->width); + avio_printf(pb, " width=\"%d\"", par->width); if (par->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as) - avio_printf(s->pb, " height=\"%d\"", par->height); + avio_printf(pb, " height=\"%d\"", par->height); if (par->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as) - avio_printf(s->pb, " audioSamplingRate=\"%d\"", par->sample_rate); + avio_printf(pb, " audioSamplingRate=\"%d\"", par->sample_rate); - avio_printf(s->pb, " bitstreamSwitching=\"%s\"", + avio_printf(pb, " bitstreamSwitching=\"%s\"", boolean[bitstream_switching(s, as)]); - avio_printf(s->pb, " subsegmentAlignment=\"%s\"", + avio_printf(pb, " subsegmentAlignment=\"%s\"", boolean[w->is_live || subsegment_alignment(s, as)]); for (i = 0; i < as->nb_streams; i++) { @@ -377,66 +347,60 @@ static int write_adaptation_set(AVFormatContext *s, int as_index) CLUSTER_KEYFRAME, NULL, 0); if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0; } - avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP); - avio_printf(s->pb, ">\n"); + avio_printf(pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP); + avio_printf(pb, ">\n"); if (w->is_live) { AVDictionaryEntry *filename = - av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0); - char *initialization_pattern = NULL; - char *media_pattern = NULL; - int ret = parse_filename(filename->value, NULL, &initialization_pattern, - &media_pattern); + av_dict_get(st->metadata, FILENAME, NULL, 0); + char *underscore_pos, *period_pos; + int ret; + if (!filename) + return AVERROR(EINVAL); + ret = split_filename(filename->value, &underscore_pos, &period_pos); if (ret) return ret; - avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n", + *underscore_pos = '\0'; + avio_printf(pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n", par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - avio_printf(s->pb, "<SegmentTemplate"); - avio_printf(s->pb, " timescale=\"1000\""); - avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration); - avio_printf(s->pb, " media=\"%s\"", media_pattern); - avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index); - avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern); - avio_printf(s->pb, "/>\n"); - av_free(initialization_pattern); - av_free(media_pattern); + avio_printf(pb, "<SegmentTemplate"); + avio_printf(pb, " timescale=\"1000\""); + avio_printf(pb, " duration=\"%d\"", w->chunk_duration); + avio_printf(pb, " media=\"%s_$RepresentationID$_$Number$.chk\"", + filename->value); + avio_printf(pb, " startNumber=\"%d\"", w->chunk_start_index); + avio_printf(pb, " initialization=\"%s_$RepresentationID$.hdr\"", + filename->value); + avio_printf(pb, "/>\n"); + *underscore_pos = '_'; } for (i = 0; i < as->nb_streams; i++) { - char *representation_id = NULL; + char buf[25], *representation_id = buf, *underscore_pos, *period_pos; + AVStream *st = s->streams[as->streams[i]]; int ret; if (w->is_live) { AVDictionaryEntry *filename = - av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0); + av_dict_get(st->metadata, FILENAME, NULL, 0); if (!filename) return AVERROR(EINVAL); - if (ret = parse_filename(filename->value, &representation_id, NULL, NULL)) + ret = split_filename(filename->value, &underscore_pos, &period_pos); + if (ret < 0) return ret; + representation_id = underscore_pos + 1; + *period_pos = '\0'; } else { - representation_id = av_asprintf("%d", w->representation_id++); - if (!representation_id) return AVERROR(ENOMEM); + snprintf(buf, sizeof(buf), "%d", w->representation_id++); } - ret = write_representation(s, s->streams[as->streams[i]], - representation_id, !width_in_as, + ret = write_representation(s, st, representation_id, !width_in_as, !height_in_as, !sample_rate_in_as); - av_free(representation_id); if (ret) return ret; + if (w->is_live) + *period_pos = '.'; } avio_printf(s->pb, "</AdaptationSet>\n"); return 0; } -static int to_integer(char *p, int len) -{ - int ret; - char *q = av_malloc(len); - if (!q) - return AVERROR(ENOMEM); - av_strlcpy(q, p, len); - ret = atoi(q); - av_free(q); - return ret; -} - static int parse_adaptation_sets(AVFormatContext *s) { WebMDashMuxContext *w = s->priv_data; @@ -449,10 +413,16 @@ static int parse_adaptation_sets(AVFormatContext *s) } // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on state = new_set; - while (p < w->adaptation_sets + strlen(w->adaptation_sets)) { - if (*p == ' ') + while (1) { + if (*p == '\0') { + if (state == new_set) + break; + else + return AVERROR(EINVAL); + } else if (state == new_set && *p == ' ') { + p++; continue; - else if (state == new_set && !strncmp(p, "id=", 3)) { + } else if (state == new_set && !strncmp(p, "id=", 3)) { void *mem = av_realloc(w->as, sizeof(*w->as) * (w->nb_as + 1)); const char *comma; if (mem == NULL) @@ -477,18 +447,18 @@ static int parse_adaptation_sets(AVFormatContext *s) state = parsing_streams; } else if (state == parsing_streams) { struct AdaptationSet *as = &w->as[w->nb_as - 1]; + int64_t num; int ret = av_reallocp_array(&as->streams, ++as->nb_streams, sizeof(*as->streams)); if (ret < 0) return ret; - q = p; - while (*q != '\0' && *q != ',' && *q != ' ') q++; - as->streams[as->nb_streams - 1] = to_integer(p, q - p + 1); - if (as->streams[as->nb_streams - 1] < 0 || - as->streams[as->nb_streams - 1] >= s->nb_streams) { + num = strtoll(p, &q, 10); + if (!av_isdigit(*p) || (*q != ' ' && *q != '\0' && *q != ',') || + num < 0 || num >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "Invalid value for 'streams' in adapation_sets.\n"); return AVERROR(EINVAL); } + as->streams[as->nb_streams - 1] = num; if (*q == '\0') break; if (*q == ' ') state = new_set; p = ++q; diff --git a/chromium/third_party/ffmpeg/libavformat/webvttdec.c b/chromium/third_party/ffmpeg/libavformat/webvttdec.c index 6c4d5f6736e..8d2fdfed37d 100644 --- a/chromium/third_party/ffmpeg/libavformat/webvttdec.c +++ b/chromium/third_party/ffmpeg/libavformat/webvttdec.c @@ -125,7 +125,7 @@ static int webvtt_read_header(AVFormatContext *s) break; /* optional cue settings */ - p += strcspn(p, "\n\t "); + p += strcspn(p, "\n\r\t "); while (*p == '\t' || *p == ' ') p++; settings = p; @@ -164,6 +164,8 @@ static int webvtt_read_header(AVFormatContext *s) ff_subtitles_queue_finalize(s, &webvtt->q); end: + if (res < 0) + ff_subtitles_queue_clean(&webvtt->q); av_bprint_finalize(&cue, NULL); return res; } diff --git a/chromium/third_party/ffmpeg/libavformat/wtvenc.c b/chromium/third_party/ffmpeg/libavformat/wtvenc.c index 498bc640195..b53fdf90487 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/wtvenc.c @@ -241,7 +241,7 @@ static void put_videoinfoheader2(AVIOContext *pb, AVStream *st) avio_wl32(pb, 0); avio_wl32(pb, 0); - ff_put_bmp_header(pb, st->codecpar, 0, 1); + ff_put_bmp_header(pb, st->codecpar, 0, 1, 0); if (st->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO) { int padding = (st->codecpar->extradata_size & 3) ? 4 - (st->codecpar->extradata_size & 3) : 0; |