diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/ffmpeg/libavformat | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/ffmpeg/libavformat')
205 files changed, 12801 insertions, 4378 deletions
diff --git a/chromium/third_party/ffmpeg/libavformat/4xm.c b/chromium/third_party/ffmpeg/libavformat/4xm.c index 6e63c673993..23279c42fb7 100644 --- a/chromium/third_party/ffmpeg/libavformat/4xm.c +++ b/chromium/third_party/ffmpeg/libavformat/4xm.c @@ -319,8 +319,10 @@ static int fourxm_read_packet(AVFormatContext *s, if (ret < 0) { av_free_packet(pkt); - } else + } else { packet_read = 1; + av_shrink_packet(pkt, ret + 8); + } break; case snd__TAG: diff --git a/chromium/third_party/ffmpeg/libavformat/Makefile b/chromium/third_party/ffmpeg/libavformat/Makefile index cf3352b96de..00358e771b9 100644 --- a/chromium/third_party/ffmpeg/libavformat/Makefile +++ b/chromium/third_party/ffmpeg/libavformat/Makefile @@ -1,7 +1,6 @@ include $(SUBDIR)../config.mak NAME = avformat -FFLIBS = avcodec avutil HEADERS = avformat.h \ avio.h \ @@ -50,7 +49,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtpdec_xiph.o \ srtp.o OBJS-$(CONFIG_RTPENC_CHAIN) += rtpenc_chain.o rtp.o -OBJS-$(CONFIG_SHARED) += log2_tab.o +OBJS-$(CONFIG_SHARED) += log2_tab.o golomb_tab.o # muxers/demuxers OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o @@ -62,7 +61,7 @@ OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_ADP_DEMUXER) += adp.o OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o OBJS-$(CONFIG_ADX_MUXER) += rawenc.o -OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o +OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o img2.o OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o OBJS-$(CONFIG_AFC_DEMUXER) += afc.o OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o isom.o \ @@ -84,7 +83,7 @@ OBJS-$(CONFIG_AST_MUXER) += ast.o astenc.o OBJS-$(CONFIG_AU_DEMUXER) += au.o pcm.o OBJS-$(CONFIG_AU_MUXER) += au.o rawenc.o OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o -OBJS-$(CONFIG_AVI_MUXER) += avienc.o +OBJS-$(CONFIG_AVI_MUXER) += avienc.o avlanguage.o OBJS-$(CONFIG_AVISYNTH) += avisynth.o OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o swf.o OBJS-$(CONFIG_AVR_DEMUXER) += avr.o pcm.o @@ -106,6 +105,7 @@ OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o +OBJS-$(CONFIG_CINE_DEMUXER) += cinedec.o OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o OBJS-$(CONFIG_CRC_MUXER) += crcenc.o OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o @@ -117,6 +117,7 @@ OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o OBJS-$(CONFIG_DNXHD_MUXER) += rawenc.o +OBJS-$(CONFIG_DSF_DEMUXER) += dsfdec.o OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o OBJS-$(CONFIG_DTSHD_DEMUXER) += dtshddec.o OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o @@ -138,6 +139,7 @@ OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \ flac_picture.o \ oggparsevorbis.o \ + replaygain.o \ vorbiscomment.o OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \ vorbiscomment.o @@ -166,6 +168,7 @@ OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o OBJS-$(CONFIG_H264_MUXER) += rawenc.o OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o +OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o @@ -180,6 +183,8 @@ OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE2_MUXER) += img2enc.o img2.o OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2enc.o img2.o +OBJS-$(CONFIG_IMAGE2_ALIAS_PIX_DEMUXER) += img2_alias_pix.o +OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o OBJS-$(CONFIG_INGENIENT_DEMUXER) += ingenientdec.o rawdec.o OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o OBJS-$(CONFIG_IRCAM_DEMUXER) += ircamdec.o ircam.o pcm.o @@ -202,7 +207,7 @@ OBJS-$(CONFIG_M4V_MUXER) += rawenc.o OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \ isom.o rmsipr.o OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ - isom.o avc.o \ + isom.o avc.o hevc.o \ flacenc_header.o avlanguage.o wv.o OBJS-$(CONFIG_MD5_MUXER) += md5enc.o OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o @@ -212,14 +217,15 @@ OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o OBJS-$(CONFIG_MJPEG_MUXER) += rawenc.o OBJS-$(CONFIG_MLP_DEMUXER) += rawdec.o OBJS-$(CONFIG_MLP_MUXER) += rawenc.o +OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o -OBJS-$(CONFIG_MOV_DEMUXER) += mov.o isom.o mov_chan.o -OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o \ +OBJS-$(CONFIG_MOV_DEMUXER) += mov.o isom.o mov_chan.o replaygain.o +OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o hevc.o \ movenchint.o mov_chan.o rtp.o OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o -OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o +OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o replaygain.o OBJS-$(CONFIG_MP3_MUXER) += mp3enc.o rawenc.o id3v2enc.o OBJS-$(CONFIG_MPC_DEMUXER) += mpc.o apetag.o img2.o OBJS-$(CONFIG_MPC8_DEMUXER) += mpc8.o apetag.o img2.o @@ -239,8 +245,8 @@ OBJS-$(CONFIG_MPL2_DEMUXER) += mpl2dec.o subtitles.o OBJS-$(CONFIG_MPSUB_DEMUXER) += mpsubdec.o subtitles.o OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o -OBJS-$(CONFIG_MVI_DEMUXER) += mvi.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 OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o @@ -261,8 +267,12 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparsespeex.o \ oggparsetheora.o \ oggparsevorbis.o \ + oggparsevp8.o \ + replaygain.o \ vorbiscomment.o \ flac_picture.o +OBJS-$(CONFIG_OGA_MUXER) += oggenc.o \ + vorbiscomment.o OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \ vorbiscomment.o OBJS-$(CONFIG_OMA_DEMUXER) += omadec.o pcm.o oma.o @@ -351,6 +361,7 @@ OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o OBJS-$(CONFIG_SAP_MUXER) += sapenc.o OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o +OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o OBJS-$(CONFIG_SHORTEN_DEMUXER) += rawdec.o @@ -386,6 +397,7 @@ OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o +OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o OBJS-$(CONFIG_VC1_MUXER) += rawenc.o OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o @@ -411,7 +423,7 @@ OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec.o asf.o asfcrypt.o \ avlanguage.o mpegts.o isom.o -OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o asf.o asfenc.o +OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o mpegtsenc.o OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o OBJS-$(CONFIG_WV_MUXER) += wvenc.o wv.o apetag.o img2.o OBJS-$(CONFIG_XA_DEMUXER) += xa.o @@ -460,6 +472,7 @@ OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o +OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o @@ -472,6 +485,7 @@ SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h + TESTPROGS = seek \ srtp \ url \ diff --git a/chromium/third_party/ffmpeg/libavformat/aacdec.c b/chromium/third_party/ffmpeg/libavformat/aacdec.c index d93e75ec52c..05cbaf78aa1 100644 --- a/chromium/third_party/ffmpeg/libavformat/aacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/aacdec.c @@ -38,28 +38,42 @@ static int adts_aac_probe(AVProbeData *p) buf = buf0; - for(; buf < end; buf= buf2+1) { + for (; buf < end; buf = buf2 + 1) { buf2 = buf; - for(frames = 0; buf2 < end; frames++) { + for (frames = 0; buf2 < end; frames++) { uint32_t header = AV_RB16(buf2); - if((header&0xFFF6) != 0xFFF0) + if ((header & 0xFFF6) != 0xFFF0) { + if (buf != buf0) { + // Found something that isn't an ADTS header, starting + // from a position other than the start of the buffer. + // Discard the count we've accumulated so far since it + // probably was a false positive. + frames = 0; + } break; + } fsize = (AV_RB32(buf2 + 3) >> 13) & 0x1FFF; - if(fsize < 7) + if (fsize < 7) break; fsize = FFMIN(fsize, end - buf2); buf2 += fsize; } max_frames = FFMAX(max_frames, frames); - if(buf == buf0) - first_frames= frames; + if (buf == buf0) + first_frames = frames; } - if (first_frames>=3) return AVPROBE_SCORE_EXTENSION + 1; - else if(max_frames>500)return AVPROBE_SCORE_EXTENSION; - else if(max_frames>=3) return AVPROBE_SCORE_EXTENSION / 2; - else if(max_frames>=1) return 1; - else return 0; + + if (first_frames >= 3) + return AVPROBE_SCORE_EXTENSION + 1; + else if (max_frames > 100) + return AVPROBE_SCORE_EXTENSION; + else if (max_frames >= 3) + return AVPROBE_SCORE_EXTENSION / 2; + else if (max_frames >= 1) + return 1; + else + return 0; } static int adts_aac_read_header(AVFormatContext *s) @@ -71,8 +85,8 @@ static int adts_aac_read_header(AVFormatContext *s) return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = s->iformat->raw_codec_id; - st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + st->codec->codec_id = s->iformat->raw_codec_id; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; ff_id3v1_read(s); if (s->pb->seekable && @@ -82,19 +96,19 @@ static int adts_aac_read_header(AVFormatContext *s) avio_seek(s->pb, cur, SEEK_SET); } - //LCM of all possible ADTS sample rates + // LCM of all possible ADTS sample rates avpriv_set_pts_info(st, 64, 1, 28224000); return 0; } AVInputFormat ff_aac_demuxer = { - .name = "aac", - .long_name = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"), - .read_probe = adts_aac_probe, - .read_header = adts_aac_read_header, - .read_packet = ff_raw_read_partial_packet, - .flags = AVFMT_GENERIC_INDEX, - .extensions = "aac", - .raw_codec_id = AV_CODEC_ID_AAC, + .name = "aac", + .long_name = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"), + .read_probe = adts_aac_probe, + .read_header = adts_aac_read_header, + .read_packet = ff_raw_read_partial_packet, + .flags = AVFMT_GENERIC_INDEX, + .extensions = "aac", + .raw_codec_id = AV_CODEC_ID_AAC, }; diff --git a/chromium/third_party/ffmpeg/libavformat/ac3dec.c b/chromium/third_party/ffmpeg/libavformat/ac3dec.c index 3db23397d0d..58ef44d45a7 100644 --- a/chromium/third_party/ffmpeg/libavformat/ac3dec.c +++ b/chromium/third_party/ffmpeg/libavformat/ac3dec.c @@ -28,7 +28,7 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; const uint8_t *buf, *buf2, *end; - AC3HeaderInfo hdr; + AC3HeaderInfo *phdr = NULL; GetBitContext gbc; enum AVCodecID codec_id = AV_CODEC_ID_AC3; @@ -55,27 +55,28 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) init_get_bits(&gbc, buf3, 54); }else init_get_bits(&gbc, buf2, 54); - if(avpriv_ac3_parse_header(&gbc, &hdr) < 0) + if(avpriv_ac3_parse_header2(&gbc, &phdr) < 0) break; - if(buf2 + hdr.frame_size > end) + if(buf2 + phdr->frame_size > end) break; if (buf[0] == 0x77 && buf[1] == 0x0B) { - av_assert0(hdr.frame_size <= sizeof(buf3)); - for(i=8; i<hdr.frame_size; i+=2) { + av_assert0(phdr->frame_size <= sizeof(buf3)); + for(i=8; i<phdr->frame_size; i+=2) { buf3[i ] = buf[i+1]; buf3[i+1] = buf[i ]; } } - if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, hdr.frame_size - 2)) + if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2)) break; - if (hdr.bitstream_id > 10) + if (phdr->bitstream_id > 10) codec_id = AV_CODEC_ID_EAC3; - buf2 += hdr.frame_size; + buf2 += phdr->frame_size; } max_frames = FFMAX(max_frames, frames); if(buf == p->buf) first_frames = frames; } + av_freep(&phdr); if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! diff --git a/chromium/third_party/ffmpeg/libavformat/adxdec.c b/chromium/third_party/ffmpeg/libavformat/adxdec.c index 0a0436f1847..fe22c3ae697 100644 --- a/chromium/third_party/ffmpeg/libavformat/adxdec.c +++ b/chromium/third_party/ffmpeg/libavformat/adxdec.c @@ -78,13 +78,8 @@ static int adx_read_header(AVFormatContext *s) c->header_size = avio_rb16(s->pb) + 4; avio_seek(s->pb, -4, SEEK_CUR); - if (ff_alloc_extradata(avctx, c->header_size)) + if (ff_get_extradata(avctx, s->pb, c->header_size) < 0) return AVERROR(ENOMEM); - if (avio_read(s->pb, avctx->extradata, c->header_size) < c->header_size) { - av_freep(&avctx->extradata); - return AVERROR(EIO); - } - avctx->extradata_size = c->header_size; ret = avpriv_adx_decode_header(avctx, avctx->extradata, avctx->extradata_size, &c->header_size, diff --git a/chromium/third_party/ffmpeg/libavformat/aiffdec.c b/chromium/third_party/ffmpeg/libavformat/aiffdec.c index 6f82d9339a1..81bcc64a0c5 100644 --- a/chromium/third_party/ffmpeg/libavformat/aiffdec.c +++ b/chromium/third_party/ffmpeg/libavformat/aiffdec.c @@ -237,7 +237,7 @@ static int aiff_read_header(AVFormatContext *s) break; case MKTAG('I', 'D', '3', ' '): position = avio_tell(pb); - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + 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) { ff_id3v2_free_extra_meta(&id3v2_extra_meta); @@ -278,9 +278,8 @@ static int aiff_read_header(AVFormatContext *s) case MKTAG('w', 'a', 'v', 'e'): if ((uint64_t)size > (1<<30)) return -1; - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, size); if (st->codec->codec_id == AV_CODEC_ID_QDM2 && size>=12*4 && !st->codec->block_align) { st->codec->block_align = AV_RB32(st->codec->extradata+11*4); aiff->block_duration = AV_RB32(st->codec->extradata+9*4); diff --git a/chromium/third_party/ffmpeg/libavformat/aiffenc.c b/chromium/third_party/ffmpeg/libavformat/aiffenc.c index 6e3d8bc6add..90fc43346ce 100644 --- a/chromium/third_party/ffmpeg/libavformat/aiffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/aiffenc.c @@ -66,7 +66,7 @@ static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff) return ret; pict_list = pict_list->next; } - ff_id3v2_finish(&id3v2, pb); + ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding); end = avio_tell(pb); size = end - pos; diff --git a/chromium/third_party/ffmpeg/libavformat/allformats.c b/chromium/third_party/ffmpeg/libavformat/allformats.c index f1039dda84b..0e7feea8f64 100644 --- a/chromium/third_party/ffmpeg/libavformat/allformats.c +++ b/chromium/third_party/ffmpeg/libavformat/allformats.c @@ -98,6 +98,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo); REGISTER_DEMUXER (CDG, cdg); REGISTER_DEMUXER (CDXL, cdxl); + REGISTER_DEMUXER (CINE, cine); REGISTER_DEMUXER (CONCAT, concat); REGISTER_MUXER (CRC, crc); REGISTER_MUXDEMUX(DATA, data); @@ -105,6 +106,7 @@ void av_register_all(void) REGISTER_DEMUXER (DFA, dfa); REGISTER_MUXDEMUX(DIRAC, dirac); REGISTER_MUXDEMUX(DNXHD, dnxhd); + REGISTER_DEMUXER (DSF, dsf); REGISTER_DEMUXER (DSICIN, dsicin); REGISTER_MUXDEMUX(DTS, dts); REGISTER_DEMUXER (DTSHD, dtshd); @@ -135,7 +137,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(H263, h263); REGISTER_MUXDEMUX(H264, h264); REGISTER_MUXER (HDS, hds); - REGISTER_DEMUXER (HEVC, hevc); + REGISTER_MUXDEMUX(HEVC, hevc); REGISTER_MUXDEMUX(HLS, hls); REGISTER_DEMUXER (HNM, hnm); REGISTER_MUXDEMUX(ICO, ico); @@ -145,6 +147,8 @@ void av_register_all(void) REGISTER_MUXDEMUX(ILBC, ilbc); REGISTER_MUXDEMUX(IMAGE2, image2); REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe); + REGISTER_DEMUXER (IMAGE2_ALIAS_PIX, image2_alias_pix); + REGISTER_DEMUXER (IMAGE2_BRENDER_PIX, image2_brender_pix); REGISTER_DEMUXER (INGENIENT, ingenient); REGISTER_DEMUXER (IPMOVIE, ipmovie); REGISTER_MUXER (IPOD, ipod); @@ -168,6 +172,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(MICRODVD, microdvd); REGISTER_MUXDEMUX(MJPEG, mjpeg); REGISTER_MUXDEMUX(MLP, mlp); + REGISTER_DEMUXER (MLV, mlv); REGISTER_DEMUXER (MM, mm); REGISTER_MUXDEMUX(MMF, mmf); REGISTER_MUXDEMUX(MOV, mov); @@ -203,6 +208,7 @@ void av_register_all(void) REGISTER_MUXER (NULL, null); REGISTER_MUXDEMUX(NUT, nut); REGISTER_DEMUXER (NUV, nuv); + REGISTER_MUXER (OGA, oga); REGISTER_MUXDEMUX(OGG, ogg); REGISTER_MUXDEMUX(OMA, oma); REGISTER_MUXER (OPUS, opus); @@ -249,6 +255,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(SAP, sap); REGISTER_DEMUXER (SBG, sbg); REGISTER_DEMUXER (SDP, sdp); + REGISTER_DEMUXER (SDR2, sdr2); #if CONFIG_RTPDEC ff_register_rtp_dynamic_payload_handlers(); ff_register_rdt_dynamic_payload_handlers(); @@ -284,6 +291,7 @@ void av_register_all(void) REGISTER_DEMUXER (TTA, tta); REGISTER_DEMUXER (TXD, txd); REGISTER_DEMUXER (TTY, tty); + REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc); REGISTER_MUXDEMUX(VC1, vc1); REGISTER_MUXDEMUX(VC1T, vc1t); REGISTER_DEMUXER (VIVO, vivo); @@ -336,6 +344,7 @@ void av_register_all(void) REGISTER_PROTOCOL(RTP, rtp); REGISTER_PROTOCOL(SCTP, sctp); REGISTER_PROTOCOL(SRTP, srtp); + REGISTER_PROTOCOL(SUBFILE, subfile); REGISTER_PROTOCOL(TCP, tcp); REGISTER_PROTOCOL(TLS, tls); REGISTER_PROTOCOL(UDP, udp); diff --git a/chromium/third_party/ffmpeg/libavformat/amr.c b/chromium/third_party/ffmpeg/libavformat/amr.c index db9bb4e59da..60015255307 100644 --- a/chromium/third_party/ffmpeg/libavformat/amr.c +++ b/chromium/third_party/ffmpeg/libavformat/amr.c @@ -26,11 +26,15 @@ Only mono files are supported. */ -#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "avformat.h" #include "internal.h" +typedef struct { + uint64_t cumulated_size; + uint64_t block_count; +} AMRContext; + static const char AMR_header[] = "#!AMR\n"; static const char AMRWB_header[] = "#!AMR-WB\n"; @@ -111,12 +115,13 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) AVCodecContext *enc = s->streams[0]->codec; int read, size = 0, toc, mode; int64_t pos = avio_tell(s->pb); + AMRContext *amr = s->priv_data; if (url_feof(s->pb)) { return AVERROR(EIO); } - // FIXME this is wrong, this should rather be in a AVParset + // FIXME this is wrong, this should rather be in a AVParser toc = avio_r8(s->pb); mode = (toc >> 3) & 0x0F; @@ -137,8 +142,11 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) if (!size || av_new_packet(pkt, size)) return AVERROR(EIO); - /* Both AMR formats have 50 frames per second */ - s->streams[0]->codec->bit_rate = size*8*50; + if (amr->cumulated_size < UINT64_MAX - size) { + amr->cumulated_size += size; + /* Both AMR formats have 50 frames per second */ + s->streams[0]->codec->bit_rate = amr->cumulated_size / ++amr->block_count * 8 * 50; + } pkt->stream_index = 0; pkt->pos = pos; @@ -158,6 +166,7 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) AVInputFormat ff_amr_demuxer = { .name = "amr", .long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"), + .priv_data_size = sizeof(AMRContext), .read_probe = amr_probe, .read_header = amr_read_header, .read_packet = amr_read_packet, diff --git a/chromium/third_party/ffmpeg/libavformat/apc.c b/chromium/third_party/ffmpeg/libavformat/apc.c index 08ae9351dcf..21bb514cd0b 100644 --- a/chromium/third_party/ffmpeg/libavformat/apc.c +++ b/chromium/third_party/ffmpeg/libavformat/apc.c @@ -52,11 +52,9 @@ static int apc_read_header(AVFormatContext *s) avio_rl32(pb); /* number of samples */ st->codec->sample_rate = avio_rl32(pb); - if (ff_alloc_extradata(st->codec, 2 * 4)) - return AVERROR(ENOMEM); - /* initial predictor values for adpcm decoder */ - avio_read(pb, st->codec->extradata, 2 * 4); + if (ff_get_extradata(st->codec, pb, 2 * 4) < 0) + return AVERROR(ENOMEM); if (avio_rl32(pb)) { st->codec->channels = 2; diff --git a/chromium/third_party/ffmpeg/libavformat/ape.c b/chromium/third_party/ffmpeg/libavformat/ape.c index 6f824800a39..d5a786a1989 100644 --- a/chromium/third_party/ffmpeg/libavformat/ape.c +++ b/chromium/third_party/ffmpeg/libavformat/ape.c @@ -264,7 +264,7 @@ static int ape_read_header(AVFormatContext * s) } if (ape->seektablelength / sizeof(*ape->seektable) < ape->totalframes) { av_log(s, AV_LOG_ERROR, - "Number of seek entries is less than number of frames: %zu vs. %"PRIu32"\n", + "Number of seek entries is less than number of frames: %"SIZE_SPECIFIER" vs. %"PRIu32"\n", ape->seektablelength / sizeof(*ape->seektable), ape->totalframes); return AVERROR_INVALIDDATA; } @@ -282,18 +282,20 @@ static int ape_read_header(AVFormatContext * s) ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1); if (ape->seektablelength > 0) { - ape->seektable = av_malloc(ape->seektablelength); + ape->seektable = av_mallocz(ape->seektablelength); if (!ape->seektable) return AVERROR(ENOMEM); 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_malloc(ape->totalframes); + ape->bittable = av_mallocz(ape->totalframes); if (!ape->bittable) return AVERROR(ENOMEM); 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"); } ape->frames[0].pos = ape->firstframe; @@ -415,8 +417,10 @@ static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) AV_WL32(pkt->data , nblocks); AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip); ret = avio_read(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size); - if (ret < 0) + if (ret < 0) { + av_free_packet(pkt); return ret; + } pkt->pts = ape->frames[ape->currentframe].pts; pkt->stream_index = 0; diff --git a/chromium/third_party/ffmpeg/libavformat/apetag.c b/chromium/third_party/ffmpeg/libavformat/apetag.c index a376a0bc4a4..7d2f0b3222d 100644 --- a/chromium/third_party/ffmpeg/libavformat/apetag.c +++ b/chromium/third_party/ffmpeg/libavformat/apetag.c @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "avformat.h" @@ -88,13 +90,8 @@ static int ape_tag_read_field(AVFormatContext *s) st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; } else { - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, s->pb, size) < 0) return AVERROR(ENOMEM); - if (avio_read(pb, st->codec->extradata, size) != size) { - av_freep(&st->codec->extradata); - st->codec->extradata_size = 0; - return AVERROR(EIO); - } st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; } } else { @@ -144,14 +141,14 @@ int64_t ff_ape_parse_tag(AVFormatContext *s) } if (tag_bytes > file_size - APE_TAG_FOOTER_BYTES) { - av_log(s, AV_LOG_ERROR, "Invalid tag size %u.\n", tag_bytes); + av_log(s, AV_LOG_ERROR, "Invalid tag size %"PRIu32".\n", tag_bytes); return 0; } tag_start = file_size - tag_bytes - APE_TAG_FOOTER_BYTES; fields = avio_rl32(pb); /* number of fields */ if (fields > 65536) { - av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); + av_log(s, AV_LOG_ERROR, "Too many tag fields (%"PRIu32")\n", fields); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/asf.h b/chromium/third_party/ffmpeg/libavformat/asf.h index 904d3486e88..0c9598a8d8f 100644 --- a/chromium/third_party/ffmpeg/libavformat/asf.h +++ b/chromium/third_party/ffmpeg/libavformat/asf.h @@ -43,6 +43,7 @@ typedef struct ASFStream { int timestamp; int64_t duration; int skip_to_key; + int pkt_clean; int ds_span; /* descrambling */ int ds_packet_size; @@ -188,6 +189,4 @@ extern const AVMetadataConv ff_asf_metadata_conv[]; extern AVInputFormat ff_asf_demuxer; -void ff_put_guid(AVIOContext *s, const ff_asf_guid *g); - #endif /* AVFORMAT_ASF_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/asfdec.c b/chromium/third_party/ffmpeg/libavformat/asfdec.c index a9b032682d5..a7d860927b1 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/asfdec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -266,7 +268,7 @@ static void get_id3_tag(AVFormatContext *s, int len) { ID3v2ExtraMeta *id3v2_extra_meta = NULL; - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len); if (id3v2_extra_meta) ff_id3v2_parse_apic(s, &id3v2_extra_meta); ff_id3v2_free_extra_meta(&id3v2_extra_meta); @@ -943,13 +945,13 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb) // the following checks prevent overflows and infinite loops if (!packet_length || packet_length >= (1U << 29)) { av_log(s, AV_LOG_ERROR, - "invalid packet_length %d at:%"PRId64"\n", + "invalid packet_length %"PRIu32" at:%"PRId64"\n", packet_length, avio_tell(pb)); return AVERROR_INVALIDDATA; } if (padsize >= packet_length) { av_log(s, AV_LOG_ERROR, - "invalid padsize %d at:%"PRId64"\n", padsize, avio_tell(pb)); + "invalid padsize %"PRIu32" at:%"PRId64"\n", padsize, avio_tell(pb)); return AVERROR_INVALIDDATA; } @@ -968,7 +970,7 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb) if (rsize > packet_length - padsize) { asf->packet_size_left = 0; av_log(s, AV_LOG_ERROR, - "invalid packet header length %d for pktlen %d-%d at %"PRId64"\n", + "invalid packet header length %d for pktlen %"PRIu32"-%"PRIu32" at %"PRId64"\n", rsize, packet_length, padsize, avio_tell(pb)); return AVERROR_INVALIDDATA; } @@ -1159,6 +1161,16 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) asf_st = asf->asf_st; av_assert0(asf_st); + if (!asf_st->frag_offset && asf->packet_frag_offset) { + av_dlog(s, "skipping asf data pkt with fragment offset for " + "stream:%d, expected:%d but got %d from pkt)\n", + asf->stream_index, asf_st->frag_offset, + asf->packet_frag_offset); + avio_skip(pb, asf->packet_frag_size); + asf->packet_size_left -= asf->packet_frag_size; + continue; + } + if (asf->packet_replic_size == 1) { // frag_offset is here used as the beginning timestamp asf->packet_frag_timestamp = asf->packet_time_start; @@ -1191,6 +1203,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) asf_st->pkt.dts = asf->packet_frag_timestamp - asf->hdr.preroll; asf_st->pkt.stream_index = asf->stream_index; asf_st->pkt.pos = asf_st->packet_pos = asf->packet_pos; + asf_st->pkt_clean = 0; if (asf_st->pkt.data && asf_st->palette_changed) { uint8_t *pal; @@ -1231,6 +1244,11 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) continue; } + if (asf->packet_frag_offset != asf_st->frag_offset && !asf_st->pkt_clean) { + memset(asf_st->pkt.data + asf_st->frag_offset, 0, asf_st->pkt.size - asf_st->frag_offset); + asf_st->pkt_clean = 1; + } + ret = avio_read(pb, asf_st->pkt.data + asf->packet_frag_offset, asf->packet_frag_size); if (ret != asf->packet_frag_size) { @@ -1450,30 +1468,30 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, return pts; } -static void asf_build_simple_index(AVFormatContext *s, int stream_index) +static int asf_build_simple_index(AVFormatContext *s, int stream_index) { ff_asf_guid g; ASFContext *asf = s->priv_data; int64_t current_pos = avio_tell(s->pb); + int ret = 0; - if(avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET) < 0) { - asf->index_read= -1; - return; + if((ret = avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET)) < 0) { + return ret; } - ff_get_guid(s->pb, &g); + if ((ret = ff_get_guid(s->pb, &g)) < 0) + goto end; /* the data object can be followed by other top-level objects, * skip them until the simple index object is reached */ while (ff_guidcmp(&g, &ff_asf_simple_index_header)) { int64_t gsize = avio_rl64(s->pb); if (gsize < 24 || url_feof(s->pb)) { - avio_seek(s->pb, current_pos, SEEK_SET); - asf->index_read= -1; - return; + goto end; } avio_skip(s->pb, gsize - 24); - ff_get_guid(s->pb, &g); + if ((ret = ff_get_guid(s->pb, &g)) < 0) + goto end; } { @@ -1481,7 +1499,8 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) int pct, ict; int i; int64_t av_unused gsize = avio_rl64(s->pb); - ff_get_guid(s->pb, &g); + if ((ret = ff_get_guid(s->pb, &g)) < 0) + goto end; itime = avio_rl64(s->pb); pct = avio_rl32(s->pb); ict = avio_rl32(s->pb); @@ -1504,7 +1523,12 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) } asf->index_read = ict > 1; } +end: +// if (url_feof(s->pb)) { +// ret = 0; +// } avio_seek(s->pb, current_pos, SEEK_SET); + return ret; } static int asf_read_seek(AVFormatContext *s, int stream_index, @@ -1512,6 +1536,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, { ASFContext *asf = s->priv_data; AVStream *st = s->streams[stream_index]; + int ret = 0; if (s->packet_size <= 0) return -1; @@ -1525,10 +1550,20 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, return ret; } - if (!asf->index_read) - asf_build_simple_index(s, stream_index); + /* explicitly handle the case of seeking to 0 */ + if (!pts) { + asf_reset_header(s); + avio_seek(s->pb, s->data_offset, SEEK_SET); + return 0; + } + + if (!asf->index_read) { + ret = asf_build_simple_index(s, stream_index); + if (ret < 0) + asf->index_read = -1; + } - if ((asf->index_read > 0 && st->index_entries)) { + if (asf->index_read > 0 && st->index_entries) { int index = av_index_search_timestamp(st, pts, flags); if (index >= 0) { /* find the position */ diff --git a/chromium/third_party/ffmpeg/libavformat/asfenc.c b/chromium/third_party/ffmpeg/libavformat/asfenc.c index b4a3ffb7ef6..cccbf858c7a 100644 --- a/chromium/third_party/ffmpeg/libavformat/asfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/asfenc.c @@ -34,6 +34,7 @@ #define ASF_INDEXED_INTERVAL 10000000 #define ASF_INDEX_BLOCK (1<<9) +#define ASF_PAYLOADS_PER_PACKET 63 #define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 #define ASF_PACKET_ERROR_CORRECTION_FLAGS \ @@ -223,12 +224,6 @@ static const AVCodecTag codec_asf_bmp_tags[] = { #define PREROLL_TIME 3100 -void ff_put_guid(AVIOContext *s, const ff_asf_guid *g) -{ - av_assert0(sizeof(*g) == 16); - avio_write(s, *g, sizeof(*g)); -} - static void put_str16(AVIOContext *s, const char *tag) { int len; @@ -358,7 +353,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, AVIOContext *pb = s->pb; AVDictionaryEntry *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; - int has_title; + int has_title, has_aspect_ratio = 0; int metadata_count; AVCodecContext *enc; int64_t header_offset, cur_pos, hpos; @@ -384,6 +379,10 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; + if ( enc->codec_type == AVMEDIA_TYPE_VIDEO + && enc->sample_aspect_ratio.num > 0 + && enc->sample_aspect_ratio.den > 0) + has_aspect_ratio++; } if (asf->is_streamed) { @@ -410,14 +409,46 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2); /* ??? */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, s->packet_size); /* packet size */ - avio_wl32(pb, bit_rate); /* Nominal data rate in bps */ + avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); ff_put_guid(pb, &ff_asf_head2_guid); - avio_wl32(pb, 6); - avio_wl16(pb, 0); + avio_wl16(pb, 6); + if (has_aspect_ratio) { + int64_t hpos2; + avio_wl32(pb, 26 + has_aspect_ratio * 84); + hpos2 = put_header(pb, &ff_asf_metadata_header); + avio_wl16(pb, 2 * has_aspect_ratio); + for (n = 0; n < s->nb_streams; n++) { + enc = s->streams[n]->codec; + if ( enc->codec_type == AVMEDIA_TYPE_VIDEO + && enc->sample_aspect_ratio.num > 0 + && enc->sample_aspect_ratio.den > 0) { + AVRational sar = enc->sample_aspect_ratio; + avio_wl16(pb, 0); + // the stream number is set like this below + avio_wl16(pb, n + 1); + avio_wl16(pb, 26); // name_len + avio_wl16(pb, 3); // value_type + avio_wl32(pb, 4); // value_len + avio_put_str16le(pb, "AspectRatioX"); + avio_wl32(pb, sar.num); + avio_wl16(pb, 0); + // the stream number is set like this below + avio_wl16(pb, n + 1); + avio_wl16(pb, 26); // name_len + avio_wl16(pb, 3); // value_type + avio_wl32(pb, 4); // value_len + avio_put_str16le(pb, "AspectRatioY"); + avio_wl32(pb, sar.den); + } + } + end_header(pb, hpos2); + } else { + avio_wl32(pb, 0); + } end_header(pb, hpos); /* title and other infos */ @@ -497,7 +528,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { /* WAVEFORMATEX header */ - int wavsize = ff_put_wav_header(pb, enc); + int wavsize = ff_put_wav_header(pb, enc, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); if (wavsize < 0) return -1; @@ -525,7 +556,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avio_wl16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ - ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1); + ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1, 0); } end_header(pb, hpos); } @@ -536,14 +567,11 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, ff_put_guid(pb, &ff_asf_codec_comment1_header); avio_wl32(pb, s->nb_streams); for (n = 0; n < s->nb_streams; n++) { - AVCodec *p; + const AVCodecDescriptor *codec_desc; const char *desc; - int len; - uint8_t *buf; - AVIOContext *dyn_buf; - enc = s->streams[n]->codec; - p = avcodec_find_encoder(enc->codec_id); + enc = s->streams[n]->codec; + codec_desc = avcodec_descriptor_get(enc->codec_id); if (enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl16(pb, 2); @@ -555,17 +583,24 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, if (enc->codec_id == AV_CODEC_ID_WMAV2) desc = "Windows Media Audio V8"; else - desc = p ? p->name : enc->codec_name; + desc = codec_desc ? codec_desc->name : NULL; - if (avio_open_dyn_buf(&dyn_buf) < 0) - return AVERROR(ENOMEM); + if (desc) { + AVIOContext *dyn_buf; + uint8_t *buf; + int len; - avio_put_str16le(dyn_buf, desc); - len = avio_close_dyn_buf(dyn_buf, &buf); - avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 + if (avio_open_dyn_buf(&dyn_buf) < 0) + return AVERROR(ENOMEM); - avio_write(pb, buf, len); - av_freep(&buf); + avio_put_str16le(dyn_buf, desc); + len = avio_close_dyn_buf(dyn_buf, &buf); + avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 + + avio_write(pb, buf, len); + av_freep(&buf); + } else + avio_wl16(pb, 0); avio_wl16(pb, 0); /* no parameters */ @@ -617,6 +652,7 @@ static int asf_write_header(AVFormatContext *s) ASFContext *asf = s->priv_data; s->packet_size = PACKET_SIZE; + s->max_interleave_delta = 0; asf->nb_packets = 0; asf->index_ptr = av_malloc(sizeof(ASFIndex) * ASF_INDEX_BLOCK); @@ -823,6 +859,8 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst, flush_packet(s); else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1)) flush_packet(s); + else if (asf->packet_nb_payloads == ASF_PAYLOADS_PER_PACKET) + flush_packet(s); } stream->seq++; } diff --git a/chromium/third_party/ffmpeg/libavformat/assdec.c b/chromium/third_party/ffmpeg/libavformat/assdec.c index c9bd63b3c4d..bb953c7276f 100644 --- a/chromium/third_party/ffmpeg/libavformat/assdec.c +++ b/chromium/third_party/ffmpeg/libavformat/assdec.c @@ -27,16 +27,16 @@ #include "libavcodec/internal.h" #include "libavutil/bprint.h" -typedef struct ASSContext{ +typedef struct ASSContext { FFDemuxSubtitlesQueue q; -}ASSContext; +} ASSContext; static int ass_probe(AVProbeData *p) { - const char *header= "[Script Info]"; + const char *header = "[Script Info]"; - if( !memcmp(p->buf , header, strlen(header)) - || !memcmp(p->buf+3, header, strlen(header))) + if (!memcmp(p->buf, header, strlen(header)) || + !memcmp(p->buf + 3, header, strlen(header))) return AVPROBE_SCORE_MAX; return 0; @@ -94,9 +94,9 @@ static int ass_read_header(AVFormatContext *s) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_id= AV_CODEC_ID_SSA; + st->codec->codec_id = AV_CODEC_ID_SSA; - header_remaining= INT_MAX; + header_remaining = INT_MAX; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED); @@ -108,9 +108,9 @@ static int ass_read_header(AVFormatContext *s) break; if (!memcmp(line.str, "[Events]", 8)) - header_remaining= 2; - else if (line.str[0]=='[') - header_remaining= INT_MAX; + header_remaining = 2; + else if (line.str[0] == '[') + header_remaining = INT_MAX; if (header_remaining) { av_bprintf(&header, "%s", line.str); diff --git a/chromium/third_party/ffmpeg/libavformat/astenc.c b/chromium/third_party/ffmpeg/libavformat/astenc.c index edd802cbf39..cf7a12c95d1 100644 --- a/chromium/third_party/ffmpeg/libavformat/astenc.c +++ b/chromium/third_party/ffmpeg/libavformat/astenc.c @@ -113,7 +113,7 @@ static int ast_write_packet(AVFormatContext *s, AVPacket *pkt) AVCodecContext *enc = s->streams[0]->codec; int size = pkt->size / enc->channels; - if (enc->frame_number == 1) + if (s->streams[0]->nb_frames == 0) ast->fbs = size; ffio_wfourcc(pb, "BLCK"); @@ -135,7 +135,7 @@ static int ast_write_trailer(AVFormatContext *s) ASTMuxContext *ast = s->priv_data; AVCodecContext *enc = s->streams[0]->codec; int64_t file_size = avio_tell(pb); - int64_t samples = (file_size - 64 - (32 * enc->frame_number)) / enc->block_align; /* PCM_S16BE_PLANAR */ + int64_t samples = (file_size - 64 - (32 * s->streams[0]->nb_frames)) / enc->block_align; /* PCM_S16BE_PLANAR */ av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples); diff --git a/chromium/third_party/ffmpeg/libavformat/audiointerleave.c b/chromium/third_party/ffmpeg/libavformat/audiointerleave.c index 2aa95f3dc6a..6d24ff5c7fe 100644 --- a/chromium/third_party/ffmpeg/libavformat/audiointerleave.c +++ b/chromium/third_party/ffmpeg/libavformat/audiointerleave.c @@ -34,7 +34,7 @@ void ff_audio_interleave_close(AVFormatContext *s) AudioInterleaveContext *aic = st->priv_data; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) - av_fifo_free(aic->fifo); + av_fifo_freep(&aic->fifo); } } diff --git a/chromium/third_party/ffmpeg/libavformat/avformat.h b/chromium/third_party/ffmpeg/libavformat/avformat.h index 6bd54cec64d..55a3cfbd35d 100644 --- a/chromium/third_party/ffmpeg/libavformat/avformat.h +++ b/chromium/third_party/ffmpeg/libavformat/avformat.h @@ -173,6 +173,58 @@ * * @defgroup lavf_encoding Muxing * @{ + * Muxers take encoded data in the form of @ref AVPacket "AVPackets" and write + * it into files or other output bytestreams in the specified container format. + * + * The main API functions for muxing are avformat_write_header() for writing the + * file header, av_write_frame() / av_interleaved_write_frame() for writing the + * packets and av_write_trailer() for finalizing the file. + * + * At the beginning of the muxing process, the caller must first call + * avformat_alloc_context() to create a muxing context. The caller then sets up + * the muxer by filling the various fields in this context: + * + * - The @ref AVFormatContext.oformat "oformat" field must be set to select the + * muxer that will be used. + * - Unless the format is of the AVFMT_NOFILE type, the @ref AVFormatContext.pb + * "pb" field must be set to an opened IO context, either returned from + * avio_open2() or a custom one. + * - Unless the format is of the AVFMT_NOSTREAMS type, at least one stream must + * be created with the avformat_new_stream() function. The caller should fill + * the @ref AVStream.codec "stream codec context" information, such as the + * codec @ref AVCodecContext.codec_type "type", @ref AVCodecContext.codec_id + * "id" and other parameters (e.g. width / height, the pixel or sample format, + * etc.) as known. The @ref AVCodecContext.time_base "codec timebase" should + * be set to the timebase that the caller desires to use for this stream (note + * that the timebase actually used by the muxer can be different, as will be + * described later). + * - The caller may fill in additional information, such as @ref + * AVFormatContext.metadata "global" or @ref AVStream.metadata "per-stream" + * metadata, @ref AVFormatContext.chapters "chapters", @ref + * AVFormatContext.programs "programs", etc. as described in the + * AVFormatContext documentation. Whether such information will actually be + * stored in the output depends on what the container format and the muxer + * support. + * + * When the muxing context is fully set up, the caller must call + * avformat_write_header() to initialize the muxer internals and write the file + * header. Whether anything actually is written to the IO context at this step + * depends on the muxer, but this function must always be called. Any muxer + * private options must be passed in the options parameter to this function. + * + * The data is then sent to the muxer by repeatedly calling av_write_frame() or + * av_interleaved_write_frame() (consult those functions' documentation for + * discussion on the difference between them; only one of them may be used with + * a single muxing context, they should not be mixed). Do note that the timing + * information on the packets sent to the muxer must be in the corresponding + * AVStream's timebase. That timebase is set by the muxer (in the + * avformat_write_header() step) and may be different from the timebase the + * caller set on the codec context. + * + * Once all the data has been written, the caller must call av_write_trailer() + * to flush any buffered packets and finalize the output file, then close the IO + * context (if any) and finally free the muxing context with + * avformat_free_context(). * @} * * @defgroup lavf_io I/O Read/Write @@ -209,6 +261,8 @@ struct AVFormatContext; +struct AVDeviceInfoList; +struct AVDeviceCapabilitiesQuery; /** * @defgroup metadata_api Public Metadata API @@ -290,6 +344,7 @@ struct AVFormatContext; * Allocate and read the payload of a packet and initialize its * fields with default values. * + * @param s associated IO context * @param pkt packet * @param size desired payload size * @return >0 (read size) if OK, AVERROR_xxx otherwise @@ -305,6 +360,7 @@ int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); * when there is no reasonable way to know (an upper bound of) * the final size. * + * @param s associated IO context * @param pkt packet * @param size amount of data to read * @return >0 (read size) if OK, AVERROR_xxx otherwise, previous data @@ -338,6 +394,8 @@ typedef struct AVProbeData { } AVProbeData; #define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4) +#define AVPROBE_SCORE_STREAM_RETRY (AVPROBE_SCORE_MAX/4-1) + #define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension #define AVPROBE_SCORE_MAX 100 ///< maximum score @@ -453,6 +511,37 @@ typedef struct AVOutputFormat { void (*get_output_timestamp)(struct AVFormatContext *s, int stream, int64_t *dts, int64_t *wall); + /** + * Allows sending messages from application to device. + */ + int (*control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + /** + * Write an uncoded AVFrame. + * + * See av_write_uncoded_frame() for details. + * + * The library will free *frame afterwards, but the muxer can prevent it + * by setting the pointer to NULL. + */ + int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index, + AVFrame **frame, unsigned flags); + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVOutputFormat; /** * @} @@ -581,6 +670,24 @@ typedef struct AVInputFormat { * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. */ int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); + + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVInputFormat; /** * @} @@ -740,6 +847,30 @@ typedef struct AVStream { */ AVPacket attached_pic; + /** + * An array of side data that applies to the whole stream (i.e. the + * container does not allow it to change between packets). + * + * There may be no overlap between the side data in this array and side data + * in the packets. I.e. a given side data is either exported by the muxer + * (demuxing) / set by the caller (muxing) in this array, then it never + * appears in the packets, or the side data is exported / sent through + * the packets (always in the first packet where the value becomes known or + * changes), then it does not appear in this array. + * + * - demuxing: Set by libavformat when the stream is created. + * - muxing: May be set by the caller before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + * + * @see av_format_inject_global_side_data() + */ + AVPacketSideData *side_data; + /** + * The number of elements in the AVStream.side_data array. + */ + int nb_side_data; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and @@ -756,9 +887,16 @@ typedef struct AVStream { int64_t last_dts; int64_t duration_gcd; int duration_count; + int64_t rfps_duration_sum; double (*duration_error)[2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; int64_t codec_info_duration_fields; + + /** + * 0 -> decoder has not been searched for yet. + * >0 -> decoder found + * <0 -> decoder with codec_id == -found_decoder has not been found + */ int found_decoder; int64_t last_duration; @@ -892,6 +1030,29 @@ typedef struct AVStream { */ int pts_wrap_behavior; + /** + * Internal data to prevent doing update_initial_durations() twice + */ + int update_initial_durations_done; + + /** + * Internal data to generate dts from pts + */ + int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; + uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; + + /** + * Internal data to analyze DTS and detect faulty mpeg streams + */ + int64_t last_dts_for_order_check; + uint8_t dts_ordered; + uint8_t dts_misordered; + + /** + * Internal data to inject global side data + */ + int inject_global_side_data; + } AVStream; AVRational av_stream_get_r_frame_rate(const AVStream *s); @@ -943,6 +1104,13 @@ typedef struct AVChapter { /** + * Callback used by devices to communicate with application. + */ +typedef int (*av_format_control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + +/** * The duration of a video can be estimated through various ways, and this enum can be used * to know how the duration was estimated. */ @@ -952,6 +1120,8 @@ enum AVDurationEstimationMethod { AVFMT_DURATION_FROM_BITRATE ///< Duration estimated from bitrate (less accurate) }; +typedef struct AVFormatInternal AVFormatInternal; + /** * Format I/O context. * New fields can be added to the end with minor version bumps. @@ -962,32 +1132,41 @@ enum AVDurationEstimationMethod { */ typedef struct AVFormatContext { /** - * A class for logging and AVOptions. Set by avformat_alloc_context(). + * A class for logging and @ref avoptions. Set by avformat_alloc_context(). * Exports (de)muxer private options if they exist. */ const AVClass *av_class; /** - * Can only be iformat or oformat, not both at the same time. + * The input container format. * - * decoding: set by avformat_open_input(). - * encoding: set by the user. + * Demuxing only, set by avformat_open_input(). */ struct AVInputFormat *iformat; + + /** + * The output container format. + * + * Muxing only, must be set by the caller before avformat_write_header(). + */ struct AVOutputFormat *oformat; /** * Format private data. This is an AVOptions-enabled struct * if and only if iformat/oformat.priv_class is not NULL. + * + * - muxing: set by avformat_write_header() + * - demuxing: set by avformat_open_input() */ void *priv_data; /** * I/O context. * - * decoding: either set by the user before avformat_open_input() (then - * the user must close it manually) or set by avformat_open_input(). - * encoding: set by the user. + * - demuxing: either set by the user before avformat_open_input() (then + * the user must close it manually) or set by avformat_open_input(). + * - muxing: set by the user before avformat_write_header(). The caller must + * take care of closing / freeing the IO context. * * Do NOT set this field if AVFMT_NOFILE flag is set in * iformat/oformat.flags. In such a case, the (de)muxer will handle @@ -996,39 +1175,60 @@ typedef struct AVFormatContext { AVIOContext *pb; /* stream info */ - int ctx_flags; /**< Format-specific flags, see AVFMTCTX_xx */ + /** + * Flags signalling stream properties. A combination of AVFMTCTX_*. + * Set by libavformat. + */ + int ctx_flags; /** + * Number of elements in AVFormatContext.streams. + * + * Set by avformat_new_stream(), must not be modified by any other code. + */ + unsigned int nb_streams; + /** * A list of all streams in the file. New streams are created with * avformat_new_stream(). * - * decoding: streams are created by libavformat in avformat_open_input(). - * If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also - * appear in av_read_frame(). - * encoding: streams are created by the user before avformat_write_header(). + * - demuxing: streams are created by libavformat in avformat_open_input(). + * If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also + * appear in av_read_frame(). + * - muxing: streams are created by the user before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). */ - unsigned int nb_streams; AVStream **streams; - char filename[1024]; /**< input or output filename */ + /** + * input or output filename + * + * - demuxing: set by avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + */ + char filename[1024]; /** - * Decoding: position of the first frame of the component, in + * Position of the first frame of the component, in * AV_TIME_BASE fractional seconds. NEVER set this value directly: * It is deduced from the AVStream values. + * + * Demuxing only, set by libavformat. */ int64_t start_time; /** - * Decoding: duration of the stream, in AV_TIME_BASE fractional + * Duration of the stream, in AV_TIME_BASE fractional * seconds. Only set this value if you know none of the individual stream * durations and also do not set any of them. This is deduced from the * AVStream values if not set. + * + * Demuxing only, set by libavformat. */ int64_t duration; /** - * Decoding: total stream bitrate in bit/s, 0 if not + * Total stream bitrate in bit/s, 0 if not * available. Never set it directly if the file_size and the * duration are known as FFmpeg can compute it automatically. */ @@ -1037,6 +1237,10 @@ typedef struct AVFormatContext { unsigned int packet_size; int max_delay; + /** + * Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*. + * Set by the user before avformat_open_input() / avformat_write_header(). + */ int flags; #define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. #define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. @@ -1048,19 +1252,29 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. #define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted #define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet. +/** + * When muxing, try to avoid writing any random/volatile data to the output. + * This includes any random IDs, real-time timestamps/dates, muxer version, etc. + * + * This flag is mainly intended for testing. + */ +#define AVFMT_FLAG_BITEXACT 0x0400 #define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. /** - * decoding: size of data to probe; encoding: unused. + * Maximum size of the data read from input for determining + * the input container format. + * Demuxing only, set by the caller before avformat_open_input(). */ unsigned int probesize; /** - * decoding: maximum time (in AV_TIME_BASE units) during which the input should - * be analyzed in avformat_find_stream_info(). + * Maximum duration (in AV_TIME_BASE units) of the data read + * from input in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). */ int max_analyze_duration; @@ -1095,8 +1309,8 @@ typedef struct AVFormatContext { * accurate seeking (depends on demuxer). * Demuxers for which a full in-memory index is mandatory will ignore * this. - * muxing : unused - * demuxing: set by user + * - muxing: unused + * - demuxing: set by user */ unsigned int max_index_size; @@ -1114,41 +1328,54 @@ typedef struct AVFormatContext { * in the trailer. To write chapters in the trailer, nb_chapters * must be zero when write_header is called and non-zero when * write_trailer is called. - * muxing : set by user - * demuxing: set by libavformat + * - muxing: set by user + * - demuxing: set by libavformat */ unsigned int nb_chapters; AVChapter **chapters; + /** + * Metadata that applies to the whole file. + * + * - demuxing: set by libavformat in avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + * + * Freed by libavformat in avformat_free_context(). + */ AVDictionary *metadata; /** * Start time of the stream in real world time, in microseconds - * since the unix epoch (00:00 1st January 1970). That is, pts=0 - * in the stream was captured at this real world time. - * - encoding: Set by user. - * - decoding: Unused. + * since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the + * stream was captured at this real world time. + * - muxing: Set by the caller before avformat_write_header(). If set to + * either 0 or AV_NOPTS_VALUE, then the current wall-time will + * be used. + * - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that + * the value may become known after some number of frames + * have been received. */ int64_t start_time_realtime; /** - * decoding: number of frames used to probe fps + * The number of frames used for determining the framerate in + * avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). */ int fps_probe_size; /** * Error recognition; higher values will detect more errors but may * misdetect some more or less valid parts as errors. - * - encoding: unused - * - decoding: Set by user. + * Demuxing only, set by the caller before avformat_open_input(). */ int error_recognition; /** * Custom interrupt callbacks for the I/O layer. * - * decoding: set by the user before avformat_open_input(). - * encoding: set by the user before avformat_write_header() + * demuxing: set by the user before avformat_open_input(). + * muxing: set by the user before avformat_write_header() * (mainly useful for AVFMT_NOFILE formats). The callback * should also be passed to avio_open2() if it's used to * open the file. @@ -1162,6 +1389,24 @@ typedef struct AVFormatContext { #define FF_FDEBUG_TS 0x0001 /** + * Maximum buffering duration for interleaving. + * + * To ensure all the streams are interleaved correctly, + * av_interleaved_write_frame() will wait until it has at least one packet + * for each stream before actually writing any packets to the output file. + * When some streams are "sparse" (i.e. there are large gaps between + * successive packets), this can result in excessive buffering. + * + * This field specifies the maximum difference between the timestamps of the + * first and the last packet in the muxing queue, above which libavformat + * will output a packet regardless of whether it has queued a packet for all + * the streams. + * + * Muxing only, set by the caller before avformat_write_header(). + */ + int64_t max_interleave_delta; + + /** * Transport stream id. * This will be moved into demuxer private options. Thus no API/ABI compatibility */ @@ -1235,14 +1480,14 @@ typedef struct AVFormatContext { /** * Correct single timestamp overflows * - encoding: unused - * - decoding: Set by user via AVOPtions (NO direct access) + * - decoding: Set by user via AVOptions (NO direct access) */ unsigned int correct_ts_overflow; /** * Force seeking to any (also non key) frames. * - encoding: unused - * - decoding: Set by user via AVOPtions (NO direct access) + * - decoding: Set by user via AVOptions (NO direct access) */ int seek2any; @@ -1313,6 +1558,12 @@ typedef struct AVFormatContext { AVRational offset_timebase; /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVFormatInternal *internal; + + /** * IO repositioned flag. * This is set by avformat when the underlaying IO context read pointer * is repositioned, for example when doing byte based seeking. @@ -1343,6 +1594,31 @@ typedef struct AVFormatContext { * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access). */ AVCodec *subtitle_codec; + + /** + * Number of bytes to be written as padding in a metadata header. + * Demuxing: Unused. + * Muxing: Set by user via av_format_set_metadata_header_padding. + */ + int metadata_header_padding; + + /** + * User data. + * This is a place for some private data of the user. + * Mostly usable with control_message_cb or any future callbacks in device's context. + */ + void *opaque; + + /** + * Callback used by devices to communicate with application. + */ + av_format_control_message control_message_cb; + + /** + * Output timestamp offset, in microseconds. + * Muxing: set by user via AVOptions (NO direct access) + */ + int64_t output_ts_offset; } AVFormatContext; int av_format_get_probe_score(const AVFormatContext *s); @@ -1352,6 +1628,18 @@ AVCodec * av_format_get_audio_codec(const AVFormatContext *s); void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +int av_format_get_metadata_header_padding(const AVFormatContext *s); +void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +void * av_format_get_opaque(const AVFormatContext *s); +void av_format_set_opaque(AVFormatContext *s, void *opaque); +av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); + +/** + * This function will cause global side data to be injected in the next packet + * of each stream as well as after any subsequent seek. + */ +void av_format_inject_global_side_data(AVFormatContext *s); /** * Returns the method used to set ctx->duration. @@ -1465,6 +1753,7 @@ const AVClass *avformat_get_class(void); * User is required to call avcodec_close() and avformat_free_context() to * clean up the allocation by avformat_new_stream(). * + * @param s media file handle * @param c If non-NULL, the AVCodecContext corresponding to the new stream * will be initialized to use this codec. This is needed for e.g. codec-specific * defaults to be set, so codec should be provided if it is known. @@ -1522,6 +1811,7 @@ AVInputFormat *av_find_input_format(const char *short_name); /** * Guess the file format. * + * @param pd data to be probed * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. */ @@ -1530,6 +1820,7 @@ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); /** * Guess the file format. * + * @param pd data to be probed * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. * @param score_max A probe score larger that this is required to accept a @@ -1733,6 +2024,8 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt); /** * Seek to the keyframe at timestamp. * 'timestamp' in 'stream_index'. + * + * @param s media file handle * @param stream_index If stream_index is (-1), a default * stream is selected, and timestamp is automatically converted * from AV_TIME_BASE units to the stream specific time_base. @@ -1760,6 +2053,7 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, * keyframes (this may not be supported by all demuxers). * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored. * + * @param s media file handle * @param stream_index index of the stream which is used as time base reference * @param min_ts smallest acceptable timestamp * @param ts target timestamp @@ -1859,50 +2153,109 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options); /** * Write a packet to an output media file. * - * The packet shall contain one audio or video frame. - * The packet must be correctly interleaved according to the container - * specification, if not then av_interleaved_write_frame must be used. + * This function passes the packet directly to the muxer, without any buffering + * or reordering. The caller is responsible for correctly interleaving the + * packets if the format requires it. Callers that want libavformat to handle + * the interleaving should call av_interleaved_write_frame() instead of this + * function. * * @param s media file handle - * @param pkt The packet, which contains the stream_index, buf/buf_size, - * dts/pts, ... - * This can be NULL (at any time, not just at the end), in - * order to immediately flush data buffered within the muxer, - * for muxers that buffer up data internally before writing it - * to the output. + * @param pkt The packet containing the data to be written. Note that unlike + * av_interleaved_write_frame(), this function does not take + * ownership of the packet passed to it (though some muxers may make + * an internal reference to the input packet). + * <br> + * This parameter can be NULL (at any time, not just at the end), in + * order to immediately flush data buffered within the muxer, for + * muxers that buffer up data internally before writing it to the + * output. + * <br> + * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". It is very strongly + * recommended that timing information (@ref AVPacket.pts "pts", @ref + * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to + * correct values. * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush + * + * @see av_interleaved_write_frame() */ int av_write_frame(AVFormatContext *s, AVPacket *pkt); /** * Write a packet to an output media file ensuring correct interleaving. * - * The packet must contain one audio or video frame. - * If the packets are already correctly interleaved, the application should - * call av_write_frame() instead as it is slightly faster. It is also important - * to keep in mind that completely non-interleaved input will need huge amounts - * of memory to interleave with this, so it is preferable to interleave at the - * demuxer level. + * This function will buffer the packets internally as needed to make sure the + * packets in the output file are properly interleaved in the order of + * increasing dts. Callers doing their own interleaving should call + * av_write_frame() instead of this function. * * @param s media file handle - * @param pkt The packet containing the data to be written. pkt->buf must be set - * to a valid AVBufferRef describing the packet data. Libavformat takes - * ownership of this reference and will unref it when it sees fit. The caller - * must not access the data through this reference after this function returns. - * This can be NULL (at any time, not just at the end), to flush the - * interleaving queues. - * Packet's @ref AVPacket.stream_index "stream_index" field must be set to the - * index of the corresponding stream in @ref AVFormatContext.streams - * "s.streams". - * It is very strongly recommended that timing information (@ref AVPacket.pts - * "pts", @ref AVPacket.dts "dts" @ref AVPacket.duration "duration") is set to - * correct values. - * - * @return 0 on success, a negative AVERROR on error. + * @param pkt The packet containing the data to be written. + * <br> + * If the packet is reference-counted, this function will take + * ownership of this reference and unreference it later when it sees + * fit. + * The caller must not access the data through this reference after + * this function returns. If the packet is not reference-counted, + * libavformat will make a copy. + * <br> + * This parameter can be NULL (at any time, not just at the end), to + * flush the interleaving queues. + * <br> + * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". It is very strongly + * recommended that timing information (@ref AVPacket.pts "pts", @ref + * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to + * correct values. + * + * @return 0 on success, a negative AVERROR on error. Libavformat will always + * take care of freeing the packet, even if this function fails. + * + * @see av_write_frame(), AVFormatContext.max_interleave_delta */ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); /** + * Write a uncoded frame to an output media file. + * + * The frame must be correctly interleaved according to the container + * specification; if not, then av_interleaved_write_frame() must be used. + * + * See av_interleaved_write_frame() for details. + */ +int av_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Write a uncoded frame to an output media file. + * + * If the muxer supports it, this function allows to write an AVFrame + * structure directly, without encoding it into a packet. + * It is mostly useful for devices and similar special muxers that use raw + * video or PCM data and will not serialize it into a byte stream. + * + * To test whether it is possible to use it with a given muxer and stream, + * use av_write_uncoded_frame_query(). + * + * The caller gives up ownership of the frame and must not access it + * afterwards. + * + * @return >=0 for success, a negative code on error + */ +int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Test whether a muxer supports uncoded frame. + * + * @return >=0 if an uncoded frame can be written to that muxer and stream, + * <0 if not + */ +int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index); + +/** * Write the stream trailer to an output media file and free the * file private data. * @@ -2002,7 +2355,7 @@ void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size); * @param dump_payload True if the payload must be displayed, too. * @param st AVStream that the packet belongs to */ -void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st); +void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st); /** @@ -2016,8 +2369,8 @@ void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st); * @param dump_payload True if the payload must be displayed, too. * @param st AVStream that the packet belongs to */ -void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, - AVStream *st); +void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload, + const AVStream *st); /** * Get the AVCodecID for the given codec tag tag. @@ -2025,6 +2378,7 @@ void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, * * @param tags list of supported codec_id-codec_tag pairs, as stored * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param tag codec tag to match to a codec ID */ enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); @@ -2034,6 +2388,7 @@ enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned i * * @param tags list of supported codec_id-codec_tag pairs, as stored * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec ID to match to a codec tag */ unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum AVCodecID id); @@ -2053,6 +2408,9 @@ int av_find_default_stream_index(AVFormatContext *s); /** * Get the index for a specific timestamp. + * + * @param st stream that the timestamp belongs to + * @param timestamp timestamp to retrieve the index for * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond * to the timestamp which is <= the requested one, if backward * is 0, then it will be >= @@ -2097,7 +2455,13 @@ void av_url_split(char *proto, int proto_size, char *path, int path_size, const char *url); - +/** + * log a nice Dump of input format context or output format context + * @param ic already initialized Format Context, must not be NULL. + * @param index index of the stream to dump information about + * @param url name of file or URL of stream to print information about + * @param is_output Select whether specified context is of input(0) or output(1) + */ void av_dump_format(AVFormatContext *ic, int index, const char *url, @@ -2149,6 +2513,7 @@ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size); * Return a positive value if the given filename has one of the given * extensions, 0 otherwise. * + * @param filename file name to check against the given extensions * @param extensions a comma-separated list of filename extensions */ int av_match_ext(const char *filename, const char *extensions); @@ -2156,6 +2521,8 @@ int av_match_ext(const char *filename, const char *extensions); /** * Test if the given container can store a codec. * + * @param ofmt container to check for compatibility + * @param codec_id codec to potentially store in container * @param std_compliance standards compliance level, one of FF_COMPLIANCE_* * * @return 1 if codec with ID codec_id can be stored in ofmt, 0 if it cannot. @@ -2183,6 +2550,14 @@ const struct AVCodecTag *avformat_get_riff_video_tags(void); * @return the table mapping RIFF FourCCs for audio to AVCodecID. */ const struct AVCodecTag *avformat_get_riff_audio_tags(void); +/** + * @return the table mapping MOV FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_video_tags(void); +/** + * @return the table mapping MOV FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_audio_tags(void); /** * @} diff --git a/chromium/third_party/ffmpeg/libavformat/avidec.c b/chromium/third_party/ffmpeg/libavformat/avidec.c index 1c6b18c9805..0db9f32ef92 100644 --- a/chromium/third_party/ffmpeg/libavformat/avidec.c +++ b/chromium/third_party/ffmpeg/libavformat/avidec.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdint.h> +#include <inttypes.h> #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -34,6 +34,8 @@ #include "dv.h" #include "internal.h" #include "riff.h" +#include "libavcodec/bytestream.h" +#include "libavcodec/exif.h" typedef struct AVIStream { int64_t frame_offset; /* current frame (video) or byte (audio) counter @@ -222,7 +224,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) if (last_pos == pos || pos == base - 8) avi->non_interleaved = 1; - if (last_pos != pos && (len || !ast->sample_size)) + if (last_pos != pos && len) av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0); @@ -350,6 +352,7 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end) uint16_t size = avio_rl16(s->pb); const char *name = NULL; char buffer[64] = { 0 }; + size = FFMIN(size, tag_end - avio_tell(s->pb)); size -= avio_read(s->pb, buffer, FFMIN(size, sizeof(buffer) - 1)); switch (tag) { @@ -378,6 +381,84 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end) } } +static int avi_extract_stream_metadata(AVStream *st) +{ + GetByteContext gb; + uint8_t *data = st->codec->extradata; + int data_size = st->codec->extradata_size; + int tag, offset; + + if (!data || data_size < 8) { + return AVERROR_INVALIDDATA; + } + + bytestream2_init(&gb, data, data_size); + + tag = bytestream2_get_le32(&gb); + + switch (tag) { + case MKTAG('A', 'V', 'I', 'F'): + // skip 4 byte padding + bytestream2_skip(&gb, 4); + offset = bytestream2_tell(&gb); + bytestream2_init(&gb, data + offset, data_size - offset); + + // decode EXIF tags from IFD, AVI is always little-endian + return avpriv_exif_decode_ifd(st->codec, &gb, 1, 0, &st->metadata); + break; + case MKTAG('C', 'A', 'S', 'I'): + avpriv_request_sample(st->codec, "RIFF stream data tag type CASI (%u)", tag); + break; + case MKTAG('Z', 'o', 'r', 'a'): + avpriv_request_sample(st->codec, "RIFF stream data tag type Zora (%u)", tag); + break; + default: + break; + } + + return 0; +} + +static int calculate_bitrate(AVFormatContext *s) +{ + AVIContext *avi = s->priv_data; + int i, j; + int64_t lensum = 0; + int64_t maxpos = 0; + + for (i = 0; i<s->nb_streams; i++) { + int64_t len = 0; + AVStream *st = s->streams[i]; + + if (!st->nb_index_entries) + continue; + + for (j = 0; j < st->nb_index_entries; j++) + len += st->index_entries[j].size; + maxpos = FFMAX(maxpos, st->index_entries[j-1].pos); + lensum += len; + } + if (maxpos < avi->io_fsize*9/10) // index does not cover the whole file + return 0; + if (lensum*9/10 > maxpos || lensum < maxpos*9/10) // frame sum and filesize mismatch + return 0; + + for (i = 0; i<s->nb_streams; i++) { + int64_t len = 0; + AVStream *st = s->streams[i]; + int64_t duration; + + for (j = 0; j < st->nb_index_entries; j++) + len += st->index_entries[j].size; + + if (st->nb_index_entries < 2 || st->codec->bit_rate > 0) + continue; + duration = st->index_entries[j-1].timestamp - st->index_entries[0].timestamp; + st->codec->bit_rate = av_rescale(8*len, st->time_base.den, duration * st->time_base.num); + } + return 1; +} + static int avi_read_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; @@ -556,7 +637,7 @@ static int avi_read_header(AVFormatContext *s) ast->rate = avio_rl32(pb); if (!(ast->scale && ast->rate)) { av_log(s, AV_LOG_WARNING, - "scale/rate is %u/%u which is invalid. " + "scale/rate is %"PRIu32"/%"PRIu32" which is invalid. " "(This file has been generated by broken software.)\n", ast->scale, ast->rate); @@ -590,6 +671,7 @@ static int avi_read_header(AVFormatContext *s) codec_type = AVMEDIA_TYPE_VIDEO; ast->sample_size = 0; + st->avg_frame_rate = av_inv_q(st->time_base); break; case MKTAG('a', 'u', 'd', 's'): codec_type = AVMEDIA_TYPE_AUDIO; @@ -654,11 +736,8 @@ static int avi_read_header(AVFormatContext *s) st->codec->extradata_size = esize - 10 * 4; } else st->codec->extradata_size = size - 10 * 4; - if (ff_alloc_extradata(st->codec, st->codec->extradata_size)) + if (ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0) return AVERROR(ENOMEM); - avio_read(pb, - st->codec->extradata, - st->codec->extradata_size); } // FIXME: check if the encoder really did this correctly @@ -691,6 +770,8 @@ static int avi_read_header(AVFormatContext *s) /* This is needed to get the pict type which is necessary * for generating correct pts. */ st->need_parsing = AVSTREAM_PARSE_HEADERS; + if (st->codec->codec_tag == MKTAG('V', 'S', 'S', 'H')) + st->need_parsing = AVSTREAM_PARSE_FULL; if (st->codec->codec_tag == 0 && st->codec->height > 0 && st->codec->extradata_size < 1U << 30) { @@ -783,13 +864,17 @@ static int avi_read_header(AVFormatContext *s) st = s->streams[stream_index]; if (size<(1<<30)) { - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, st->codec->extradata_size); } if (st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly avio_r8(pb); + + ret = avi_extract_stream_metadata(st); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "could not decoding EXIF data in stream header.\n"); + } } break; case MKTAG('i', 'n', 'd', 'x'): @@ -864,8 +949,13 @@ fail: if (!avi->index_loaded && pb->seekable) avi_load_index(s); + calculate_bitrate(s); avi->index_loaded |= 1; - avi->non_interleaved |= guess_ni_flag(s) | (s->flags & AVFMT_FLAG_SORT_DTS); + + if ((ret = guess_ni_flag(s)) < 0) + return ret; + + avi->non_interleaved |= ret | (s->flags & AVFMT_FLAG_SORT_DTS); dict_entry = av_dict_get(s->metadata, "ISFT", NULL, 0); if (dict_entry && !strcmp(dict_entry->value, "PotEncoder")) @@ -905,12 +995,14 @@ fail: static int read_gab2_sub(AVStream *st, AVPacket *pkt) { if (pkt->size >= 7 && + pkt->size < INT_MAX - AVPROBE_PADDING_SIZE && !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data + 5) == 2) { uint8_t desc[256]; int score = AVPROBE_SCORE_EXTENSION, ret; AVIStream *ast = st->priv_data; AVInputFormat *sub_demuxer; AVRational time_base; + int size; AVIOContext *pb = avio_alloc_context(pkt->data + 7, pkt->size - 7, 0, NULL, NULL, NULL, NULL); @@ -928,9 +1020,15 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) avio_rl16(pb); /* flags? */ avio_rl32(pb); /* data size */ - pd = (AVProbeData) { .buf = pb->buf_ptr, - .buf_size = pb->buf_end - pb->buf_ptr }; - if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score))) + size = pb->buf_end - pb->buf_ptr; + pd = (AVProbeData) { .buf = av_mallocz(size + AVPROBE_PADDING_SIZE), + .buf_size = size }; + if (!pd.buf) + goto error; + memcpy(pd.buf, pb->buf_ptr, size); + sub_demuxer = av_probe_input_format2(&pd, 1, &score); + av_freep(&pd.buf); + if (!sub_demuxer) goto error; if (!(ast->sub_ctx = avformat_alloc_context())) @@ -1063,7 +1161,7 @@ start_sync: ast = st->priv_data; if (!ast) { - av_log(s, AV_LOG_WARNING, "Skiping foreign stream %d packet\n", n); + av_log(s, AV_LOG_WARNING, "Skipping foreign stream %d packet\n", n); continue; } @@ -1129,7 +1227,7 @@ start_sync: ast->packet_size = size + 8; ast->remaining = size; - if (size || !ast->sample_size) { + if (size) { uint64_t pos = avio_tell(pb) - 8; if (!st->index_entries || !st->nb_index_entries || st->index_entries[st->nb_index_entries - 1].pos < pos) { @@ -1316,7 +1414,7 @@ FF_ENABLE_DEPRECATION_WARNINGS AVIndexEntry *e; int index; - index = av_index_search_timestamp(st, ast->frame_offset, 0); + index = av_index_search_timestamp(st, ast->frame_offset, AVSEEK_FLAG_ANY); e = &st->index_entries[index]; if (index >= 0 && e->timestamp == ast->frame_offset) { @@ -1456,14 +1554,69 @@ static int avi_read_idx1(AVFormatContext *s, int size) return 0; } +/* Scan the index and consider any file with streams more than + * 2 seconds or 64MB apart non-interleaved. */ +static int check_stream_max_drift(AVFormatContext *s) +{ + int64_t min_pos, pos; + int i; + int *idx = av_mallocz_array(s->nb_streams, sizeof(*idx)); + if (!idx) + return AVERROR(ENOMEM); + for (min_pos = pos = 0; min_pos != INT64_MAX; pos = min_pos + 1LU) { + int64_t max_dts = INT64_MIN / 2; + int64_t min_dts = INT64_MAX / 2; + int64_t max_buffer = 0; + + min_pos = INT64_MAX; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + int n = st->nb_index_entries; + while (idx[i] < n && st->index_entries[idx[i]].pos < pos) + idx[i]++; + if (idx[i] < n) { + int64_t dts; + dts = av_rescale_q(st->index_entries[idx[i]].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q); + min_dts = FFMIN(min_dts, dts); + min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos); + } + } + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + + if (idx[i] && min_dts != INT64_MAX / 2) { + int64_t dts; + dts = av_rescale_q(st->index_entries[idx[i] - 1].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q); + max_dts = FFMAX(max_dts, dts); + max_buffer = FFMAX(max_buffer, + av_rescale(dts - min_dts, + st->codec->bit_rate, + AV_TIME_BASE)); + } + } + if (max_dts - min_dts > 2 * AV_TIME_BASE || + max_buffer > 1024 * 1024 * 8 * 8) { + av_free(idx); + return 1; + } + } + av_free(idx); + return 0; +} + static int guess_ni_flag(AVFormatContext *s) { int i; int64_t last_start = 0; int64_t first_end = INT64_MAX; int64_t oldpos = avio_tell(s->pb); - int *idx; - int64_t min_pos, pos; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -1487,35 +1640,11 @@ static int guess_ni_flag(AVFormatContext *s) first_end = st->index_entries[n - 1].pos; } avio_seek(s->pb, oldpos, SEEK_SET); + if (last_start > first_end) return 1; - idx= av_calloc(s->nb_streams, sizeof(*idx)); - if (!idx) - return 0; - for (min_pos=pos=0; min_pos!=INT64_MAX; pos= min_pos+1LU) { - int64_t max_dts = INT64_MIN/2, min_dts= INT64_MAX/2; - min_pos = INT64_MAX; - for (i=0; i<s->nb_streams; i++) { - AVStream *st = s->streams[i]; - AVIStream *ast = st->priv_data; - int n= st->nb_index_entries; - while (idx[i]<n && st->index_entries[idx[i]].pos < pos) - idx[i]++; - if (idx[i] < n) { - min_dts = FFMIN(min_dts, av_rescale_q(st->index_entries[idx[i]].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q)); - min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos); - } - if (idx[i]) - max_dts = FFMAX(max_dts, av_rescale_q(st->index_entries[idx[i]-1].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q)); - } - if (max_dts - min_dts > 2*AV_TIME_BASE) { - av_free(idx); - return 1; - } - } - av_free(idx); - return 0; + return check_stream_max_drift(s); } static int avi_load_index(AVFormatContext *s) @@ -1734,6 +1863,7 @@ AVInputFormat ff_avi_demuxer = { .name = "avi", .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), .priv_data_size = sizeof(AVIContext), + .extensions = "avi", .read_probe = avi_probe, .read_header = avi_read_header, .read_packet = avi_read_packet, diff --git a/chromium/third_party/ffmpeg/libavformat/avienc.c b/chromium/third_party/ffmpeg/libavformat/avienc.c index 45f7a203da8..89e2a539a05 100644 --- a/chromium/third_party/ffmpeg/libavformat/avienc.c +++ b/chromium/third_party/ffmpeg/libavformat/avienc.c @@ -32,6 +32,8 @@ #include "libavutil/dict.h" #include "libavutil/avassert.h" #include "libavutil/timestamp.h" +#include "libavutil/pixdesc.h" +#include "libavcodec/raw.h" /* * TODO: @@ -64,9 +66,9 @@ typedef struct { int entry; AVIIndex indexes; -} AVIStream ; +} AVIStream; -static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) +static inline AVIIentry *avi_get_ientry(AVIIndex *idx, int ent_id) { int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; int id = ent_id % AVI_INDEX_CLUSTER_SIZE; @@ -74,15 +76,15 @@ static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) } static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb, - const char* riff_tag, const char* list_tag) + const char *riff_tag, const char *list_tag) { - AVIContext *avi= s->priv_data; + AVIContext *avi = s->priv_data; int64_t loff; int i; avi->riff_id++; - for (i=0; i<s->nb_streams; i++){ - AVIStream *avist= s->streams[i]->priv_data; + for (i = 0; i < s->nb_streams; i++) { + AVIStream *avist = s->streams[i]->priv_data; avist->indexes.entry = 0; } @@ -93,10 +95,10 @@ static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb, return loff; } -static char* avi_stream2fourcc(char* tag, int index, enum AVMediaType type) +static char *avi_stream2fourcc(char *tag, int index, enum AVMediaType type) { - tag[0] = '0' + index/10; - tag[1] = '0' + index%10; + tag[0] = '0' + index / 10; + tag[1] = '0' + index % 10; if (type == AVMEDIA_TYPE_VIDEO) { tag[2] = 'd'; tag[3] = 'c'; @@ -112,31 +114,30 @@ static char* avi_stream2fourcc(char* tag, int index, enum AVMediaType type) return tag; } -static int avi_write_counters(AVFormatContext* s, int riff_id) +static int avi_write_counters(AVFormatContext *s, int riff_id) { AVIOContext *pb = s->pb; AVIContext *avi = s->priv_data; int n, au_byterate, au_ssize, au_scale, nb_frames = 0; int64_t file_size; - AVCodecContext* stream; + AVCodecContext *stream; file_size = avio_tell(pb); - for(n = 0; n < s->nb_streams; n++) { - AVIStream *avist= s->streams[n]->priv_data; + for (n = 0; n < s->nb_streams; n++) { + AVIStream *avist = s->streams[n]->priv_data; av_assert0(avist->frames_hdr_strm); stream = s->streams[n]->codec; avio_seek(pb, avist->frames_hdr_strm, SEEK_SET); ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); - if(au_ssize == 0) { + if (au_ssize == 0) avio_wl32(pb, avist->packet_count); - } else { + else avio_wl32(pb, avist->audio_strm_length / au_ssize); - } - if(stream->codec_type == AVMEDIA_TYPE_VIDEO) + if (stream->codec_type == AVMEDIA_TYPE_VIDEO) nb_frames = FFMAX(nb_frames, avist->packet_count); } - if(riff_id == 1) { + if (riff_id == 1) { av_assert0(avi->frames_hdr_all); avio_seek(pb, avi->frames_hdr_all, SEEK_SET); avio_wl32(pb, nb_frames); @@ -154,6 +155,7 @@ static int avi_write_header(AVFormatContext *s) AVCodecContext *stream, *video_enc; int64_t list1, list2, strh, strf; AVDictionaryEntry *t = NULL; + int padding; if (s->nb_streams > AVI_MAX_STREAM_COUNT) { av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n", @@ -161,9 +163,9 @@ static int avi_write_header(AVFormatContext *s) return AVERROR(EINVAL); } - for(n=0;n<s->nb_streams;n++) { - s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream)); - if(!s->streams[n]->priv_data) + for (n = 0; n < s->nb_streams; n++) { + s->streams[n]->priv_data = av_mallocz(sizeof(AVIStream)); + if (!s->streams[n]->priv_data) return AVERROR(ENOMEM); } @@ -177,8 +179,8 @@ static int avi_write_header(AVFormatContext *s) bitrate = 0; video_enc = NULL; - for(n=0;n<s->nb_streams;n++) { - stream = s->streams[n]->codec; + for (n = 0; n < s->nb_streams; n++) { + stream = s->streams[n]->codec; bitrate += stream->bit_rate; if (stream->codec_type == AVMEDIA_TYPE_VIDEO) video_enc = stream; @@ -186,23 +188,23 @@ static int avi_write_header(AVFormatContext *s) nb_frames = 0; - if(video_enc){ - avio_wl32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); - } else { + if (video_enc) + avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_enc->time_base.num / + video_enc->time_base.den)); + else avio_wl32(pb, 0); - } avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */ avio_wl32(pb, 0); /* padding */ if (!pb->seekable) - avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ + avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ else - avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ + avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */ avio_wl32(pb, nb_frames); /* nb frames, filled later */ avio_wl32(pb, 0); /* initial frame */ avio_wl32(pb, s->nb_streams); /* nb streams */ avio_wl32(pb, 1024 * 1024); /* suggested buffer size */ - if(video_enc){ + if (video_enc) { avio_wl32(pb, video_enc->width); avio_wl32(pb, video_enc->height); } else { @@ -215,8 +217,8 @@ static int avi_write_header(AVFormatContext *s) avio_wl32(pb, 0); /* reserved */ /* stream list */ - for(i=0;i<n;i++) { - AVIStream *avist= s->streams[i]->priv_data; + for (i = 0; i < n; i++) { + AVIStream *avist = s->streams[i]->priv_data; list2 = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "strl"); @@ -224,21 +226,30 @@ static int avi_write_header(AVFormatContext *s) /* stream generic header */ strh = ff_start_tag(pb, "strh"); - switch(stream->codec_type) { + switch (stream->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (stream->codec_id != AV_CODEC_ID_XSUB) { - av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n"); + av_log(s, AV_LOG_ERROR, + "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n"); return AVERROR_PATCHWELCOME; } - case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break; - case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break; -// case AVMEDIA_TYPE_TEXT : ffio_wfourcc(pb, "txts"); break; - case AVMEDIA_TYPE_DATA : ffio_wfourcc(pb, "dats"); break; + case AVMEDIA_TYPE_VIDEO: + ffio_wfourcc(pb, "vids"); + break; + case AVMEDIA_TYPE_AUDIO: + ffio_wfourcc(pb, "auds"); + break; +// case AVMEDIA_TYPE_TEXT: +// ffio_wfourcc(pb, "txts"); +// break; + case AVMEDIA_TYPE_DATA: + ffio_wfourcc(pb, "dats"); + break; } - if(stream->codec_type == AVMEDIA_TYPE_VIDEO || - stream->codec_id == AV_CODEC_ID_XSUB) + if (stream->codec_type == AVMEDIA_TYPE_VIDEO || + stream->codec_id == AV_CODEC_ID_XSUB) avio_wl32(pb, stream->codec_tag); else avio_wl32(pb, 1); @@ -256,23 +267,25 @@ static int avi_write_header(AVFormatContext *s) au_scale = 1; } avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate); - if(stream->codec_id == AV_CODEC_ID_XSUB) + if (stream->codec_id == AV_CODEC_ID_XSUB) au_scale = au_byterate = 0; avio_wl32(pb, au_scale); /* scale */ avio_wl32(pb, au_byterate); /* rate */ avio_wl32(pb, 0); /* start */ - avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */ + /* remember this offset to fill later */ + avist->frames_hdr_strm = avio_tell(pb); if (!pb->seekable) - avio_wl32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ + /* FIXME: this may be broken, but who cares */ + avio_wl32(pb, AVI_MAX_RIFF_SIZE); else - avio_wl32(pb, 0); /* length, XXX: filled later */ + avio_wl32(pb, 0); /* length, XXX: filled later */ /* suggested buffer size */ //FIXME set at the end to largest chunk - if(stream->codec_type == AVMEDIA_TYPE_VIDEO) + if (stream->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl32(pb, 1024 * 1024); - else if(stream->codec_type == AVMEDIA_TYPE_AUDIO) + else if (stream->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl32(pb, 12 * 1024); else avio_wl32(pb, 0); @@ -283,45 +296,60 @@ static int avi_write_header(AVFormatContext *s) avio_wl16(pb, stream->height); ff_end_tag(pb, strh); - if(stream->codec_type != AVMEDIA_TYPE_DATA){ - int ret; - - strf = ff_start_tag(pb, "strf"); - switch(stream->codec_type) { - case AVMEDIA_TYPE_SUBTITLE: - // XSUB subtitles behave like video tracks, other subtitles - // are not (yet) supported. - if (stream->codec_id != AV_CODEC_ID_XSUB) break; - case AVMEDIA_TYPE_VIDEO: - ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0); - break; - case AVMEDIA_TYPE_AUDIO: - if ((ret = ff_put_wav_header(pb, stream)) < 0) { - return ret; + if (stream->codec_type != AVMEDIA_TYPE_DATA) { + int ret; + enum AVPixelFormat pix_fmt; + + strf = ff_start_tag(pb, "strf"); + switch (stream->codec_type) { + case AVMEDIA_TYPE_SUBTITLE: + /* XSUB subtitles behave like video tracks, other subtitles + * are not (yet) supported. */ + if (stream->codec_id != AV_CODEC_ID_XSUB) + break; + case AVMEDIA_TYPE_VIDEO: + /* WMP expects RGB 5:5:5 rawvideo in avi to have bpp set to 16. */ + if ( !stream->codec_tag + && stream->codec_id == AV_CODEC_ID_RAWVIDEO + && stream->pix_fmt == AV_PIX_FMT_RGB555LE + && stream->bits_per_coded_sample == 15) + stream->bits_per_coded_sample = 16; + ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0); + pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi, + stream->bits_per_coded_sample); + if ( !stream->codec_tag + && stream->codec_id == AV_CODEC_ID_RAWVIDEO + && stream->pix_fmt != pix_fmt + && stream->pix_fmt != AV_PIX_FMT_NONE) + av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to avi, output file will be unreadable\n", + av_get_pix_fmt_name(stream->pix_fmt)); + break; + case AVMEDIA_TYPE_AUDIO: + if ((ret = ff_put_wav_header(pb, stream, 0)) < 0) + return ret; + break; + default: + av_log(s, AV_LOG_ERROR, + "Invalid or not supported codec type '%s' found in the input\n", + (char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?")); + return AVERROR(EINVAL); } - break; - default: - av_log(s, AV_LOG_ERROR, - "Invalid or not supported codec type '%s' found in the input\n", - (char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?")); - return AVERROR(EINVAL); - } - ff_end_tag(pb, strf); - if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) { - ff_riff_write_info_tag(s->pb, "strn", t->value); - t = NULL; - } - if(stream->codec_id == AV_CODEC_ID_XSUB - && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { - const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1); - t = NULL; - if (langstr) { - char* str = av_asprintf("Subtitle - %s-xx;02", langstr); - ff_riff_write_info_tag(s->pb, "strn", str); - av_free(str); + ff_end_tag(pb, strf); + if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) { + ff_riff_write_info_tag(s->pb, "strn", t->value); + t = NULL; + } + if (stream->codec_id == AV_CODEC_ID_XSUB + && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { + const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1); + t = NULL; + if (langstr) { + char* str = av_asprintf("Subtitle - %s-xx;02", langstr); + ff_riff_write_info_tag(s->pb, "strn", str); + av_free(str); + } } } - } if (pb->seekable) { unsigned char tag[5]; @@ -330,47 +358,47 @@ static int avi_write_header(AVFormatContext *s) /* Starting to lay out AVI OpenDML master index. * We want to make it JUNK entry for now, since we'd * like to get away without making AVI an OpenDML one - * for compatibility reasons. - */ - avist->indexes.entry = avist->indexes.ents_allocated = 0; + * for compatibility reasons. */ + avist->indexes.entry = avist->indexes.ents_allocated = 0; avist->indexes.indx_start = ff_start_tag(pb, "JUNK"); - avio_wl16(pb, 4); /* wLongsPerEntry */ - avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ - avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ - avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */ + avio_wl16(pb, 4); /* wLongsPerEntry */ + avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ + avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ + avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */ ffio_wfourcc(pb, avi_stream2fourcc(tag, i, stream->codec_type)); - /* dwChunkId */ - avio_wl64(pb, 0); /* dwReserved[3] - avio_wl32(pb, 0); Must be 0. */ - for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) - avio_wl64(pb, 0); + /* dwChunkId */ + avio_wl64(pb, 0); /* dwReserved[3] */ + // avio_wl32(pb, 0); /* Must be 0. */ + for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++) + avio_wl64(pb, 0); ff_end_tag(pb, avist->indexes.indx_start); } - if( stream->codec_type == AVMEDIA_TYPE_VIDEO - && s->streams[i]->sample_aspect_ratio.num>0 - && s->streams[i]->sample_aspect_ratio.den>0){ - int vprp= ff_start_tag(pb, "vprp"); + if (stream->codec_type == AVMEDIA_TYPE_VIDEO && + s->streams[i]->sample_aspect_ratio.num > 0 && + s->streams[i]->sample_aspect_ratio.den > 0) { + int vprp = ff_start_tag(pb, "vprp"); AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, - (AVRational){stream->width, stream->height}); + (AVRational) { stream->width, + stream->height }); int num, den; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); - avio_wl32(pb, 0); //video format = unknown - avio_wl32(pb, 0); //video standard= unknown - avio_wl32(pb, lrintf(1.0/av_q2d(stream->time_base))); - avio_wl32(pb, stream->width ); + avio_wl32(pb, 0); // video format = unknown + avio_wl32(pb, 0); // video standard = unknown + avio_wl32(pb, lrintf(1.0 / av_q2d(stream->time_base))); + avio_wl32(pb, stream->width); avio_wl32(pb, stream->height); avio_wl16(pb, den); avio_wl16(pb, num); - avio_wl32(pb, stream->width ); + avio_wl32(pb, stream->width); avio_wl32(pb, stream->height); - avio_wl32(pb, 1); //progressive FIXME + avio_wl32(pb, 1); // progressive FIXME avio_wl32(pb, stream->height); - avio_wl32(pb, stream->width ); + avio_wl32(pb, stream->width); avio_wl32(pb, stream->height); - avio_wl32(pb, stream->width ); + avio_wl32(pb, stream->width); avio_wl32(pb, 0); avio_wl32(pb, 0); @@ -388,8 +416,8 @@ static int avi_write_header(AVFormatContext *s) ffio_wfourcc(pb, "odml"); ffio_wfourcc(pb, "dmlh"); avio_wl32(pb, 248); - for (i = 0; i < 248; i+= 4) - avio_wl32(pb, 0); + for (i = 0; i < 248; i += 4) + avio_wl32(pb, 0); ff_end_tag(pb, avi->odml_list); } @@ -397,11 +425,18 @@ static int avi_write_header(AVFormatContext *s) ff_riff_write_info(s); + + padding = s->metadata_header_padding; + if (padding < 0) + padding = 1016; + /* some padding for easier tag editing */ - list2 = ff_start_tag(pb, "JUNK"); - for (i = 0; i < 1016; i += 4) - avio_wl32(pb, 0); - ff_end_tag(pb, list2); + if (padding) { + list2 = ff_start_tag(pb, "JUNK"); + for (i = padding; i > 0; i -= 4) + avio_wl32(pb, 0); + ff_end_tag(pb, list2); + } avi->movi_list = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "movi"); @@ -427,47 +462,47 @@ static int avi_write_ix(AVFormatContext *s) return AVERROR(EINVAL); } - for (i=0;i<s->nb_streams;i++) { - AVIStream *avist= s->streams[i]->priv_data; - int64_t ix, pos; - - avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type); - ix_tag[3] = '0' + i; - - /* Writing AVI OpenDML leaf index chunk */ - ix = avio_tell(pb); - ffio_wfourcc(pb, ix_tag); /* ix?? */ - avio_wl32(pb, avist->indexes.entry * 8 + 24); - /* chunk size */ - avio_wl16(pb, 2); /* wLongsPerEntry */ - avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ - avio_w8(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ - avio_wl32(pb, avist->indexes.entry); - /* nEntriesInUse */ - ffio_wfourcc(pb, tag); /* dwChunkId */ - avio_wl64(pb, avi->movi_list);/* qwBaseOffset */ - avio_wl32(pb, 0); /* dwReserved_3 (must be 0) */ - - for (j=0; j<avist->indexes.entry; j++) { - AVIIentry* ie = avi_get_ientry(&avist->indexes, j); - avio_wl32(pb, ie->pos + 8); - avio_wl32(pb, ((uint32_t)ie->len & ~0x80000000) | + for (i = 0; i < s->nb_streams; i++) { + AVIStream *avist = s->streams[i]->priv_data; + int64_t ix, pos; + + avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type); + ix_tag[3] = '0' + i; + + /* Writing AVI OpenDML leaf index chunk */ + ix = avio_tell(pb); + ffio_wfourcc(pb, ix_tag); /* ix?? */ + avio_wl32(pb, avist->indexes.entry * 8 + 24); + /* chunk size */ + avio_wl16(pb, 2); /* wLongsPerEntry */ + avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ + avio_w8(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ + avio_wl32(pb, avist->indexes.entry); + /* nEntriesInUse */ + ffio_wfourcc(pb, tag); /* dwChunkId */ + avio_wl64(pb, avi->movi_list); /* qwBaseOffset */ + avio_wl32(pb, 0); /* dwReserved_3 (must be 0) */ + + for (j = 0; j < avist->indexes.entry; j++) { + AVIIentry *ie = avi_get_ientry(&avist->indexes, j); + avio_wl32(pb, ie->pos + 8); + avio_wl32(pb, ((uint32_t) ie->len & ~0x80000000) | (ie->flags & 0x10 ? 0 : 0x80000000)); - } - avio_flush(pb); - pos = avio_tell(pb); - - /* Updating one entry in the AVI OpenDML master index */ - avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET); - ffio_wfourcc(pb, "indx"); /* enabling this entry */ - avio_skip(pb, 8); - avio_wl32(pb, avi->riff_id); /* nEntriesInUse */ - avio_skip(pb, 16*avi->riff_id); - avio_wl64(pb, ix); /* qwOffset */ - avio_wl32(pb, pos - ix); /* dwSize */ - avio_wl32(pb, avist->indexes.entry); /* dwDuration */ - - avio_seek(pb, pos, SEEK_SET); + } + avio_flush(pb); + pos = avio_tell(pb); + + /* Updating one entry in the AVI OpenDML master index */ + avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET); + ffio_wfourcc(pb, "indx"); /* enabling this entry */ + avio_skip(pb, 8); + avio_wl32(pb, avi->riff_id); /* nEntriesInUse */ + avio_skip(pb, 16 * avi->riff_id); + avio_wl64(pb, ix); /* qwOffset */ + avio_wl32(pb, pos - ix); /* dwSize */ + avio_wl32(pb, avist->indexes.entry); /* dwDuration */ + + avio_seek(pb, pos, SEEK_SET); } return 0; } @@ -482,31 +517,31 @@ static int avi_write_idx1(AVFormatContext *s) if (pb->seekable) { AVIStream *avist; - AVIIentry* ie = 0, *tie; + AVIIentry *ie = 0, *tie; int empty, stream_id = -1; idx_chunk = ff_start_tag(pb, "idx1"); - for(i=0; i<s->nb_streams; i++){ - avist= s->streams[i]->priv_data; - avist->entry=0; + for (i = 0; i < s->nb_streams; i++) { + avist = s->streams[i]->priv_data; + avist->entry = 0; } do { empty = 1; - for (i=0; i<s->nb_streams; i++) { - avist= s->streams[i]->priv_data; - if (avist->indexes.entry <= avist->entry) - continue; - - tie = avi_get_ientry(&avist->indexes, avist->entry); - if (empty || tie->pos < ie->pos) { - ie = tie; - stream_id = i; - } - empty = 0; + for (i = 0; i < s->nb_streams; i++) { + avist = s->streams[i]->priv_data; + if (avist->indexes.entry <= avist->entry) + continue; + + tie = avi_get_ientry(&avist->indexes, avist->entry); + if (empty || tie->pos < ie->pos) { + ie = tie; + stream_id = i; + } + empty = 0; } if (!empty) { - avist= s->streams[stream_id]->priv_data; + avist = s->streams[stream_id]->priv_data; avi_stream2fourcc(tag, stream_id, s->streams[stream_id]->codec->codec_type); ffio_wfourcc(pb, tag); @@ -525,28 +560,29 @@ static int avi_write_idx1(AVFormatContext *s) static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) { - AVIContext *avi = s->priv_data; - AVIOContext *pb = s->pb; unsigned char tag[5]; - unsigned int flags=0; - const int stream_index= pkt->stream_index; - AVIStream *avist= s->streams[stream_index]->priv_data; - AVCodecContext *enc= s->streams[stream_index]->codec; - int size= pkt->size; + unsigned int flags = 0; + const int stream_index = pkt->stream_index; + int size = pkt->size; + AVIContext *avi = s->priv_data; + AVIOContext *pb = s->pb; + AVIStream *avist = s->streams[stream_index]->priv_data; + AVCodecContext *enc = s->streams[stream_index]->codec; av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index); - while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count){ + while (enc->block_align == 0 && pkt->dts != AV_NOPTS_VALUE && + pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) { AVPacket empty_packet; - if(pkt->dts - avist->packet_count > 60000){ + if (pkt->dts - avist->packet_count > 60000) { av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", pkt->dts - avist->packet_count); return AVERROR(EINVAL); } av_init_packet(&empty_packet); - empty_packet.size= 0; - empty_packet.data= NULL; - empty_packet.stream_index= stream_index; + empty_packet.size = 0; + empty_packet.data = NULL; + empty_packet.stream_index = stream_index; avi_write_packet(s, &empty_packet); av_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(pkt->dts), avist->packet_count); } @@ -555,7 +591,6 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) // Make sure to put an OpenDML chunk when the file size exceeds the limits if (pb->seekable && (avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { - avi_write_ix(s); ff_end_tag(pb, avi->movi_list); @@ -567,32 +602,32 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) } avi_stream2fourcc(tag, stream_index, enc->codec_type); - if(pkt->flags&AV_PKT_FLAG_KEY) + if (pkt->flags & AV_PKT_FLAG_KEY) flags = 0x10; - if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { - avist->audio_strm_length += size; - } + if (enc->codec_type == AVMEDIA_TYPE_AUDIO) + avist->audio_strm_length += size; if (s->pb->seekable) { - AVIIndex* idx = &avist->indexes; + AVIIndex *idx = &avist->indexes; int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; if (idx->ents_allocated <= idx->entry) { idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1); if (!idx->cluster) { idx->ents_allocated = 0; - idx->entry = 0; + idx->entry = 0; return AVERROR(ENOMEM); } - idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); + idx->cluster[cl] = + av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry)); if (!idx->cluster[cl]) return AVERROR(ENOMEM); idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; } idx->cluster[cl][id].flags = flags; - idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list; - idx->cluster[cl][id].len = size; + idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list; + idx->cluster[cl][id].len = size; idx->entry++; } @@ -613,7 +648,7 @@ static int avi_write_trailer(AVFormatContext *s) int i, j, n, nb_frames; int64_t file_size; - if (pb->seekable){ + if (pb->seekable) { if (avi->riff_id == 1) { ff_end_tag(pb, avi->movi_list); res = avi_write_idx1(s); @@ -628,17 +663,17 @@ static int avi_write_trailer(AVFormatContext *s) ffio_wfourcc(pb, "LIST"); /* Making this AVI OpenDML one */ avio_skip(pb, 16); - for (n=nb_frames=0;n<s->nb_streams;n++) { + for (n = nb_frames = 0; n < s->nb_streams; n++) { AVCodecContext *stream = s->streams[n]->codec; - AVIStream *avist= s->streams[n]->priv_data; + AVIStream *avist = s->streams[n]->priv_data; if (stream->codec_type == AVMEDIA_TYPE_VIDEO) { if (nb_frames < avist->packet_count) nb_frames = avist->packet_count; } else { - if (stream->codec_id == AV_CODEC_ID_MP2 || stream->codec_id == AV_CODEC_ID_MP3) { + if (stream->codec_id == AV_CODEC_ID_MP2 || + stream->codec_id == AV_CODEC_ID_MP3) nb_frames += avist->packet_count; - } } } avio_wl32(pb, nb_frames); @@ -648,29 +683,29 @@ static int avi_write_trailer(AVFormatContext *s) } } - for (i=0; i<s->nb_streams; i++) { - AVIStream *avist= s->streams[i]->priv_data; - for (j=0; j<avist->indexes.ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) - av_freep(&avist->indexes.cluster[j]); - av_freep(&avist->indexes.cluster); - avist->indexes.ents_allocated = avist->indexes.entry = 0; + for (i = 0; i < s->nb_streams; i++) { + AVIStream *avist = s->streams[i]->priv_data; + for (j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++) + av_freep(&avist->indexes.cluster[j]); + av_freep(&avist->indexes.cluster); + avist->indexes.ents_allocated = avist->indexes.entry = 0; } return res; } AVOutputFormat ff_avi_muxer = { - .name = "avi", - .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), - .mime_type = "video/x-msvideo", - .extensions = "avi", - .priv_data_size = sizeof(AVIContext), - .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3, - .video_codec = AV_CODEC_ID_MPEG4, - .write_header = avi_write_header, - .write_packet = avi_write_packet, - .write_trailer = avi_write_trailer, - .codec_tag = (const AVCodecTag* const []){ + .name = "avi", + .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), + .mime_type = "video/x-msvideo", + .extensions = "avi", + .priv_data_size = sizeof(AVIContext), + .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3, + .video_codec = AV_CODEC_ID_MPEG4, + .write_header = avi_write_header, + .write_packet = avi_write_packet, + .write_trailer = avi_write_trailer, + .codec_tag = (const AVCodecTag * const []) { ff_codec_bmp_tags, ff_codec_wav_tags, 0 }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/avio.c b/chromium/third_party/ffmpeg/libavformat/avio.c index 225d9821a0a..4edaaa62150 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.c +++ b/chromium/third_party/ffmpeg/libavformat/avio.c @@ -215,18 +215,12 @@ int ffurl_connect(URLContext *uc, AVDictionary **options) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "0123456789+-." -int ffurl_alloc(URLContext **puc, const char *filename, int flags, - const AVIOInterruptCB *int_cb) +static struct URLProtocol *url_find_protocol(const char *filename) { URLProtocol *up = NULL; char proto_str[128], proto_nested[128], *ptr; size_t proto_len = strspn(filename, URL_SCHEME_CHARS); - if (!first_protocol) { - av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. " - "Missing call to av_register_all()?\n"); - } - if (filename[proto_len] != ':' && (filename[proto_len] != ',' || !strchr(filename + proto_len + 1, ':')) || is_dos_path(filename)) @@ -243,13 +237,31 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, while (up = ffurl_protocol_next(up)) { if (!strcmp(proto_str, up->name)) - return url_alloc_for_protocol(puc, up, filename, flags, int_cb); + break; if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME && !strcmp(proto_nested, up->name)) - return url_alloc_for_protocol(puc, up, filename, flags, int_cb); + break; + } + + return up; +} + +int ffurl_alloc(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb) +{ + URLProtocol *p = NULL; + + if (!first_protocol) { + av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. " + "Missing call to av_register_all()?\n"); } + + p = url_find_protocol(filename); + if (p) + return url_alloc_for_protocol(puc, p, filename, flags, int_cb); + *puc = NULL; - if (!strcmp("https", proto_str)) + if (av_strstart("https:", filename, NULL)) av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n"); return AVERROR_PROTOCOL_NOT_FOUND; } @@ -258,11 +270,13 @@ int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options) { int ret = ffurl_alloc(puc, filename, flags, int_cb); - if (ret) + if (ret < 0) return ret; if (options && (*puc)->prot->priv_data_class && (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0) goto fail; + if ((ret = av_opt_set_dict(*puc, options)) < 0) + goto fail; ret = ffurl_connect(*puc, options); if (!ret) return 0; @@ -376,11 +390,18 @@ int ffurl_close(URLContext *h) } +const char *avio_find_protocol_name(const char *url) +{ + URLProtocol *p = url_find_protocol(url); + + return p ? p->name : NULL; +} + int avio_check(const char *url, int flags) { URLContext *h; int ret = ffurl_alloc(&h, url, flags, NULL); - if (ret) + if (ret < 0) return ret; if (h->prot->url_check) { diff --git a/chromium/third_party/ffmpeg/libavformat/avio.h b/chromium/third_party/ffmpeg/libavformat/avio.h index 4f4ac3cbaf9..4004b6fda91 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.h +++ b/chromium/third_party/ffmpeg/libavformat/avio.h @@ -146,11 +146,27 @@ typedef struct AVIOContext { * This field is internal to libavformat and access from outside is not allowed. */ int writeout_count; + + /** + * Original buffer size + * used internally after probing and ensure seekback to reset the buffer size + * This field is internal to libavformat and access from outside is not allowed. + */ + int orig_buffer_size; } AVIOContext; /* unbuffered I/O */ /** + * Return the name of the protocol that will handle the passed URL. + * + * NULL is returned if no protocol could be found for the given URL. + * + * @return Name of the protocol or NULL. + */ +const char *avio_find_protocol_name(const char *url); + +/** * Return AVIO_FLAG_* access flags corresponding to the access permissions * of the resource in url, or a negative value corresponding to an * AVERROR code in case of failure. The returned access flags are @@ -366,6 +382,7 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); * * @param s Used to return the pointer to the created AVIOContext. * In case of failure the pointed to value is set to NULL. + * @param url resource to access * @param flags flags which control how the resource indicated by url * is to be opened * @return >= 0 in case of success, a negative value corresponding to an @@ -381,6 +398,7 @@ int avio_open(AVIOContext **s, const char *url, int flags); * * @param s Used to return the pointer to the created AVIOContext. * In case of failure the pointed to value is set to NULL. + * @param url resource to access * @param flags flags which control how the resource indicated by url * is to be opened * @param int_cb an interrupt callback to be used at the protocols level @@ -454,6 +472,8 @@ const char *avio_enum_protocols(void **opaque, int output); /** * Pause and resume playing - only meaningful if using a network streaming * protocol (e.g. MMS). + * + * @param h IO context from which to call the read_pause function pointer * @param pause 1 for pause, 0 for resume */ int avio_pause(AVIOContext *h, int pause); @@ -461,6 +481,8 @@ int avio_pause(AVIOContext *h, int pause); /** * Seek to a given timestamp relative to some component stream. * Only meaningful if using a network streaming protocol (e.g. MMS.). + * + * @param h IO context from which to call the seek function pointers * @param stream_index The stream index that the timestamp is relative to. * If stream_index is (-1) the timestamp should be in AV_TIME_BASE * units from the beginning of the presentation. diff --git a/chromium/third_party/ffmpeg/libavformat/avio_internal.h b/chromium/third_party/ffmpeg/libavformat/avio_internal.h index 8441d49971f..f4bc39c6003 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio_internal.h +++ b/chromium/third_party/ffmpeg/libavformat/avio_internal.h @@ -105,6 +105,8 @@ void ffio_init_checksum(AVIOContext *s, unsigned long ffio_get_checksum(AVIOContext *s); unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, unsigned int len); +unsigned long ff_crcA001_update(unsigned long checksum, const uint8_t *buf, + unsigned int len); /** * Open a write only packetized memory stream with a maximum packet diff --git a/chromium/third_party/ffmpeg/libavformat/aviobuf.c b/chromium/third_party/ffmpeg/libavformat/aviobuf.c index 8b4511d177d..32a1f92cb83 100644 --- a/chromium/third_party/ffmpeg/libavformat/aviobuf.c +++ b/chromium/third_party/ffmpeg/libavformat/aviobuf.c @@ -78,6 +78,7 @@ int ffio_init_context(AVIOContext *s, int64_t (*seek)(void *opaque, int64_t offset, int whence)) { s->buffer = buffer; + s->orig_buffer_size = s->buffer_size = buffer_size; s->buf_ptr = buffer; s->opaque = opaque; @@ -201,12 +202,14 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) int64_t offset1; int64_t pos; int force = whence & AVSEEK_FORCE; + int buffer_size; whence &= ~AVSEEK_FORCE; if(!s) return AVERROR(EINVAL); - pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer)); + buffer_size = s->buf_end - s->buffer; + pos = s->pos - (s->write_flag ? 0 : buffer_size); if (whence != SEEK_CUR && whence != SEEK_SET) return AVERROR(EINVAL); @@ -219,7 +222,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) } offset1 = offset - pos; if (!s->must_flush && (!s->direct || !s->seek) && - offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) { + offset1 >= 0 && offset1 <= buffer_size) { /* can do the seek inside the buffer */ s->buf_ptr = s->buffer + offset1; } else if ((!s->seekable || @@ -232,9 +235,20 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) if (s->eof_reached) return AVERROR_EOF; s->buf_ptr = s->buf_end + offset - s->pos; - } else { + } else if(!s->write_flag && offset1 < 0 && -offset1 < buffer_size>>1 && s->seek && offset > 0) { int64_t res; + pos -= FFMIN(buffer_size>>1, pos); + if ((res = s->seek(s->opaque, pos, SEEK_SET)) < 0) + return res; + s->buf_end = + s->buf_ptr = s->buffer; + s->pos = pos; + s->eof_reached = 0; + fill_buffer(s); + return avio_seek(s, offset, SEEK_SET | force); + } else { + int64_t res; if (s->write_flag) { flush_buffer(s); s->must_flush = 1; @@ -421,14 +435,14 @@ static void fill_buffer(AVIOContext *s) } /* make buffer smaller in case it ended up large after probing */ - if (s->read_packet && s->buffer_size > max_buffer_size) { + if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) { if (dst == s->buffer) { - ffio_set_buf_size(s, max_buffer_size); + ffio_set_buf_size(s, s->orig_buffer_size); s->checksum_ptr = dst = s->buffer; } - av_assert0(len >= max_buffer_size); - len = max_buffer_size; + av_assert0(len >= s->orig_buffer_size); + len = s->orig_buffer_size; } if (s->read_packet) @@ -455,6 +469,12 @@ unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len); } +unsigned long ff_crcA001_update(unsigned long checksum, const uint8_t *buf, + unsigned int len) +{ + return av_crc(av_crc_get_table(AV_CRC_16_ANSI_LE), checksum, buf, len); +} + unsigned long ffio_get_checksum(AVIOContext *s) { s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, @@ -749,10 +769,11 @@ int ffio_ensure_seekback(AVIOContext *s, int buf_size) uint8_t *buffer; int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE; + int filled = s->buf_end - s->buffer; buf_size += s->buf_ptr - s->buffer + max_buffer_size; - if (buf_size < s->buffer_size || s->seekable) + if (buf_size < filled || s->seekable) return 0; av_assert0(!s->write_flag); @@ -760,7 +781,7 @@ int ffio_ensure_seekback(AVIOContext *s, int buf_size) if (!buffer) return AVERROR(ENOMEM); - memcpy(buffer, s->buffer, s->buffer_size); + memcpy(buffer, s->buffer, filled); av_free(s->buffer); s->buf_ptr = buffer + (s->buf_ptr - s->buffer); s->buf_end = buffer + (s->buf_end - s->buffer); @@ -778,6 +799,7 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size) av_free(s->buffer); s->buffer = buffer; + s->orig_buffer_size = s->buffer_size = buf_size; s->buf_ptr = buffer; url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); @@ -1036,7 +1058,7 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { - DynBuffer *d = s->opaque; + DynBuffer *d; int size; static const char padbuf[FF_INPUT_BUFFER_PADDING_SIZE] = {0}; int padding = 0; @@ -1045,6 +1067,7 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) *pbuffer = NULL; return 0; } + d = s->opaque; /* don't attempt to pad fixed-size packet buffers */ if (!s->max_packet_size) { diff --git a/chromium/third_party/ffmpeg/libavformat/avisynth.c b/chromium/third_party/ffmpeg/libavformat/avisynth.c index 2f438d90270..c01d7e484cd 100644 --- a/chromium/third_party/ffmpeg/libavformat/avisynth.c +++ b/chromium/third_party/ffmpeg/libavformat/avisynth.c @@ -294,6 +294,7 @@ static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) st->codec->channels = avs->vi->nchannels; st->time_base = (AVRational) { 1, avs->vi->audio_samples_per_second }; + st->duration = avs->vi->num_audio_samples; switch (avs->vi->sample_type) { case AVS_SAMPLE_INT8: @@ -401,10 +402,10 @@ static void avisynth_next_stream(AVFormatContext *s, AVStream **st, { AviSynthContext *avs = s->priv_data; - pkt->stream_index = avs->curr_stream++; + avs->curr_stream++; avs->curr_stream %= s->nb_streams; - *st = s->streams[pkt->stream_index]; + *st = s->streams[avs->curr_stream]; if ((*st)->discard == AVDISCARD_ALL) *discard = 1; else @@ -432,10 +433,6 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, if (discard) return 0; - pkt->pts = n; - pkt->dts = n; - pkt->duration = 1; - #ifdef USING_AVISYNTH /* Define the bpp values for the new AviSynth 2.6 colorspaces. * Since AvxSynth doesn't have these functions, special-case @@ -459,17 +456,21 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, (int64_t)avs->vi->height) * bits) / 8; if (!pkt->size) return AVERROR_UNKNOWN; - if (av_new_packet(pkt, (int)pkt->size) < 0) { - av_free(pkt); + + if (av_new_packet(pkt, pkt->size) < 0) return AVERROR(ENOMEM); - } + + pkt->pts = n; + pkt->dts = n; + pkt->duration = 1; + pkt->stream_index = avs->curr_stream; frame = avs_library.avs_get_frame(avs->clip, n); error = avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; - av_freep(&pkt->data); + av_packet_unref(pkt); return AVERROR_UNKNOWN; } @@ -550,24 +551,25 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, if (discard) return 0; - pkt->pts = n; - pkt->dts = n; - pkt->duration = samples; - pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels; if (!pkt->size) return AVERROR_UNKNOWN; - pkt->data = av_malloc(pkt->size); - if (!pkt->data) + + if (av_new_packet(pkt, pkt->size) < 0) return AVERROR(ENOMEM); + pkt->pts = n; + pkt->dts = n; + pkt->duration = samples; + pkt->stream_index = avs->curr_stream; + avs_library.avs_get_audio(avs->clip, pkt->data, n, samples); error = avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; - av_freep(&pkt->data); + av_packet_unref(pkt); return AVERROR_UNKNOWN; } return 0; @@ -600,8 +602,6 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) if (avs->error) return AVERROR_UNKNOWN; - av_free_packet(pkt); - /* If either stream reaches EOF, try to read the other one before * giving up. */ avisynth_next_stream(s, &st, pkt, &discard); diff --git a/chromium/third_party/ffmpeg/libavformat/bink.c b/chromium/third_party/ffmpeg/libavformat/bink.c index 6db73cce3aa..395c8d9aa89 100644 --- a/chromium/third_party/ffmpeg/libavformat/bink.c +++ b/chromium/third_party/ffmpeg/libavformat/bink.c @@ -28,6 +28,8 @@ * http://wiki.multimedia.cx/index.php?title=Bink_Container */ +#include <inttypes.h> + #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "avformat.h" @@ -59,8 +61,10 @@ static int probe(AVProbeData *p) { const uint8_t *b = p->buf; - if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' && - (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') && + if (((b[0] == 'B' && b[1] == 'I' && b[2] == 'K' && + (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i')) || + (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */ + (b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g'))) && AV_RL32(b+8) > 0 && // num_frames AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH && AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT && @@ -79,6 +83,7 @@ static int read_header(AVFormatContext *s) uint32_t pos, next_pos; uint16_t flags; int keyframe; + int ret; vst = avformat_new_stream(s, NULL); if (!vst) @@ -108,7 +113,9 @@ static int read_header(AVFormatContext *s) fps_num = avio_rl32(pb); fps_den = avio_rl32(pb); if (fps_num == 0 || fps_den == 0) { - av_log(s, AV_LOG_ERROR, "invalid header: invalid fps (%d/%d)\n", fps_num, fps_den); + av_log(s, AV_LOG_ERROR, + "invalid header: invalid fps (%"PRIu32"/%"PRIu32")\n", + fps_num, fps_den); return AVERROR(EIO); } avpriv_set_pts_info(vst, 64, fps_den, fps_num); @@ -116,15 +123,20 @@ static int read_header(AVFormatContext *s) vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_id = AV_CODEC_ID_BINKVIDEO; - if (ff_alloc_extradata(vst->codec, 4)) + + if ((vst->codec->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) { + av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n"); + vst->codec->codec_id = AV_CODEC_ID_NONE; + } + + if (ff_get_extradata(vst->codec, pb, 4) < 0) return AVERROR(ENOMEM); - avio_read(pb, vst->codec->extradata, 4); bink->num_audio_tracks = avio_rl32(pb); if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) { av_log(s, AV_LOG_ERROR, - "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n", + "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%"PRIu32")\n", bink->num_audio_tracks); return AVERROR(EIO); } @@ -177,11 +189,12 @@ static int read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "invalid frame index table\n"); return AVERROR(EIO); } - av_add_index_entry(vst, pos, i, next_pos - pos, 0, - keyframe ? AVINDEX_KEYFRAME : 0); + if ((ret = av_add_index_entry(vst, pos, i, next_pos - pos, 0, + keyframe ? AVINDEX_KEYFRAME : 0)) < 0) + return ret; } - avio_skip(pb, 4); + avio_seek(pb, vst->index_entries[0].pos, SEEK_SET); bink->current_track = -1; return 0; @@ -217,7 +230,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) uint32_t audio_size = avio_rl32(pb); if (audio_size > bink->remain_packet_size - 4) { av_log(s, AV_LOG_ERROR, - "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", + "frame %"PRId64": audio size in header (%"PRIu32") > size of packet left (%"PRIu32")\n", bink->video_pts, audio_size, bink->remain_packet_size); return AVERROR(EIO); } @@ -280,4 +293,5 @@ AVInputFormat ff_bink_demuxer = { .read_header = read_header, .read_packet = read_packet, .read_seek = read_seek, + .flags = AVFMT_SHOW_IDS, }; diff --git a/chromium/third_party/ffmpeg/libavformat/cafdec.c b/chromium/third_party/ffmpeg/libavformat/cafdec.c index e954c65683b..a8edbca039b 100644 --- a/chromium/third_party/ffmpeg/libavformat/cafdec.c +++ b/chromium/third_party/ffmpeg/libavformat/cafdec.c @@ -25,6 +25,8 @@ * Core Audio Format demuxer */ +#include <inttypes.h> + #include "avformat.h" #include "internal.h" #include "isom.h" @@ -154,9 +156,8 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size) avio_skip(pb, size - ALAC_NEW_KUKI); } } else { - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, size); } return 0; @@ -286,7 +287,8 @@ static int read_header(AVFormatContext *s) default: #define _(x) ((x) >= ' ' ? (x) : ' ') - av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%c%c%c%c), size %"PRId64"\n", + av_log(s, AV_LOG_WARNING, + "skipping CAF chunk: %08"PRIX32" (%c%c%c%c), size %"PRId64"\n", tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF), size); #undef _ case MKBETAG('f','r','e','e'): diff --git a/chromium/third_party/ffmpeg/libavformat/cafenc.c b/chromium/third_party/ffmpeg/libavformat/cafenc.c index cd3a0be907f..f94101ab020 100644 --- a/chromium/third_party/ffmpeg/libavformat/cafenc.c +++ b/chromium/third_party/ffmpeg/libavformat/cafenc.c @@ -108,9 +108,13 @@ static int caf_write_header(AVFormatContext *s) unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id); int64_t chunk_size = 0; + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n"); + return AVERROR(EINVAL); + } + switch (enc->codec_id) { case AV_CODEC_ID_AAC: - case AV_CODEC_ID_AC3: av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n"); return AVERROR_PATCHWELCOME; } diff --git a/chromium/third_party/ffmpeg/libavformat/cinedec.c b/chromium/third_party/ffmpeg/libavformat/cinedec.c new file mode 100644 index 00000000000..372088495e1 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/cinedec.c @@ -0,0 +1,301 @@ +/* + * Phanton Cine demuxer + * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org> + * + * 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 + */ + +/** + * @file + * Phantom Cine demuxer + * @author Peter Ross <pross@xvid.org> + */ + +#include "libavutil/intreadwrite.h" +#include "libavcodec/bmp.h" +#include "avformat.h" +#include "internal.h" + +typedef struct { + uint64_t pts; +} CineDemuxContext; + +/** Compression */ +enum { + CC_RGB = 0, /**< Gray */ + CC_LEAD = 1, /**< LEAD (M)JPEG */ + CC_UNINT = 2 /**< Uninterpolated color image (CFA field indicates color ordering) */ +}; + +/** Color Filter Array */ +enum { + CFA_NONE = 0, /**< GRAY */ + CFA_VRI = 1, /**< GBRG/RGGB */ + CFA_VRIV6 = 2, /**< BGGR/GRBG */ + CFA_BAYER = 3, /**< GB/RG */ + CFA_BAYERFLIP = 4, /**< RG/GB */ + + CFA_TLGRAY = 0x80000000, + CFA_TRGRAY = 0x40000000, + CFA_BLGRAY = 0x20000000, + CFA_BRGRAY = 0x10000000 +}; + +static int cine_read_probe(AVProbeData *p) +{ + int HeaderSize; + if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type + (HeaderSize = AV_RL16(p->buf + 2)) >= 0x2C && // HeaderSize + AV_RL16(p->buf + 4) <= CC_UNINT && // Compression + AV_RL16(p->buf + 6) <= 1 && // Version + AV_RL32(p->buf + 20) && // ImageCount + AV_RL32(p->buf + 24) >= HeaderSize && // OffImageHeader + AV_RL32(p->buf + 28) >= HeaderSize && // OffSetup + AV_RL32(p->buf + 32) >= HeaderSize) // OffImageOffsets + return AVPROBE_SCORE_MAX; + return 0; +} + +static int set_metadata_int(AVDictionary **dict, const char *key, int value) +{ + if (value) { + char buf[64]; + snprintf(buf, sizeof(buf), "%i", value); + return av_dict_set(dict, key, buf, 0); + } + return 0; +} + +static int cine_read_header(AVFormatContext *avctx) +{ + AVIOContext *pb = avctx->pb; + AVStream *st; + unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA; + int vflip; + char *description; + uint64_t i; + + st = avformat_new_stream(avctx, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + st->codec->codec_tag = 0; + + /* CINEFILEHEADER structure */ + avio_skip(pb, 4); // Type, Headersize + + compression = avio_rl16(pb); + version = avio_rl16(pb); + if (version != 1) { + avpriv_request_sample(avctx, "uknown version %i", version); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber + + st->duration = avio_rl32(pb); + offImageHeader = avio_rl32(pb); + offSetup = avio_rl32(pb); + offImageOffsets = avio_rl32(pb); + + avio_skip(pb, 8); // TriggerTime + + /* BITMAPINFOHEADER structure */ + avio_seek(pb, offImageHeader, SEEK_SET); + avio_skip(pb, 4); //biSize + st->codec->width = avio_rl32(pb); + st->codec->height = avio_rl32(pb); + + if (avio_rl16(pb) != 1) // biPlanes + return AVERROR_INVALIDDATA; + + biBitCount = avio_rl16(pb); + if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) { + avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); + return AVERROR_INVALIDDATA; + } + + switch (avio_rl32(pb)) { + case BMP_RGB: + vflip = 0; + break; + case 0x100: /* BI_PACKED */ + st->codec->codec_tag = MKTAG('B', 'I', 'T', 0); + vflip = 1; + break; + default: + avpriv_request_sample(avctx, "unknown bitmap compression"); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 4); // biSizeImage + + /* parse SETUP structure */ + avio_seek(pb, offSetup, SEEK_SET); + avio_skip(pb, 140); // FrameRatae16 .. descriptionOld + if (avio_rl16(pb) != 0x5453) + return AVERROR_INVALIDDATA; + length = avio_rl16(pb); + if (length < 0x163C) { + avpriv_request_sample(avctx, "short SETUP header"); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 616); // Binning .. bFlipH + if (!avio_rl32(pb) ^ vflip) { + st->codec->extradata = av_strdup("BottomUp"); + st->codec->extradata_size = 9; + } + + avio_skip(pb, 4); // Grid + + avpriv_set_pts_info(st, 64, 1, avio_rl32(pb)); + + avio_skip(pb, 20); // Shutter .. bEnableColor + + set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb)); + set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb)); + set_metadata_int(&st->metadata, "software_version", avio_rl32(pb)); + set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb)); + + CFA = avio_rl32(pb); + + set_metadata_int(&st->metadata, "brightness", avio_rl32(pb)); + set_metadata_int(&st->metadata, "contrast", avio_rl32(pb)); + set_metadata_int(&st->metadata, "gamma", avio_rl32(pb)); + + avio_skip(pb, 72); // Reserved1 .. WBView + + st->codec->bits_per_coded_sample = avio_rl32(pb); + + if (compression == CC_RGB) { + if (biBitCount == 8) { + st->codec->pix_fmt = AV_PIX_FMT_GRAY8; + } else if (biBitCount == 16) { + st->codec->pix_fmt = AV_PIX_FMT_GRAY16LE; + } else if (biBitCount == 24) { + st->codec->pix_fmt = AV_PIX_FMT_BGR24; + } else if (biBitCount == 48) { + st->codec->pix_fmt = AV_PIX_FMT_BGR48LE; + } else { + avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); + return AVERROR_INVALIDDATA; + } + } else if (compression == CC_UNINT) { + switch (CFA & 0xFFFFFF) { + case CFA_BAYER: + if (biBitCount == 8) { + st->codec->pix_fmt = AV_PIX_FMT_BAYER_GBRG8; + } else if (biBitCount == 16) { + st->codec->pix_fmt = AV_PIX_FMT_BAYER_GBRG16LE; + } else { + avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); + return AVERROR_INVALIDDATA; + } + break; + case CFA_BAYERFLIP: + if (biBitCount == 8) { + st->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB8; + } else if (biBitCount == 16) { + st->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB16LE; + } else { + avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); + return AVERROR_INVALIDDATA; + } + break; + default: + avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF); + return AVERROR_INVALIDDATA; + } + } else { //CC_LEAD + avpriv_request_sample(avctx, "unsupported compression %i", compression); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 696); // Conv8Min ... ImHeightAcq + +#define DESCRIPTION_SIZE 4096 + description = av_malloc(DESCRIPTION_SIZE + 1); + if (!description) + return AVERROR(ENOMEM); + i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1); + if (i < DESCRIPTION_SIZE) + avio_skip(pb, DESCRIPTION_SIZE - i); + if (description[0]) + av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL); + else + av_free(description); + + /* parse image offsets */ + avio_seek(pb, offImageOffsets, SEEK_SET); + for (i = 0; i < st->duration; i++) + av_add_index_entry(st, avio_rl64(pb), i, 0, 0, AVINDEX_KEYFRAME); + + return 0; +} + +static int cine_read_packet(AVFormatContext *avctx, AVPacket *pkt) +{ + CineDemuxContext *cine = avctx->priv_data; + AVStream *st = avctx->streams[0]; + AVIOContext *pb = avctx->pb; + int n, size, ret; + + if (cine->pts >= st->duration) + return AVERROR_EOF; + + avio_seek(pb, st->index_entries[cine->pts].pos, SEEK_SET); + n = avio_rl32(pb); + if (n < 8) + return AVERROR_INVALIDDATA; + avio_skip(pb, n - 8); + size = avio_rl32(pb); + + ret = av_get_packet(pb, pkt, size); + if (ret < 0) + return ret; + + pkt->pts = cine->pts++; + pkt->stream_index = 0; + pkt->flags |= AV_PKT_FLAG_KEY; + return 0; +} + +static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags) +{ + CineDemuxContext *cine = avctx->priv_data; + + if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) + return AVERROR(ENOSYS); + + if (!avctx->pb->seekable) + return AVERROR(EIO); + + cine->pts = timestamp; + return 0; +} + +AVInputFormat ff_cine_demuxer = { + .name = "cine", + .long_name = NULL_IF_CONFIG_SMALL("Phantom Cine"), + .priv_data_size = sizeof(CineDemuxContext), + .read_probe = cine_read_probe, + .read_header = cine_read_header, + .read_packet = cine_read_packet, + .read_seek = cine_read_seek, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/concatdec.c b/chromium/third_party/ffmpeg/libavformat/concatdec.c index 428c749ab24..4590dc59232 100644 --- a/chromium/third_party/ffmpeg/libavformat/concatdec.c +++ b/chromium/third_party/ffmpeg/libavformat/concatdec.c @@ -18,17 +18,31 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" #include "url.h" +typedef enum ConcatMatchMode { + MATCH_ONE_TO_ONE, + MATCH_EXACT_ID, +} ConcatMatchMode; + +typedef struct ConcatStream { + AVBitStreamFilterContext *bsf; + int out_stream_index; +} ConcatStream; + typedef struct { char *url; int64_t start_time; int64_t duration; + ConcatStream *streams; + int nb_streams; } ConcatFile; typedef struct { @@ -39,6 +53,8 @@ typedef struct { AVFormatContext *avf; int safe; int seekable; + ConcatMatchMode stream_match_mode; + unsigned auto_convert; } ConcatContext; static int concat_probe(AVProbeData *probe) @@ -85,18 +101,28 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, ConcatContext *cat = avf->priv_data; ConcatFile *file; char *url = NULL; - size_t url_len; + const char *proto; + size_t url_len, proto_len; int ret; if (cat->safe > 0 && !safe_filename(filename)) { av_log(avf, AV_LOG_ERROR, "Unsafe file name '%s'\n", filename); FAIL(AVERROR(EPERM)); } - url_len = strlen(avf->filename) + strlen(filename) + 16; - if (!(url = av_malloc(url_len))) - FAIL(AVERROR(ENOMEM)); - ff_make_absolute_url(url, url_len, avf->filename, filename); - av_freep(&filename); + + proto = avio_find_protocol_name(filename); + proto_len = proto ? strlen(proto) : 0; + if (!memcmp(filename, proto, proto_len) && + (filename[proto_len] == ':' || filename[proto_len] == ',')) { + url = filename; + filename = NULL; + } else { + url_len = strlen(avf->filename) + strlen(filename) + 16; + if (!(url = av_malloc(url_len))) + FAIL(AVERROR(ENOMEM)); + ff_make_absolute_url(url, url_len, avf->filename, filename); + av_freep(&filename); + } if (cat->nb_files >= *nb_files_alloc) { size_t n = FFMAX(*nb_files_alloc * 2, 16); @@ -124,6 +150,130 @@ fail: return ret; } +static int copy_stream_props(AVStream *st, AVStream *source_st) +{ + int ret; + + if (st->codec->codec_id || !source_st->codec->codec_id) { + if (st->codec->extradata_size < source_st->codec->extradata_size) { + ret = ff_alloc_extradata(st->codec, + source_st->codec->extradata_size); + if (ret < 0) + return ret; + } + memcpy(st->codec->extradata, source_st->codec->extradata, + source_st->codec->extradata_size); + return 0; + } + if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0) + return ret; + st->r_frame_rate = source_st->r_frame_rate; + st->avg_frame_rate = source_st->avg_frame_rate; + st->time_base = source_st->time_base; + st->sample_aspect_ratio = source_st->sample_aspect_ratio; + return 0; +} + +static int detect_stream_specific(AVFormatContext *avf, int idx) +{ + ConcatContext *cat = avf->priv_data; + AVStream *st = cat->avf->streams[idx]; + ConcatStream *cs = &cat->cur_file->streams[idx]; + AVBitStreamFilterContext *bsf; + + if (cat->auto_convert && st->codec->codec_id == AV_CODEC_ID_H264 && + (st->codec->extradata_size < 4 || AV_RB32(st->codec->extradata) != 1)) { + av_log(cat->avf, AV_LOG_INFO, + "Auto-inserting h264_mp4toannexb bitstream filter\n"); + if (!(bsf = av_bitstream_filter_init("h264_mp4toannexb"))) { + av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter " + "required for H.264 streams\n"); + return AVERROR_BSF_NOT_FOUND; + } + cs->bsf = bsf; + } + return 0; +} + +static int match_streams_one_to_one(AVFormatContext *avf) +{ + ConcatContext *cat = avf->priv_data; + AVStream *st; + int i, ret; + + for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) { + if (i < avf->nb_streams) { + st = avf->streams[i]; + } else { + if (!(st = avformat_new_stream(avf, NULL))) + return AVERROR(ENOMEM); + } + if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0) + return ret; + cat->cur_file->streams[i].out_stream_index = i; + } + return 0; +} + +static int match_streams_exact_id(AVFormatContext *avf) +{ + ConcatContext *cat = avf->priv_data; + AVStream *st; + int i, j, ret; + + for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) { + st = cat->avf->streams[i]; + for (j = 0; j < avf->nb_streams; j++) { + if (avf->streams[j]->id == st->id) { + av_log(avf, AV_LOG_VERBOSE, + "Match slave stream #%d with stream #%d id 0x%x\n", + i, j, st->id); + if ((ret = copy_stream_props(avf->streams[j], st)) < 0) + return ret; + cat->cur_file->streams[i].out_stream_index = j; + } + } + } + return 0; +} + +static int match_streams(AVFormatContext *avf) +{ + ConcatContext *cat = avf->priv_data; + ConcatStream *map; + int i, ret; + + if (cat->cur_file->nb_streams >= cat->avf->nb_streams) + return 0; + map = av_realloc(cat->cur_file->streams, + cat->avf->nb_streams * sizeof(*map)); + if (!map) + return AVERROR(ENOMEM); + cat->cur_file->streams = map; + memset(map + cat->cur_file->nb_streams, 0, + (cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map)); + + for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) + map[i].out_stream_index = -1; + switch (cat->stream_match_mode) { + case MATCH_ONE_TO_ONE: + ret = match_streams_one_to_one(avf); + break; + case MATCH_EXACT_ID: + ret = match_streams_exact_id(avf); + break; + default: + ret = AVERROR_BUG; + } + if (ret < 0) + return ret; + for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) + if ((ret = detect_stream_specific(avf, i)) < 0) + return ret; + cat->cur_file->nb_streams = cat->avf->nb_streams; + return 0; +} + static int open_file(AVFormatContext *avf, unsigned fileno) { ConcatContext *cat = avf->priv_data; @@ -132,9 +282,16 @@ static int open_file(AVFormatContext *avf, unsigned fileno) if (cat->avf) avformat_close_input(&cat->avf); + + cat->avf = avformat_alloc_context(); + if (!cat->avf) + return AVERROR(ENOMEM); + + cat->avf->interrupt_callback = avf->interrupt_callback; if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 || (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) { av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url); + avformat_close_input(&cat->avf); return ret; } cat->cur_file = file; @@ -142,6 +299,8 @@ static int open_file(AVFormatContext *avf, unsigned fileno) file->start_time = !fileno ? 0 : cat->files[fileno - 1].start_time + cat->files[fileno - 1].duration; + if ((ret = match_streams(avf)) < 0) + return ret; return 0; } @@ -152,8 +311,10 @@ static int concat_read_close(AVFormatContext *avf) if (cat->avf) avformat_close_input(&cat->avf); - for (i = 0; i < cat->nb_files; i++) + for (i = 0; i < cat->nb_files; i++) { av_freep(&cat->files[i].url); + av_freep(&cat->files[i].streams); + } av_freep(&cat->files); return 0; } @@ -166,7 +327,6 @@ static int concat_read_header(AVFormatContext *avf) int ret, line = 0, i; unsigned nb_files_alloc = 0; ConcatFile *file = NULL; - AVStream *st, *source_st; int64_t time = 0; while (1) { @@ -200,6 +360,17 @@ static int concat_read_header(AVFormatContext *avf) FAIL(ret); } file->duration = dur; + } else if (!strcmp(keyword, "stream")) { + if (!avformat_new_stream(avf, NULL)) + FAIL(AVERROR(ENOMEM)); + } else if (!strcmp(keyword, "exact_stream_id")) { + if (!avf->nb_streams) { + av_log(avf, AV_LOG_ERROR, "Line %d: exact_stream_id without stream\n", + line); + FAIL(AVERROR_INVALIDDATA); + } + avf->streams[avf->nb_streams - 1]->id = + strtol(get_keyword(&cursor), NULL, 0); } else if (!strcmp(keyword, "ffconcat")) { char *ver_kw = get_keyword(&cursor); char *ver_val = get_keyword(&cursor); @@ -234,20 +405,10 @@ static int concat_read_header(AVFormatContext *avf) cat->seekable = 1; } + cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID : + MATCH_ONE_TO_ONE; if ((ret = open_file(avf, 0)) < 0) FAIL(ret); - for (i = 0; i < cat->avf->nb_streams; i++) { - if (!(st = avformat_new_stream(avf, NULL))) - FAIL(AVERROR(ENOMEM)); - source_st = cat->avf->streams[i]; - if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0) - FAIL(ret); - st->r_frame_rate = source_st->r_frame_rate; - st->avg_frame_rate = source_st->avg_frame_rate; - st->time_base = source_st->time_base; - st->sample_aspect_ratio = source_st->sample_aspect_ratio; - } - return 0; fail: @@ -268,17 +429,77 @@ static int open_next_file(AVFormatContext *avf) return open_file(avf, fileno); } +static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt) +{ + AVStream *st = avf->streams[cs->out_stream_index]; + AVBitStreamFilterContext *bsf; + AVPacket pkt2; + int ret; + + av_assert0(cs->out_stream_index >= 0); + for (bsf = cs->bsf; bsf; bsf = bsf->next) { + pkt2 = *pkt; + ret = av_bitstream_filter_filter(bsf, st->codec, NULL, + &pkt2.data, &pkt2.size, + pkt->data, pkt->size, + !!(pkt->flags & AV_PKT_FLAG_KEY)); + if (ret < 0) { + av_packet_unref(pkt); + return ret; + } + av_assert0(pkt2.buf); + if (ret == 0 && pkt2.data != pkt->data) { + if ((ret = av_copy_packet(&pkt2, pkt)) < 0) { + av_free(pkt2.data); + return ret; + } + ret = 1; + } + if (ret > 0) { + av_free_packet(pkt); + pkt2.buf = av_buffer_create(pkt2.data, pkt2.size, + av_buffer_default_free, NULL, 0); + if (!pkt2.buf) { + av_free(pkt2.data); + return AVERROR(ENOMEM); + } + } + *pkt = pkt2; + } + return 0; +} + static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) { ConcatContext *cat = avf->priv_data; int ret; int64_t delta; + ConcatStream *cs; while (1) { - if ((ret = av_read_frame(cat->avf, pkt)) != AVERROR_EOF || - (ret = open_next_file(avf)) < 0) - break; + ret = av_read_frame(cat->avf, pkt); + if (ret == AVERROR_EOF) { + if ((ret = open_next_file(avf)) < 0) + return ret; + continue; + } + if (ret < 0) + return ret; + if ((ret = match_streams(avf)) < 0) { + av_packet_unref(pkt); + return ret; + } + cs = &cat->cur_file->streams[pkt->stream_index]; + if (cs->out_stream_index < 0) { + av_packet_unref(pkt); + continue; + } + pkt->stream_index = cs->out_stream_index; + break; } + if ((ret = filter_packet(avf, cs, pkt))) + return ret; + delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time, AV_TIME_BASE_Q, cat->avf->streams[pkt->stream_index]->time_base); @@ -384,6 +605,8 @@ static int concat_seek(AVFormatContext *avf, int stream, static const AVOption options[] = { { "safe", "enable safe mode", OFFSET(safe), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, DEC }, + { "auto_convert", "automatically convert bitstream format", + OFFSET(auto_convert), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, { NULL } }; diff --git a/chromium/third_party/ffmpeg/libavformat/crcenc.c b/chromium/third_party/ffmpeg/libavformat/crcenc.c index ac0638037e4..3fdfea5207f 100644 --- a/chromium/third_party/ffmpeg/libavformat/crcenc.c +++ b/chromium/third_party/ffmpeg/libavformat/crcenc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/adler32.h" #include "avformat.h" @@ -48,7 +50,7 @@ static int crc_write_trailer(struct AVFormatContext *s) CRCState *crc = s->priv_data; char buf[64]; - snprintf(buf, sizeof(buf), "CRC=0x%08x\n", crc->crcval); + snprintf(buf, sizeof(buf), "CRC=0x%08"PRIx32"\n", crc->crcval); avio_write(s->pb, buf, strlen(buf)); return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/dfa.c b/chromium/third_party/ffmpeg/libavformat/dfa.c index 9cd13e24d95..dfa0590e2e2 100644 --- a/chromium/third_party/ffmpeg/libavformat/dfa.c +++ b/chromium/third_party/ffmpeg/libavformat/dfa.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" @@ -98,12 +100,13 @@ static int dfa_read_packet(AVFormatContext *s, AVPacket *pkt) first = 0; frame_size = AV_RL32(pkt->data + pkt->size - 8); if (frame_size > INT_MAX - 4) { - av_log(s, AV_LOG_ERROR, "Too large chunk size: %d\n", frame_size); + av_log(s, AV_LOG_ERROR, "Too large chunk size: %"PRIu32"\n", frame_size); return AVERROR(EIO); } if (AV_RL32(pkt->data + pkt->size - 12) == MKTAG('E', 'O', 'F', 'R')) { if (frame_size) { - av_log(s, AV_LOG_WARNING, "skipping %d bytes of end-of-frame marker chunk\n", + av_log(s, AV_LOG_WARNING, + "skipping %"PRIu32" bytes of end-of-frame marker chunk\n", frame_size); avio_skip(pb, frame_size); } diff --git a/chromium/third_party/ffmpeg/libavformat/dsfdec.c b/chromium/third_party/ffmpeg/libavformat/dsfdec.c new file mode 100644 index 00000000000..ae198b2e93b --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/dsfdec.c @@ -0,0 +1,159 @@ +/* + * DSD Stream File (DSF) demuxer + * Copyright (c) 2014 Peter Ross + * + * 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/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "id3v2.h" + +typedef struct { + uint64_t data_end; +} DSFContext; + +static int dsf_probe(AVProbeData *p) +{ + if (p->buf_size < 12 || memcmp(p->buf, "DSD ", 4) || AV_RL64(p->buf + 4) != 28) + return 0; + return AVPROBE_SCORE_MAX; +} + +static const uint64_t dsf_channel_layout[] = { + 0, + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, +}; + +static void read_id3(AVFormatContext *s, uint64_t id3pos) +{ + ID3v2ExtraMeta *id3v2_extra_meta = NULL; + if (avio_seek(s->pb, id3pos, SEEK_SET) < 0) + return; + + 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_free_extra_meta(&id3v2_extra_meta); +} + +static int dsf_read_header(AVFormatContext *s) +{ + DSFContext *dsf = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st; + uint64_t id3pos; + unsigned int channel_type; + + avio_skip(pb, 4); + if (avio_rl64(pb) != 28) + return AVERROR_INVALIDDATA; + + /* create primary stream before any id3 coverart streams */ + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(pb, 8); + id3pos = avio_rl64(pb); + if (pb->seekable) { + read_id3(s, id3pos); + avio_seek(pb, 28, SEEK_SET); + } + + /* fmt chunk */ + + if (avio_rl32(pb) != MKTAG('f', 'm', 't', ' ') || avio_rl64(pb) != 52) + return AVERROR_INVALIDDATA; + + if (avio_rl32(pb) != 1) { + avpriv_request_sample(s, "unknown format version"); + return AVERROR_INVALIDDATA; + } + + if (avio_rl32(pb)) { + avpriv_request_sample(s, "unknown format id"); + return AVERROR_INVALIDDATA; + } + + channel_type = avio_rl32(pb); + if (channel_type < FF_ARRAY_ELEMS(dsf_channel_layout)) + st->codec->channel_layout = dsf_channel_layout[channel_type]; + if (!st->codec->channel_layout) + avpriv_request_sample(s, "channel type %i", channel_type); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->channels = avio_rl32(pb); + st->codec->sample_rate = avio_rl32(pb) / 8; + + switch(avio_rl32(pb)) { + case 1: st->codec->codec_id = AV_CODEC_ID_DSD_LSBF_PLANAR; break; + case 8: st->codec->codec_id = AV_CODEC_ID_DSD_MSBF_PLANAR; break; + default: + avpriv_request_sample(s, "unknown most significant bit"); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 8); + st->codec->block_align = avio_rl32(pb); + if (st->codec->block_align > INT_MAX / st->codec->channels) { + avpriv_request_sample(s, "block_align overflow"); + return AVERROR_INVALIDDATA; + } + st->codec->block_align *= st->codec->channels; + avio_skip(pb, 4); + + /* data chunk */ + + dsf->data_end = avio_tell(pb); + if (avio_rl32(pb) != MKTAG('d', 'a', 't', 'a')) + return AVERROR_INVALIDDATA; + dsf->data_end += avio_rl64(pb); + + return 0; +} + +static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + DSFContext *dsf = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st = s->streams[0]; + int64_t pos = avio_tell(pb); + + if (pos >= dsf->data_end) + return AVERROR_EOF; + + pkt->stream_index = 0; + return av_get_packet(pb, pkt, FFMIN(dsf->data_end - pos, st->codec->block_align)); +} + +AVInputFormat ff_dsf_demuxer = { + .name = "dsf", + .long_name = NULL_IF_CONFIG_SMALL("DSD Stream File (DSF)"), + .priv_data_size = sizeof(DSFContext), + .read_probe = dsf_probe, + .read_header = dsf_read_header, + .read_packet = dsf_read_packet, + .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/dvenc.c b/chromium/third_party/ffmpeg/libavformat/dvenc.c index 43f65c37b9c..defcf2a16e3 100644 --- a/chromium/third_party/ffmpeg/libavformat/dvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/dvenc.c @@ -334,7 +334,7 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s) if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc(100*MAX_AUDIO_FRAME_SIZE))) { while (i > 0) { i--; - av_fifo_free(c->audio_data[i]); + av_fifo_freep(&c->audio_data[i]); } goto bail_out; } @@ -350,7 +350,7 @@ static void dv_delete_mux(DVMuxContext *c) { int i; for (i=0; i < c->n_ast; i++) - av_fifo_free(c->audio_data[i]); + av_fifo_freep(&c->audio_data[i]); } static int dv_write_header(AVFormatContext *s) diff --git a/chromium/third_party/ffmpeg/libavformat/dxa.c b/chromium/third_party/ffmpeg/libavformat/dxa.c index 22ee2a97a54..ea5b4f7163a 100644 --- a/chromium/third_party/ffmpeg/libavformat/dxa.c +++ b/chromium/third_party/ffmpeg/libavformat/dxa.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" @@ -169,7 +171,10 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) } avio_seek(s->pb, c->vidpos, SEEK_SET); while(!url_feof(s->pb) && c->frames){ - avio_read(s->pb, buf, 4); + if ((ret = avio_read(s->pb, buf, 4)) != 4) { + av_log(s, AV_LOG_ERROR, "failed reading chunk type\n"); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } switch(AV_RL32(buf)){ case MKTAG('N', 'U', 'L', 'L'): if(av_new_packet(pkt, 4 + pal_size) < 0) @@ -187,10 +192,14 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) avio_read(s->pb, pal + 4, 768); break; case MKTAG('F', 'R', 'A', 'M'): - avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4); + if ((ret = avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4)) != DXA_EXTRA_SIZE - 4) { + av_log(s, AV_LOG_ERROR, "failed reading dxa_extra\n"); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } size = AV_RB32(buf + 5); if(size > 0xFFFFFF){ - av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size); + av_log(s, AV_LOG_ERROR, "Frame size is too big: %"PRIu32"\n", + size); return AVERROR_INVALIDDATA; } if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0) diff --git a/chromium/third_party/ffmpeg/libavformat/electronicarts.c b/chromium/third_party/ffmpeg/libavformat/electronicarts.c index dd8cf5d6449..1acaa14c8cf 100644 --- a/chromium/third_party/ffmpeg/libavformat/electronicarts.c +++ b/chromium/third_party/ffmpeg/libavformat/electronicarts.c @@ -25,6 +25,8 @@ * by Robin Kay (komadori at gekkou.co.uk) */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" @@ -152,7 +154,7 @@ static int process_audio_header_elements(AVFormatContext *s) break; case 0x8A: av_log(s, AV_LOG_DEBUG, - "element 0x%02x set to 0x%08x\n", + "element 0x%02x set to 0x%08"PRIx32"\n", subbyte, read_arbitrary(pb)); av_log(s, AV_LOG_DEBUG, "exited audio subheader\n"); in_subheader = 0; @@ -171,7 +173,7 @@ static int process_audio_header_elements(AVFormatContext *s) break; default: av_log(s, AV_LOG_DEBUG, - "element 0x%02x set to 0x%08x\n", + "element 0x%02x set to 0x%08"PRIx32"\n", subbyte, read_arbitrary(pb)); break; } @@ -183,7 +185,7 @@ static int process_audio_header_elements(AVFormatContext *s) break; default: av_log(s, AV_LOG_DEBUG, - "header element 0x%02x set to 0x%08x\n", + "header element 0x%02x set to 0x%08"PRIx32"\n", byte, read_arbitrary(pb)); break; } @@ -351,13 +353,13 @@ static int process_ea_header(AVFormatContext *s) int i; for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) { - unsigned int startpos = avio_tell(pb); + uint64_t startpos = avio_tell(pb); int err = 0; blockid = avio_rl32(pb); size = avio_rl32(pb); if (i == 0) - ea->big_endian = size > 0x000FFFFF; + ea->big_endian = size > av_bswap32(size); if (ea->big_endian) size = av_bswap32(size); diff --git a/chromium/third_party/ffmpeg/libavformat/ffmdec.c b/chromium/third_party/ffmpeg/libavformat/ffmdec.c index 679d926da16..9d89b166435 100644 --- a/chromium/third_party/ffmpeg/libavformat/ffmdec.c +++ b/chromium/third_party/ffmpeg/libavformat/ffmdec.c @@ -280,9 +280,8 @@ static int ffm2_read_header(AVFormatContext *s) codec->flags2 = avio_rb32(pb); codec->debug = avio_rb32(pb); if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { - if (ff_alloc_extradata(codec, avio_rb32(pb))) + if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); } avio_seek(pb, next, SEEK_SET); id = avio_rb32(pb); @@ -468,9 +467,8 @@ static int ffm_read_header(AVFormatContext *s) goto fail; } if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { - if (ff_alloc_extradata(codec, avio_rb32(pb))) + if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); } } diff --git a/chromium/third_party/ffmpeg/libavformat/file.c b/chromium/third_party/ffmpeg/libavformat/file.c index 2defc75e5f7..6511328de7d 100644 --- a/chromium/third_party/ffmpeg/libavformat/file.c +++ b/chromium/third_party/ffmpeg/libavformat/file.c @@ -54,7 +54,7 @@ typedef struct FileContext { } FileContext; static const AVOption file_options[] = { - { "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL } }; @@ -104,25 +104,30 @@ static int file_get_handle(URLContext *h) static int file_check(URLContext *h, int mask) { -#if HAVE_ACCESS && defined(R_OK) int ret = 0; - if (access(h->filename, F_OK) < 0) + const char *filename = h->filename; + av_strstart(filename, "file:", &filename); + + { +#if HAVE_ACCESS && defined(R_OK) + if (access(filename, F_OK) < 0) return AVERROR(errno); if (mask&AVIO_FLAG_READ) - if (access(h->filename, R_OK) >= 0) + if (access(filename, R_OK) >= 0) ret |= AVIO_FLAG_READ; if (mask&AVIO_FLAG_WRITE) - if (access(h->filename, W_OK) >= 0) + if (access(filename, W_OK) >= 0) ret |= AVIO_FLAG_WRITE; #else struct stat st; - int ret = stat(h->filename, &st); + ret = stat(filename, &st); if (ret < 0) return AVERROR(errno); ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0; ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0; #endif + } return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/flac_picture.c b/chromium/third_party/ffmpeg/libavformat/flac_picture.c index 12d73e488f9..5f2026d1d0e 100644 --- a/chromium/third_party/ffmpeg/libavformat/flac_picture.c +++ b/chromium/third_party/ffmpeg/libavformat/flac_picture.c @@ -107,9 +107,10 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) ret = AVERROR_INVALIDDATA; goto fail; } - if (!(data = av_buffer_alloc(len))) { + if (!(data = av_buffer_alloc(len + FF_INPUT_BUFFER_PADDING_SIZE))) { RETURN_ERROR(AVERROR(ENOMEM)); } + memset(data->data + len, 0, FF_INPUT_BUFFER_PADDING_SIZE); if (avio_read(pb, data->data, len) != len) { av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n"); if (s->error_recognition & AV_EF_EXPLODE) diff --git a/chromium/third_party/ffmpeg/libavformat/flacdec.c b/chromium/third_party/ffmpeg/libavformat/flacdec.c index 29310b831f1..cd752e1a20f 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flacdec.c @@ -26,6 +26,7 @@ #include "rawdec.h" #include "oggdec.h" #include "vorbiscomment.h" +#include "replaygain.h" #include "libavcodec/bytestream.h" static int flac_read_header(AVFormatContext *s) @@ -143,6 +144,10 @@ static int flac_read_header(AVFormatContext *s) } } + ret = ff_replaygain_export(st, s->metadata); + if (ret < 0) + return ret; + return 0; fail: @@ -157,12 +162,61 @@ static int flac_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION; } +static av_unused int64_t flac_read_timestamp(AVFormatContext *s, int stream_index, + int64_t *ppos, int64_t pos_limit) +{ + AVPacket pkt, out_pkt; + AVStream *st = s->streams[stream_index]; + AVCodecParserContext *parser; + int ret; + int64_t pts = AV_NOPTS_VALUE; + + if (avio_seek(s->pb, *ppos, SEEK_SET) < 0) + return AV_NOPTS_VALUE; + + av_init_packet(&pkt); + parser = av_parser_init(st->codec->codec_id); + if (!parser){ + return AV_NOPTS_VALUE; + } + parser->flags |= PARSER_FLAG_USE_CODEC_TS; + + for (;;){ + ret = ff_raw_read_partial_packet(s, &pkt); + if (ret < 0){ + if (ret == AVERROR(EAGAIN)) + continue; + else + break; + } + av_init_packet(&out_pkt); + ret = av_parser_parse2(parser, st->codec, + &out_pkt.data, &out_pkt.size, pkt.data, pkt.size, + pkt.pts, pkt.dts, *ppos); + + av_free_packet(&pkt); + if (out_pkt.size){ + int size = out_pkt.size; + if (parser->pts != AV_NOPTS_VALUE){ + // seeking may not have started from beginning of a frame + // calculate frame start position from next frame backwards + *ppos = parser->next_frame_offset - size; + pts = parser->pts; + break; + } + } + } + av_parser_close(parser); + return pts; +} + AVInputFormat ff_flac_demuxer = { .name = "flac", .long_name = NULL_IF_CONFIG_SMALL("raw FLAC"), .read_probe = flac_probe, .read_header = flac_read_header, .read_packet = ff_raw_read_partial_packet, + .read_timestamp = flac_read_timestamp, .flags = AVFMT_GENERIC_INDEX, .extensions = "flac", .raw_codec_id = AV_CODEC_ID_FLAC, diff --git a/chromium/third_party/ffmpeg/libavformat/flacenc.c b/chromium/third_party/ffmpeg/libavformat/flacenc.c index 87e93625f28..d92801807ef 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacenc.c +++ b/chromium/third_party/ffmpeg/libavformat/flacenc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/opt.h" #include "libavcodec/flac.h" #include "avformat.h" #include "avio_internal.h" @@ -27,6 +28,11 @@ #include "libavcodec/bytestream.h" +typedef struct FlacMuxerContext { + const AVClass *class; + int write_header; +} FlacMuxerContext; + static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes, int last_block) { @@ -65,7 +71,12 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, static int flac_write_header(struct AVFormatContext *s) { int ret; + int padding = s->metadata_header_padding; AVCodecContext *codec = s->streams[0]->codec; + FlacMuxerContext *c = s->priv_data; + + if (!c->write_header) + return 0; if (s->nb_streams > 1) { av_log(s, AV_LOG_ERROR, "only one stream is supported\n"); @@ -76,20 +87,27 @@ static int flac_write_header(struct AVFormatContext *s) return AVERROR(EINVAL); } + if (padding < 0) + padding = 8192; + /* The FLAC specification states that 24 bits are used to represent the + * size of a metadata block so we must clip this value to 2^24-1. */ + padding = av_clip_c(padding, 0, 16777215); + ret = ff_flac_write_header(s->pb, codec, 0); if (ret) return ret; - ret = flac_write_block_comment(s->pb, &s->metadata, 0, - codec->flags & CODEC_FLAG_BITEXACT); + ret = flac_write_block_comment(s->pb, &s->metadata, !padding, + s->flags & AVFMT_FLAG_BITEXACT); if (ret) return ret; /* The command line flac encoder defaults to placing a seekpoint * every 10s. So one might add padding to allow that later * but there seems to be no simple way to get the duration here. - * So let's try the flac default of 8192 bytes */ - flac_write_block_padding(s->pb, 8192, 1); + * So just add the amount requested by the user. */ + if (padding) + flac_write_block_padding(s->pb, padding, 1); return ret; } @@ -100,6 +118,10 @@ static int flac_write_trailer(struct AVFormatContext *s) uint8_t *streaminfo; enum FLACExtradataFormat format; int64_t file_size; + FlacMuxerContext *c = s->priv_data; + + if (!c->write_header) + return 0; if (!avpriv_flac_is_extradata_valid(s->streams[0]->codec, &format, &streaminfo)) return -1; @@ -123,9 +145,22 @@ static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt) return 0; } +static const AVOption flacenc_options[] = { + { "write_header", "Write the file header", offsetof(FlacMuxerContext, write_header), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { NULL }, +}; + +static const AVClass flac_muxer_class = { + .class_name = "flac muxer", + .item_name = av_default_item_name, + .option = flacenc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_flac_muxer = { .name = "flac", .long_name = NULL_IF_CONFIG_SMALL("raw FLAC"), + .priv_data_size = sizeof(FlacMuxerContext), .mime_type = "audio/x-flac", .extensions = "flac", .audio_codec = AV_CODEC_ID_FLAC, @@ -134,4 +169,5 @@ AVOutputFormat ff_flac_muxer = { .write_packet = flac_write_packet, .write_trailer = flac_write_trailer, .flags = AVFMT_NOTIMESTAMPS, + .priv_class = &flac_muxer_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/flvdec.c b/chromium/third_party/ffmpeg/libavformat/flvdec.c index 1024001a473..c0eddd3820d 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flvdec.c @@ -256,6 +256,7 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, return 1; // 1 byte body size adjustment for flv_read_packet() case FLV_CODECID_H264: vcodec->codec_id = AV_CODEC_ID_H264; + vstream->need_parsing = AVSTREAM_PARSE_HEADERS; return 3; // not 4, reading packet type will consume one byte case FLV_CODECID_MPEG4: vcodec->codec_id = AV_CODEC_ID_MPEG4; @@ -295,7 +296,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t initial_pos = avio_tell(ioc); if (vstream->nb_index_entries>0) { - av_log(s, AV_LOG_WARNING, "Skiping duplicate index\n"); + av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n"); return 0; } @@ -579,7 +580,7 @@ static int flv_read_header(AVFormatContext *s) flags = FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO; av_log(s, AV_LOG_WARNING, "Broken FLV file, which says no streams present, " - "this might fail\n"); + "this might fail.\n"); } s->ctx_flags |= AVFMTCTX_NOHEADER; @@ -614,9 +615,8 @@ static int flv_read_close(AVFormatContext *s) static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size) { av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, s->pb, size) < 0) return AVERROR(ENOMEM); - avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); return 0; } @@ -772,7 +772,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) size = avio_rb24(s->pb); dts = avio_rb24(s->pb); dts |= avio_r8(s->pb) << 24; - av_dlog(s, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts); + av_dlog(s, "type:%d, size:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, dts, avio_tell(s->pb)); if (url_feof(s->pb)) return AVERROR_EOF; avio_skip(s->pb, 3); /* stream id, always 0 */ @@ -820,7 +820,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } } else { av_log(s, AV_LOG_DEBUG, - "skipping flv packet: type %d, size %d, flags %d\n", + "Skipping flv packet: type %d, size %d, flags %d.\n", type, size, flags); skip: avio_seek(s->pb, next, SEEK_SET); @@ -916,7 +916,7 @@ retry_duration: flv->last_channels = channels = st->codec->channels; } else { - AVCodecContext ctx; + AVCodecContext ctx = {0}; ctx.sample_rate = sample_rate; flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK); sample_rate = ctx.sample_rate; @@ -934,15 +934,20 @@ retry_duration: // sign extension int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; pts = dts + cts; - if (cts < 0) { // dts are wrong + if (cts < 0) { // dts might be wrong + if (!flv->wrong_dts) + av_log(s, AV_LOG_WARNING, + "Negative cts, previous timestamps might be wrong.\n"); flv->wrong_dts = 1; + } else if (FFABS(dts - pts) > 1000*60*15) { av_log(s, AV_LOG_WARNING, - "negative cts, previous timestamps might be wrong\n"); + "invalid timestamps %"PRId64" %"PRId64"\n", dts, pts); + dts = pts = AV_NOPTS_VALUE; } - if (flv->wrong_dts) - dts = AV_NOPTS_VALUE; } if (type == 0 && (!st->codec->extradata || st->codec->codec_id == AV_CODEC_ID_AAC)) { + AVDictionaryEntry *t; + if (st->codec->extradata) { if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0) return ret; @@ -951,8 +956,15 @@ retry_duration: } if ((ret = flv_get_extradata(s, st, size)) < 0) return ret; + + /* Workaround for buggy Omnia A/XE encoder */ + t = av_dict_get(s->metadata, "Encoder", NULL, 0); + if (st->codec->codec_id == AV_CODEC_ID_AAC && t && !strcmp(t->value, "Omnia A/XE")) + st->codec->extradata_size = 2; + if (st->codec->codec_id == AV_CODEC_ID_AAC && 0) { MPEG4AudioConfig cfg; + if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, st->codec->extradata_size * 8, 1) >= 0) { st->codec->channels = cfg.channels; diff --git a/chromium/third_party/ffmpeg/libavformat/flvenc.c b/chromium/third_party/ffmpeg/libavformat/flvenc.c index a1b498d9e1d..c16f8ebb4a7 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/flvenc.c @@ -233,6 +233,9 @@ static int flv_write_header(AVFormatContext *s) audio_enc = enc; if (get_audio_flags(s, enc) < 0) return AVERROR_INVALIDDATA; + if (enc->codec_id == AV_CODEC_ID_PCM_S16BE) + av_log(s, AV_LOG_WARNING, + "16-bit big-endian audio in flv is valid but most likely unplayable (hardware dependent); use s16le\n"); break; case AVMEDIA_TYPE_DATA: if (enc->codec_id != AV_CODEC_ID_TEXT) { @@ -539,7 +542,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (enc->codec_type == AVMEDIA_TYPE_DATA) { int data_size; - int metadata_size_pos = avio_tell(pb); + int64_t metadata_size_pos = avio_tell(pb); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); diff --git a/chromium/third_party/ffmpeg/libavformat/format.c b/chromium/third_party/ffmpeg/libavformat/format.c index 36c0131c12e..95060f373d7 100644 --- a/chromium/third_party/ffmpeg/libavformat/format.c +++ b/chromium/third_party/ffmpeg/libavformat/format.c @@ -33,6 +33,9 @@ static AVInputFormat *first_iformat = NULL; /** head of registered output format linked list */ static AVOutputFormat *first_oformat = NULL; +static AVInputFormat **last_iformat = &first_iformat; +static AVOutputFormat **last_oformat = &first_oformat; + AVInputFormat *av_iformat_next(AVInputFormat *f) { if (f) @@ -51,20 +54,22 @@ AVOutputFormat *av_oformat_next(AVOutputFormat *f) void av_register_input_format(AVInputFormat *format) { - AVInputFormat **p = &first_iformat; + AVInputFormat **p = last_iformat; format->next = NULL; while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) p = &(*p)->next; + last_iformat = &format->next; } void av_register_output_format(AVOutputFormat *format) { - AVOutputFormat **p = &first_oformat; + AVOutputFormat **p = last_oformat; format->next = NULL; while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) p = &(*p)->next; + last_oformat = &format->next; } int av_match_ext(const char *filename, const char *extensions) diff --git a/chromium/third_party/ffmpeg/libavformat/framecrcenc.c b/chromium/third_party/ffmpeg/libavformat/framecrcenc.c index dbe49b5ba1e..4a96083953f 100644 --- a/chromium/third_party/ffmpeg/libavformat/framecrcenc.c +++ b/chromium/third_party/ffmpeg/libavformat/framecrcenc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/adler32.h" #include "libavutil/avstring.h" #include "avformat.h" @@ -29,7 +31,7 @@ static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt) uint32_t crc = av_adler32_update(0, pkt->data, pkt->size); char buf[256]; - snprintf(buf, sizeof(buf), "%d, %10"PRId64", %10"PRId64", %8d, %8d, 0x%08x", + snprintf(buf, sizeof(buf), "%d, %10"PRId64", %10"PRId64", %8d, %8d, 0x%08"PRIx32, pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size, crc); if (pkt->flags != AV_PKT_FLAG_KEY) av_strlcatf(buf, sizeof(buf), ", F=0x%0X", pkt->flags); diff --git a/chromium/third_party/ffmpeg/libavformat/ftp.c b/chromium/third_party/ffmpeg/libavformat/ftp.c index ed9a3db419b..dae8aa086d2 100644 --- a/chromium/third_party/ffmpeg/libavformat/ftp.c +++ b/chromium/third_party/ffmpeg/libavformat/ftp.c @@ -572,13 +572,15 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence) return AVERROR(EINVAL); } - if (h->is_streamed) + if (h->is_streamed) return AVERROR(EIO); - /* XXX: Simulate behaviour of lseek in file protocol, which could be treated as a reference */ - new_pos = FFMAX(0, new_pos); - fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos; + if (new_pos < 0) { + av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n"); + return AVERROR(EINVAL); + } + fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos; if (fake_pos != s->position) { if ((err = ftp_abort(h)) < 0) return err; diff --git a/chromium/third_party/ffmpeg/libavformat/gif.c b/chromium/third_party/ffmpeg/libavformat/gif.c index e52498d42b4..e8171214400 100644 --- a/chromium/third_party/ffmpeg/libavformat/gif.c +++ b/chromium/third_party/ffmpeg/libavformat/gif.c @@ -28,10 +28,19 @@ #include "libavutil/log.h" #include "libavutil/opt.h" -static int gif_image_write_header(AVIOContext *pb, int width, int height, +static int gif_image_write_header(AVFormatContext *s, int width, int height, int loop_count, uint32_t *palette) { + AVIOContext *pb = s->pb; + AVRational sar = s->streams[0]->codec->sample_aspect_ratio; int i; + int64_t aspect = 0; + + if (sar.num > 0 && sar.den > 0) { + aspect = sar.num * 64LL / sar.den - 15; + if (aspect < 0 || aspect > 255) + aspect = 0; + } avio_write(pb, "GIF", 3); avio_write(pb, "89a", 3); @@ -41,7 +50,7 @@ static int gif_image_write_header(AVIOContext *pb, int width, int height, if (palette) { avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */ avio_w8(pb, 0x1f); /* background color index */ - avio_w8(pb, 0); /* aspect ratio */ + avio_w8(pb, aspect); for (i = 0; i < 256; i++) { const uint32_t v = palette[i] & 0xffffff; avio_wb24(pb, v); @@ -49,7 +58,7 @@ static int gif_image_write_header(AVIOContext *pb, int width, int height, } else { avio_w8(pb, 0); /* flags */ avio_w8(pb, 0); /* background color index */ - avio_w8(pb, 0); /* aspect ratio */ + avio_w8(pb, aspect); } @@ -79,7 +88,6 @@ typedef struct { static int gif_write_header(AVFormatContext *s) { GIFContext *gif = s->priv_data; - AVIOContext *pb = s->pb; AVCodecContext *video_enc; int width, height; uint32_t palette[AVPALETTE_COUNT]; @@ -99,9 +107,9 @@ static int gif_write_header(AVFormatContext *s) avpriv_set_pts_info(s->streams[0], 64, 1, 100); if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) { av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8); - gif_image_write_header(pb, width, height, gif->loop, NULL); + gif_image_write_header(s, width, height, gif->loop, NULL); } else { - gif_image_write_header(pb, width, height, gif->loop, palette); + gif_image_write_header(s, width, height, gif->loop, palette); } avio_flush(s->pb); diff --git a/chromium/third_party/ffmpeg/libavformat/golomb_tab.c b/chromium/third_party/ffmpeg/libavformat/golomb_tab.c new file mode 100644 index 00000000000..063fae36471 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/golomb_tab.c @@ -0,0 +1 @@ +#include "libavcodec/golomb.c" diff --git a/chromium/third_party/ffmpeg/libavformat/gxf.c b/chromium/third_party/ffmpeg/libavformat/gxf.c index c36479a8213..479a8fb394d 100644 --- a/chromium/third_party/ffmpeg/libavformat/gxf.c +++ b/chromium/third_party/ffmpeg/libavformat/gxf.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "avformat.h" @@ -293,7 +295,9 @@ static void gxf_read_index(AVFormatContext *s, int pkt_len) { } st = s->streams[0]; if (map_cnt > 1000) { - av_log(s, AV_LOG_ERROR, "too many index entries %u (%x)\n", map_cnt, map_cnt); + av_log(s, AV_LOG_ERROR, + "too many index entries %"PRIu32" (%"PRIx32")\n", + map_cnt, map_cnt); map_cnt = 1000; } if (pkt_len < 4 * map_cnt) { diff --git a/chromium/third_party/ffmpeg/libavformat/gxfenc.c b/chromium/third_party/ffmpeg/libavformat/gxfenc.c index 5fa510057d3..12031f7cd91 100644 --- a/chromium/third_party/ffmpeg/libavformat/gxfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/gxfenc.c @@ -949,7 +949,7 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) AVStream *st = s->streams[pkt->stream_index]; int64_t pos = avio_tell(pb); int padding = 0; - int packet_start_offset = avio_tell(pb) / 1024; + unsigned packet_start_offset = avio_tell(pb) / 1024; int ret; gxf_write_packet_header(pb, PKT_MEDIA); diff --git a/chromium/third_party/ffmpeg/libavformat/h263dec.c b/chromium/third_party/ffmpeg/libavformat/h263dec.c index e6e0345b690..145fb859021 100644 --- a/chromium/third_party/ffmpeg/libavformat/h263dec.c +++ b/chromium/third_party/ffmpeg/libavformat/h263dec.c @@ -31,24 +31,37 @@ static int h263_probe(AVProbeData *p) int res_change=0; int src_fmt, last_src_fmt=-1; int last_gn=0; + int tr, last_tr = -1; for(i=0; i<p->buf_size; i++){ code = (code<<8) + p->buf[i]; - if ((code & 0xfffffc0000) == 0x800000) { - src_fmt= (code>>2)&3; + if ((code & 0xfffffc000000) == 0x80000000) { + tr = (code >> 18) & 0xFF; + src_fmt= (code>>10)&7; if( src_fmt != last_src_fmt && last_src_fmt>0 && last_src_fmt<6 && src_fmt<6) res_change++; - if((code&0x300)==0x200 && src_fmt){ + if (tr == last_tr) { + invalid_psc++; + continue; + } + + if (src_fmt != 7 && !(code&(1<<9)) && (code&(1<<5))) { + invalid_psc++; + continue; + } + + if((code&0x30000)==0x20000 && src_fmt){ valid_psc++; last_gn=0; }else invalid_psc++; last_src_fmt= src_fmt; - } else if((code & 0xffff800000) == 0x800000) { - int gn= (code>>(23-5)) & 0x1F; + last_tr = tr; + } else if((code & 0xffff80000000) == 0x80000000) { + int gn= (code>>(31-5)) & 0x1F; if(gn<last_gn){ invalid_psc++; }else diff --git a/chromium/third_party/ffmpeg/libavformat/hdsenc.c b/chromium/third_party/ffmpeg/libavformat/hdsenc.c index 08ae5490d24..fb0a94892aa 100644 --- a/chromium/third_party/ffmpeg/libavformat/hdsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hdsenc.c @@ -89,7 +89,7 @@ static int parse_header(OutputStream *os, const uint8_t *buf, int buf_size) if (size > buf_size) return AVERROR_INVALIDDATA; if (type == 8 || type == 9) { - if (os->nb_extra_packets > FF_ARRAY_ELEMS(os->extra_packets)) + if (os->nb_extra_packets >= FF_ARRAY_ELEMS(os->extra_packets)) return AVERROR_INVALIDDATA; os->extra_packet_sizes[os->nb_extra_packets] = size; os->extra_packets[os->nb_extra_packets] = av_malloc(size); @@ -204,7 +204,10 @@ static int write_manifest(AVFormatContext *s, int final) avio_printf(out, "</manifest>\n"); avio_flush(out); avio_close(out); - rename(temp_filename, filename); + if (rename(temp_filename, filename) == -1) { + av_log(s, AV_LOG_ERROR, "failed to rename file %s to %s\n", temp_filename, filename); + return AVERROR(errno); + } return 0; } @@ -286,7 +289,10 @@ static int write_abst(AVFormatContext *s, OutputStream *os, int final) update_size(out, afrt_pos); update_size(out, 0); avio_close(out); - rename(temp_filename, filename); + if (rename(temp_filename, filename) == -1) { + av_log(s, AV_LOG_ERROR, "failed to rename file %s to %s\n", temp_filename, filename); + return AVERROR(errno); + } return 0; } @@ -323,7 +329,14 @@ static int hds_write_header(AVFormatContext *s) int ret = 0, i; AVOutputFormat *oformat; - mkdir(s->filename, 0777); + if (mkdir(s->filename, 0777)) { + int is_error = errno != EEXIST; + av_log(s, is_error ? AV_LOG_ERROR : AV_LOG_VERBOSE, "Failed to create directory %s\n", s->filename); + if (is_error) { + ret = AVERROR(errno); + goto fail; + } + } oformat = av_guess_format("flv", NULL, NULL); if (!oformat) { @@ -412,7 +425,9 @@ static int hds_write_header(AVFormatContext *s) snprintf(os->temp_filename, sizeof(os->temp_filename), "%s/stream%d_temp", s->filename, i); - init_file(s, os, 0); + ret = init_file(s, os, 0); + if (ret < 0) + goto fail; if (!os->has_video && c->min_frag_duration <= 0) { av_log(s, AV_LOG_WARNING, @@ -475,7 +490,10 @@ static int hds_flush(AVFormatContext *s, OutputStream *os, int final, snprintf(target_filename, sizeof(target_filename), "%s/stream%dSeg1-Frag%d", s->filename, index, os->fragment_index); - rename(os->temp_filename, target_filename); + if (rename(os->temp_filename, target_filename) == -1) { + av_log(s, AV_LOG_ERROR, "failed to rename file %s to %s\n", os->temp_filename, target_filename); + return AVERROR(errno); + } add_fragment(os, target_filename, os->frag_start_ts, end_ts - os->frag_start_ts); if (!final) { @@ -509,7 +527,7 @@ static int hds_write_packet(AVFormatContext *s, AVPacket *pkt) HDSContext *c = s->priv_data; AVStream *st = s->streams[pkt->stream_index]; OutputStream *os = &c->streams[s->streams[pkt->stream_index]->id]; - int64_t end_dts = (os->fragment_index) * c->min_frag_duration; + int64_t end_dts = os->fragment_index * (int64_t)c->min_frag_duration; int ret; if (st->first_dts == AV_NOPTS_VALUE) diff --git a/chromium/third_party/ffmpeg/libavformat/hevc.c b/chromium/third_party/ffmpeg/libavformat/hevc.c new file mode 100644 index 00000000000..96323861532 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/hevc.c @@ -0,0 +1,1140 @@ +/* + * Copyright (c) 2014 Tim Walker <tdskywalker@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 "libavcodec/get_bits.h" +#include "libavcodec/golomb.h" +#include "libavcodec/hevc.h" +#include "libavutil/intreadwrite.h" +#include "avc.h" +#include "avio.h" +#include "hevc.h" + +#define MAX_SPATIAL_SEGMENTATION 4096 // max. value of u(12) field + +typedef struct HVCCNALUnitArray { + uint8_t array_completeness; + uint8_t NAL_unit_type; + uint16_t numNalus; + uint16_t *nalUnitLength; + uint8_t **nalUnit; +} HVCCNALUnitArray; + +typedef struct HEVCDecoderConfigurationRecord { + uint8_t configurationVersion; + uint8_t general_profile_space; + uint8_t general_tier_flag; + uint8_t general_profile_idc; + uint32_t general_profile_compatibility_flags; + uint64_t general_constraint_indicator_flags; + uint8_t general_level_idc; + uint16_t min_spatial_segmentation_idc; + uint8_t parallelismType; + uint8_t chromaFormat; + uint8_t bitDepthLumaMinus8; + uint8_t bitDepthChromaMinus8; + uint16_t avgFrameRate; + uint8_t constantFrameRate; + uint8_t numTemporalLayers; + uint8_t temporalIdNested; + uint8_t lengthSizeMinusOne; + uint8_t numOfArrays; + HVCCNALUnitArray *array; +} HEVCDecoderConfigurationRecord; + +typedef struct HVCCProfileTierLevel { + uint8_t profile_space; + uint8_t tier_flag; + uint8_t profile_idc; + uint32_t profile_compatibility_flags; + uint64_t constraint_indicator_flags; + uint8_t level_idc; +} HVCCProfileTierLevel; + +static void hvcc_update_ptl(HEVCDecoderConfigurationRecord *hvcc, + HVCCProfileTierLevel *ptl) +{ + /* + * The value of general_profile_space in all the parameter sets must be + * identical. + */ + hvcc->general_profile_space = ptl->profile_space; + + /* + * The level indication general_level_idc must indicate a level of + * capability equal to or greater than the highest level indicated for the + * highest tier in all the parameter sets. + */ + if (hvcc->general_tier_flag < ptl->tier_flag) + hvcc->general_level_idc = ptl->level_idc; + else + hvcc->general_level_idc = FFMAX(hvcc->general_level_idc, ptl->level_idc); + + /* + * The tier indication general_tier_flag must indicate a tier equal to or + * greater than the highest tier indicated in all the parameter sets. + */ + hvcc->general_tier_flag = FFMAX(hvcc->general_tier_flag, ptl->tier_flag); + + /* + * The profile indication general_profile_idc must indicate a profile to + * which the stream associated with this configuration record conforms. + * + * If the sequence parameter sets are marked with different profiles, then + * the stream may need examination to determine which profile, if any, the + * entire stream conforms to. If the entire stream is not examined, or the + * examination reveals that there is no profile to which the entire stream + * conforms, then the entire stream must be split into two or more + * sub-streams with separate configuration records in which these rules can + * be met. + * + * Note: set the profile to the highest value for the sake of simplicity. + */ + hvcc->general_profile_idc = FFMAX(hvcc->general_profile_idc, ptl->profile_idc); + + /* + * Each bit in general_profile_compatibility_flags may only be set if all + * the parameter sets set that bit. + */ + hvcc->general_profile_compatibility_flags &= ptl->profile_compatibility_flags; + + /* + * Each bit in general_constraint_indicator_flags may only be set if all + * the parameter sets set that bit. + */ + hvcc->general_constraint_indicator_flags &= ptl->constraint_indicator_flags; +} + +static void hvcc_parse_ptl(GetBitContext *gb, + HEVCDecoderConfigurationRecord *hvcc, + unsigned int max_sub_layers_minus1) +{ + unsigned int i; + HVCCProfileTierLevel general_ptl; + uint8_t sub_layer_profile_present_flag[MAX_SUB_LAYERS]; + uint8_t sub_layer_level_present_flag[MAX_SUB_LAYERS]; + + general_ptl.profile_space = get_bits(gb, 2); + general_ptl.tier_flag = get_bits1(gb); + general_ptl.profile_idc = get_bits(gb, 5); + general_ptl.profile_compatibility_flags = get_bits_long(gb, 32); + general_ptl.constraint_indicator_flags = get_bits64(gb, 48); + general_ptl.level_idc = get_bits(gb, 8); + hvcc_update_ptl(hvcc, &general_ptl); + + for (i = 0; i < max_sub_layers_minus1; i++) { + sub_layer_profile_present_flag[i] = get_bits1(gb); + sub_layer_level_present_flag[i] = get_bits1(gb); + } + + if (max_sub_layers_minus1 > 0) + for (i = max_sub_layers_minus1; i < 8; i++) + skip_bits(gb, 2); // reserved_zero_2bits[i] + + for (i = 0; i < max_sub_layers_minus1; i++) { + if (sub_layer_profile_present_flag[i]) { + /* + * sub_layer_profile_space[i] u(2) + * sub_layer_tier_flag[i] u(1) + * sub_layer_profile_idc[i] u(5) + * sub_layer_profile_compatibility_flag[i][0..31] u(32) + * sub_layer_progressive_source_flag[i] u(1) + * sub_layer_interlaced_source_flag[i] u(1) + * sub_layer_non_packed_constraint_flag[i] u(1) + * sub_layer_frame_only_constraint_flag[i] u(1) + * sub_layer_reserved_zero_44bits[i] u(44) + */ + skip_bits_long(gb, 32); + skip_bits_long(gb, 32); + skip_bits (gb, 24); + } + + if (sub_layer_level_present_flag[i]) + skip_bits(gb, 8); + } +} + +static void skip_sub_layer_hrd_parameters(GetBitContext *gb, + unsigned int cpb_cnt_minus1, + uint8_t sub_pic_hrd_params_present_flag) +{ + unsigned int i; + + for (i = 0; i <= cpb_cnt_minus1; i++) { + get_ue_golomb_long(gb); // bit_rate_value_minus1 + get_ue_golomb_long(gb); // cpb_size_value_minus1 + + if (sub_pic_hrd_params_present_flag) { + get_ue_golomb_long(gb); // cpb_size_du_value_minus1 + get_ue_golomb_long(gb); // bit_rate_du_value_minus1 + } + + skip_bits1(gb); // cbr_flag + } +} + +static void skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag, + unsigned int max_sub_layers_minus1) +{ + unsigned int i; + uint8_t sub_pic_hrd_params_present_flag = 0; + uint8_t nal_hrd_parameters_present_flag = 0; + uint8_t vcl_hrd_parameters_present_flag = 0; + + if (cprms_present_flag) { + nal_hrd_parameters_present_flag = get_bits1(gb); + vcl_hrd_parameters_present_flag = get_bits1(gb); + + if (nal_hrd_parameters_present_flag || + vcl_hrd_parameters_present_flag) { + sub_pic_hrd_params_present_flag = get_bits1(gb); + + if (sub_pic_hrd_params_present_flag) + /* + * tick_divisor_minus2 u(8) + * du_cpb_removal_delay_increment_length_minus1 u(5) + * sub_pic_cpb_params_in_pic_timing_sei_flag u(1) + * dpb_output_delay_du_length_minus1 u(5) + */ + skip_bits(gb, 19); + + /* + * bit_rate_scale u(4) + * cpb_size_scale u(4) + */ + skip_bits(gb, 8); + + if (sub_pic_hrd_params_present_flag) + skip_bits(gb, 4); // cpb_size_du_scale + + /* + * initial_cpb_removal_delay_length_minus1 u(5) + * au_cpb_removal_delay_length_minus1 u(5) + * dpb_output_delay_length_minus1 u(5) + */ + skip_bits(gb, 15); + } + } + + for (i = 0; i <= max_sub_layers_minus1; i++) { + unsigned int cpb_cnt_minus1 = 0; + uint8_t low_delay_hrd_flag = 0; + uint8_t fixed_pic_rate_within_cvs_flag = 0; + uint8_t fixed_pic_rate_general_flag = get_bits1(gb); + + if (!fixed_pic_rate_general_flag) + fixed_pic_rate_within_cvs_flag = get_bits1(gb); + + if (fixed_pic_rate_within_cvs_flag) + get_ue_golomb_long(gb); // elemental_duration_in_tc_minus1 + else + low_delay_hrd_flag = get_bits1(gb); + + if (!low_delay_hrd_flag) + cpb_cnt_minus1 = get_ue_golomb_long(gb); + + if (nal_hrd_parameters_present_flag) + skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1, + sub_pic_hrd_params_present_flag); + + if (vcl_hrd_parameters_present_flag) + skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1, + sub_pic_hrd_params_present_flag); + } +} + +static void skip_timing_info(GetBitContext *gb) +{ + skip_bits_long(gb, 32); // num_units_in_tick + skip_bits_long(gb, 32); // time_scale + + if (get_bits1(gb)) // poc_proportional_to_timing_flag + get_ue_golomb_long(gb); // num_ticks_poc_diff_one_minus1 +} + +static void hvcc_parse_vui(GetBitContext *gb, + HEVCDecoderConfigurationRecord *hvcc, + unsigned int max_sub_layers_minus1) +{ + unsigned int min_spatial_segmentation_idc; + + if (get_bits1(gb)) // aspect_ratio_info_present_flag + if (get_bits(gb, 8) == 255) // aspect_ratio_idc + skip_bits_long(gb, 32); // sar_width u(16), sar_height u(16) + + if (get_bits1(gb)) // overscan_info_present_flag + skip_bits1(gb); // overscan_appropriate_flag + + if (get_bits1(gb)) { // video_signal_type_present_flag + skip_bits(gb, 4); // video_format u(3), video_full_range_flag u(1) + + if (get_bits1(gb)) // colour_description_present_flag + /* + * colour_primaries u(8) + * transfer_characteristics u(8) + * matrix_coeffs u(8) + */ + skip_bits(gb, 24); + } + + if (get_bits1(gb)) { // chroma_loc_info_present_flag + get_ue_golomb_long(gb); // chroma_sample_loc_type_top_field + get_ue_golomb_long(gb); // chroma_sample_loc_type_bottom_field + } + + /* + * neutral_chroma_indication_flag u(1) + * field_seq_flag u(1) + * frame_field_info_present_flag u(1) + */ + skip_bits(gb, 3); + + if (get_bits1(gb)) { // default_display_window_flag + get_ue_golomb_long(gb); // def_disp_win_left_offset + get_ue_golomb_long(gb); // def_disp_win_right_offset + get_ue_golomb_long(gb); // def_disp_win_top_offset + get_ue_golomb_long(gb); // def_disp_win_bottom_offset + } + + if (get_bits1(gb)) { // vui_timing_info_present_flag + skip_timing_info(gb); + + if (get_bits1(gb)) // vui_hrd_parameters_present_flag + skip_hrd_parameters(gb, 1, max_sub_layers_minus1); + } + + if (get_bits1(gb)) { // bitstream_restriction_flag + /* + * tiles_fixed_structure_flag u(1) + * motion_vectors_over_pic_boundaries_flag u(1) + * restricted_ref_pic_lists_flag u(1) + */ + skip_bits(gb, 3); + + min_spatial_segmentation_idc = get_ue_golomb_long(gb); + + /* + * unsigned int(12) min_spatial_segmentation_idc; + * + * The min_spatial_segmentation_idc indication must indicate a level of + * spatial segmentation equal to or less than the lowest level of + * spatial segmentation indicated in all the parameter sets. + */ + hvcc->min_spatial_segmentation_idc = FFMIN(hvcc->min_spatial_segmentation_idc, + min_spatial_segmentation_idc); + + get_ue_golomb_long(gb); // max_bytes_per_pic_denom + get_ue_golomb_long(gb); // max_bits_per_min_cu_denom + get_ue_golomb_long(gb); // log2_max_mv_length_horizontal + get_ue_golomb_long(gb); // log2_max_mv_length_vertical + } +} + +static void skip_sub_layer_ordering_info(GetBitContext *gb) +{ + get_ue_golomb_long(gb); // max_dec_pic_buffering_minus1 + get_ue_golomb_long(gb); // max_num_reorder_pics + get_ue_golomb_long(gb); // max_latency_increase_plus1 +} + +static int hvcc_parse_vps(GetBitContext *gb, + HEVCDecoderConfigurationRecord *hvcc) +{ + unsigned int vps_max_sub_layers_minus1; + + /* + * vps_video_parameter_set_id u(4) + * vps_reserved_three_2bits u(2) + * vps_max_layers_minus1 u(6) + */ + skip_bits(gb, 12); + + vps_max_sub_layers_minus1 = get_bits(gb, 3); + + /* + * numTemporalLayers greater than 1 indicates that the stream to which this + * configuration record applies is temporally scalable and the contained + * number of temporal layers (also referred to as temporal sub-layer or + * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 + * indicates that the stream is not temporally scalable. Value 0 indicates + * that it is unknown whether the stream is temporally scalable. + */ + hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, + vps_max_sub_layers_minus1 + 1); + + /* + * vps_temporal_id_nesting_flag u(1) + * vps_reserved_0xffff_16bits u(16) + */ + skip_bits(gb, 17); + + hvcc_parse_ptl(gb, hvcc, vps_max_sub_layers_minus1); + + /* nothing useful for hvcC past this point */ + return 0; +} + +static void skip_scaling_list_data(GetBitContext *gb) +{ + int i, j, k, num_coeffs; + + for (i = 0; i < 4; i++) + for (j = 0; j < (i == 3 ? 2 : 6); j++) + if (!get_bits1(gb)) // scaling_list_pred_mode_flag[i][j] + get_ue_golomb_long(gb); // scaling_list_pred_matrix_id_delta[i][j] + else { + num_coeffs = FFMIN(64, 1 << (4 + (i << 1))); + + if (i > 1) + get_se_golomb_long(gb); // scaling_list_dc_coef_minus8[i-2][j] + + for (k = 0; k < num_coeffs; k++) + get_se_golomb_long(gb); // scaling_list_delta_coef + } +} + +static int parse_rps(GetBitContext *gb, unsigned int rps_idx, + unsigned int num_rps, + unsigned int num_delta_pocs[MAX_SHORT_TERM_RPS_COUNT]) +{ + unsigned int i; + + if (rps_idx && get_bits1(gb)) { // inter_ref_pic_set_prediction_flag + /* this should only happen for slice headers, and this isn't one */ + if (rps_idx >= num_rps) + return AVERROR_INVALIDDATA; + + skip_bits1 (gb); // delta_rps_sign + get_ue_golomb_long(gb); // abs_delta_rps_minus1 + + num_delta_pocs[rps_idx] = 0; + + /* + * From libavcodec/hevc_ps.c: + * + * if (is_slice_header) { + * //foo + * } else + * rps_ridx = &sps->st_rps[rps - sps->st_rps - 1]; + * + * where: + * rps: &sps->st_rps[rps_idx] + * sps->st_rps: &sps->st_rps[0] + * is_slice_header: rps_idx == num_rps + * + * thus: + * if (num_rps != rps_idx) + * rps_ridx = &sps->st_rps[rps_idx - 1]; + * + * NumDeltaPocs[RefRpsIdx]: num_delta_pocs[rps_idx - 1] + */ + for (i = 0; i < num_delta_pocs[rps_idx - 1]; i++) { + uint8_t use_delta_flag = 0; + uint8_t used_by_curr_pic_flag = get_bits1(gb); + if (!used_by_curr_pic_flag) + use_delta_flag = get_bits1(gb); + + if (used_by_curr_pic_flag || use_delta_flag) + num_delta_pocs[rps_idx]++; + } + } else { + unsigned int num_negative_pics = get_ue_golomb_long(gb); + unsigned int num_positive_pics = get_ue_golomb_long(gb); + + num_delta_pocs[rps_idx] = num_negative_pics + num_positive_pics; + + for (i = 0; i < num_negative_pics; i++) { + get_ue_golomb_long(gb); // delta_poc_s0_minus1[rps_idx] + skip_bits1 (gb); // used_by_curr_pic_s0_flag[rps_idx] + } + + for (i = 0; i < num_positive_pics; i++) { + get_ue_golomb_long(gb); // delta_poc_s1_minus1[rps_idx] + skip_bits1 (gb); // used_by_curr_pic_s1_flag[rps_idx] + } + } + + return 0; +} + +static int hvcc_parse_sps(GetBitContext *gb, + HEVCDecoderConfigurationRecord *hvcc) +{ + unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4; + unsigned int num_short_term_ref_pic_sets, num_delta_pocs[MAX_SHORT_TERM_RPS_COUNT]; + + skip_bits(gb, 4); // sps_video_parameter_set_id + + sps_max_sub_layers_minus1 = get_bits (gb, 3); + + /* + * numTemporalLayers greater than 1 indicates that the stream to which this + * configuration record applies is temporally scalable and the contained + * number of temporal layers (also referred to as temporal sub-layer or + * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 + * indicates that the stream is not temporally scalable. Value 0 indicates + * that it is unknown whether the stream is temporally scalable. + */ + hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, + sps_max_sub_layers_minus1 + 1); + + hvcc->temporalIdNested = get_bits1(gb); + + hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1); + + get_ue_golomb_long(gb); // sps_seq_parameter_set_id + + hvcc->chromaFormat = get_ue_golomb_long(gb); + + if (hvcc->chromaFormat == 3) + skip_bits1(gb); // separate_colour_plane_flag + + get_ue_golomb_long(gb); // pic_width_in_luma_samples + get_ue_golomb_long(gb); // pic_height_in_luma_samples + + if (get_bits1(gb)) { // conformance_window_flag + get_ue_golomb_long(gb); // conf_win_left_offset + get_ue_golomb_long(gb); // conf_win_right_offset + get_ue_golomb_long(gb); // conf_win_top_offset + get_ue_golomb_long(gb); // conf_win_bottom_offset + } + + hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb); + hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb); + log2_max_pic_order_cnt_lsb_minus4 = get_ue_golomb_long(gb); + + /* sps_sub_layer_ordering_info_present_flag */ + i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1; + for (; i <= sps_max_sub_layers_minus1; i++) + skip_sub_layer_ordering_info(gb); + + get_ue_golomb_long(gb); // log2_min_luma_coding_block_size_minus3 + get_ue_golomb_long(gb); // log2_diff_max_min_luma_coding_block_size + get_ue_golomb_long(gb); // log2_min_transform_block_size_minus2 + get_ue_golomb_long(gb); // log2_diff_max_min_transform_block_size + get_ue_golomb_long(gb); // max_transform_hierarchy_depth_inter + get_ue_golomb_long(gb); // max_transform_hierarchy_depth_intra + + if (get_bits1(gb) && // scaling_list_enabled_flag + get_bits1(gb)) // sps_scaling_list_data_present_flag + skip_scaling_list_data(gb); + + skip_bits1(gb); // amp_enabled_flag + skip_bits1(gb); // sample_adaptive_offset_enabled_flag + + if (get_bits1(gb)) { // pcm_enabled_flag + skip_bits (gb, 4); // pcm_sample_bit_depth_luma_minus1 + skip_bits (gb, 4); // pcm_sample_bit_depth_chroma_minus1 + get_ue_golomb_long(gb); // log2_min_pcm_luma_coding_block_size_minus3 + get_ue_golomb_long(gb); // log2_diff_max_min_pcm_luma_coding_block_size + skip_bits1 (gb); // pcm_loop_filter_disabled_flag + } + + num_short_term_ref_pic_sets = get_ue_golomb_long(gb); + if (num_short_term_ref_pic_sets > MAX_SHORT_TERM_RPS_COUNT) + return AVERROR_INVALIDDATA; + + for (i = 0; i < num_short_term_ref_pic_sets; i++) { + int ret = parse_rps(gb, i, num_short_term_ref_pic_sets, num_delta_pocs); + if (ret < 0) + return ret; + } + + if (get_bits1(gb)) { // long_term_ref_pics_present_flag + for (i = 0; i < get_ue_golomb_long(gb); i++) { // num_long_term_ref_pics_sps + int len = FFMIN(log2_max_pic_order_cnt_lsb_minus4 + 4, 16); + skip_bits (gb, len); // lt_ref_pic_poc_lsb_sps[i] + skip_bits1(gb); // used_by_curr_pic_lt_sps_flag[i] + } + } + + skip_bits1(gb); // sps_temporal_mvp_enabled_flag + skip_bits1(gb); // strong_intra_smoothing_enabled_flag + + if (get_bits1(gb)) // vui_parameters_present_flag + hvcc_parse_vui(gb, hvcc, sps_max_sub_layers_minus1); + + /* nothing useful for hvcC past this point */ + return 0; +} + +static int hvcc_parse_pps(GetBitContext *gb, + HEVCDecoderConfigurationRecord *hvcc) +{ + uint8_t tiles_enabled_flag, entropy_coding_sync_enabled_flag; + + get_ue_golomb_long(gb); // pps_pic_parameter_set_id + get_ue_golomb_long(gb); // pps_seq_parameter_set_id + + /* + * dependent_slice_segments_enabled_flag u(1) + * output_flag_present_flag u(1) + * num_extra_slice_header_bits u(3) + * sign_data_hiding_enabled_flag u(1) + * cabac_init_present_flag u(1) + */ + skip_bits(gb, 7); + + get_ue_golomb_long(gb); // num_ref_idx_l0_default_active_minus1 + get_ue_golomb_long(gb); // num_ref_idx_l1_default_active_minus1 + get_se_golomb_long(gb); // init_qp_minus26 + + /* + * constrained_intra_pred_flag u(1) + * transform_skip_enabled_flag u(1) + */ + skip_bits(gb, 2); + + if (get_bits1(gb)) // cu_qp_delta_enabled_flag + get_ue_golomb_long(gb); // diff_cu_qp_delta_depth + + get_se_golomb_long(gb); // pps_cb_qp_offset + get_se_golomb_long(gb); // pps_cr_qp_offset + + /* + * weighted_pred_flag u(1) + * weighted_bipred_flag u(1) + * transquant_bypass_enabled_flag u(1) + */ + skip_bits(gb, 3); + + tiles_enabled_flag = get_bits1(gb); + entropy_coding_sync_enabled_flag = get_bits1(gb); + + if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) + hvcc->parallelismType = 0; // mixed-type parallel decoding + else if (entropy_coding_sync_enabled_flag) + hvcc->parallelismType = 3; // wavefront-based parallel decoding + else if (tiles_enabled_flag) + hvcc->parallelismType = 2; // tile-based parallel decoding + else + hvcc->parallelismType = 1; // slice-based parallel decoding + + /* nothing useful for hvcC past this point */ + return 0; +} + +static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, + uint32_t *dst_len) +{ + uint8_t *dst; + uint32_t i, len; + + dst = av_malloc(src_len); + if (!dst) + return NULL; + + /* NAL unit header (2 bytes) */ + i = len = 0; + while (i < 2 && i < src_len) + dst[len++] = src[i++]; + + while (i + 2 < src_len) + if (!src[i] && !src[i + 1] && src[i + 2] == 3) { + dst[len++] = src[i++]; + dst[len++] = src[i++]; + i++; // remove emulation_prevention_three_byte + } else + dst[len++] = src[i++]; + + while (i < src_len) + dst[len++] = src[i++]; + + *dst_len = len; + return dst; +} + + + +static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) +{ + skip_bits1(gb); // forbidden_zero_bit + + *nal_type = get_bits(gb, 6); + + /* + * nuh_layer_id u(6) + * nuh_temporal_id_plus1 u(3) + */ + skip_bits(gb, 9); +} + +static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, + uint8_t nal_type, int ps_array_completeness, + HEVCDecoderConfigurationRecord *hvcc) +{ + int ret; + uint8_t index; + uint16_t numNalus; + HVCCNALUnitArray *array; + + for (index = 0; index < hvcc->numOfArrays; index++) + if (hvcc->array[index].NAL_unit_type == nal_type) + break; + + if (index >= hvcc->numOfArrays) { + uint8_t i; + + ret = av_reallocp_array(&hvcc->array, index + 1, sizeof(HVCCNALUnitArray)); + if (ret < 0) + return ret; + + for (i = hvcc->numOfArrays; i <= index; i++) + memset(&hvcc->array[i], 0, sizeof(HVCCNALUnitArray)); + hvcc->numOfArrays = index + 1; + } + + array = &hvcc->array[index]; + numNalus = array->numNalus; + + ret = av_reallocp_array(&array->nalUnit, numNalus + 1, sizeof(uint8_t*)); + if (ret < 0) + return ret; + + ret = av_reallocp_array(&array->nalUnitLength, numNalus + 1, sizeof(uint16_t)); + if (ret < 0) + return ret; + + array->nalUnit [numNalus] = nal_buf; + array->nalUnitLength[numNalus] = nal_size; + array->NAL_unit_type = nal_type; + array->numNalus++; + + /* + * When the sample entry name is ‘hvc1’, the default and mandatory value of + * array_completeness is 1 for arrays of all types of parameter sets, and 0 + * for all other arrays. When the sample entry name is ‘hev1’, the default + * value of array_completeness is 0 for all arrays. + */ + if (nal_type == NAL_VPS || nal_type == NAL_SPS || nal_type == NAL_PPS) + array->array_completeness = ps_array_completeness; + + return 0; +} + +static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, + int ps_array_completeness, + HEVCDecoderConfigurationRecord *hvcc) +{ + int ret = 0; + GetBitContext gbc; + uint8_t nal_type; + uint8_t *rbsp_buf; + uint32_t rbsp_size; + + rbsp_buf = nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size); + if (!rbsp_buf) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = init_get_bits8(&gbc, rbsp_buf, rbsp_size); + if (ret < 0) + goto end; + + nal_unit_parse_header(&gbc, &nal_type); + + /* + * Note: only 'declarative' SEI messages are allowed in + * hvcC. Perhaps the SEI playload type should be checked + * and non-declarative SEI messages discarded? + */ + switch (nal_type) { + case NAL_VPS: + case NAL_SPS: + case NAL_PPS: + case NAL_SEI_PREFIX: + case NAL_SEI_SUFFIX: + ret = hvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, + ps_array_completeness, hvcc); + if (ret < 0) + goto end; + else if (nal_type == NAL_VPS) + ret = hvcc_parse_vps(&gbc, hvcc); + else if (nal_type == NAL_SPS) + ret = hvcc_parse_sps(&gbc, hvcc); + else if (nal_type == NAL_PPS) + ret = hvcc_parse_pps(&gbc, hvcc); + if (ret < 0) + goto end; + break; + default: + ret = AVERROR_INVALIDDATA; + goto end; + } + +end: + av_free(rbsp_buf); + return ret; +} + +static void hvcc_init(HEVCDecoderConfigurationRecord *hvcc) +{ + memset(hvcc, 0, sizeof(HEVCDecoderConfigurationRecord)); + hvcc->configurationVersion = 1; + hvcc->lengthSizeMinusOne = 3; // 4 bytes + + /* + * The following fields have all their valid bits set by default, + * the ProfileTierLevel parsing code will unset them when needed. + */ + hvcc->general_profile_compatibility_flags = 0xffffffff; + hvcc->general_constraint_indicator_flags = 0xffffffffffff; + + /* + * Initialize this field with an invalid value which can be used to detect + * whether we didn't see any VUI (in wich case it should be reset to zero). + */ + hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1; +} + +static void hvcc_close(HEVCDecoderConfigurationRecord *hvcc) +{ + uint8_t i; + + for (i = 0; i < hvcc->numOfArrays; i++) { + hvcc->array[i].numNalus = 0; + av_freep(&hvcc->array[i].nalUnit); + av_freep(&hvcc->array[i].nalUnitLength); + } + + hvcc->numOfArrays = 0; + av_freep(&hvcc->array); +} + +static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) +{ + uint8_t i; + uint16_t j, vps_count = 0, sps_count = 0, pps_count = 0; + + /* + * We only support writing HEVCDecoderConfigurationRecord version 1. + */ + hvcc->configurationVersion = 1; + + /* + * If min_spatial_segmentation_idc is invalid, reset to 0 (unspecified). + */ + if (hvcc->min_spatial_segmentation_idc > MAX_SPATIAL_SEGMENTATION) + hvcc->min_spatial_segmentation_idc = 0; + + /* + * parallelismType indicates the type of parallelism that is used to meet + * the restrictions imposed by min_spatial_segmentation_idc when the value + * of min_spatial_segmentation_idc is greater than 0. + */ + if (!hvcc->min_spatial_segmentation_idc) + hvcc->parallelismType = 0; + + /* + * It's unclear how to properly compute these fields, so + * let's always set them to values meaning 'unspecified'. + */ + hvcc->avgFrameRate = 0; + hvcc->constantFrameRate = 0; + + av_dlog(NULL, "configurationVersion: %"PRIu8"\n", + hvcc->configurationVersion); + av_dlog(NULL, "general_profile_space: %"PRIu8"\n", + hvcc->general_profile_space); + av_dlog(NULL, "general_tier_flag: %"PRIu8"\n", + hvcc->general_tier_flag); + av_dlog(NULL, "general_profile_idc: %"PRIu8"\n", + hvcc->general_profile_idc); + av_dlog(NULL, "general_profile_compatibility_flags: 0x%08"PRIx32"\n", + hvcc->general_profile_compatibility_flags); + av_dlog(NULL, "general_constraint_indicator_flags: 0x%012"PRIx64"\n", + hvcc->general_constraint_indicator_flags); + av_dlog(NULL, "general_level_idc: %"PRIu8"\n", + hvcc->general_level_idc); + av_dlog(NULL, "min_spatial_segmentation_idc: %"PRIu16"\n", + hvcc->min_spatial_segmentation_idc); + av_dlog(NULL, "parallelismType: %"PRIu8"\n", + hvcc->parallelismType); + av_dlog(NULL, "chromaFormat: %"PRIu8"\n", + hvcc->chromaFormat); + av_dlog(NULL, "bitDepthLumaMinus8: %"PRIu8"\n", + hvcc->bitDepthLumaMinus8); + av_dlog(NULL, "bitDepthChromaMinus8: %"PRIu8"\n", + hvcc->bitDepthChromaMinus8); + av_dlog(NULL, "avgFrameRate: %"PRIu16"\n", + hvcc->avgFrameRate); + av_dlog(NULL, "constantFrameRate: %"PRIu8"\n", + hvcc->constantFrameRate); + av_dlog(NULL, "numTemporalLayers: %"PRIu8"\n", + hvcc->numTemporalLayers); + av_dlog(NULL, "temporalIdNested: %"PRIu8"\n", + hvcc->temporalIdNested); + av_dlog(NULL, "lengthSizeMinusOne: %"PRIu8"\n", + hvcc->lengthSizeMinusOne); + av_dlog(NULL, "numOfArrays: %"PRIu8"\n", + hvcc->numOfArrays); + for (i = 0; i < hvcc->numOfArrays; i++) { + av_dlog(NULL, "array_completeness[%"PRIu8"]: %"PRIu8"\n", + i, hvcc->array[i].array_completeness); + av_dlog(NULL, "NAL_unit_type[%"PRIu8"]: %"PRIu8"\n", + i, hvcc->array[i].NAL_unit_type); + av_dlog(NULL, "numNalus[%"PRIu8"]: %"PRIu16"\n", + i, hvcc->array[i].numNalus); + for (j = 0; j < hvcc->array[i].numNalus; j++) + av_dlog(NULL, + "nalUnitLength[%"PRIu8"][%"PRIu16"]: %"PRIu16"\n", + i, j, hvcc->array[i].nalUnitLength[j]); + } + + /* + * We need at least one of each: VPS, SPS and PPS. + */ + for (i = 0; i < hvcc->numOfArrays; i++) + switch (hvcc->array[i].NAL_unit_type) { + case NAL_VPS: + vps_count += hvcc->array[i].numNalus; + break; + case NAL_SPS: + sps_count += hvcc->array[i].numNalus; + break; + case NAL_PPS: + pps_count += hvcc->array[i].numNalus; + break; + default: + break; + } + if (!vps_count || vps_count > MAX_VPS_COUNT || + !sps_count || sps_count > MAX_SPS_COUNT || + !pps_count || pps_count > MAX_PPS_COUNT) + return AVERROR_INVALIDDATA; + + /* unsigned int(8) configurationVersion = 1; */ + avio_w8(pb, hvcc->configurationVersion); + + /* + * unsigned int(2) general_profile_space; + * unsigned int(1) general_tier_flag; + * unsigned int(5) general_profile_idc; + */ + avio_w8(pb, hvcc->general_profile_space << 6 | + hvcc->general_tier_flag << 5 | + hvcc->general_profile_idc); + + /* unsigned int(32) general_profile_compatibility_flags; */ + avio_wb32(pb, hvcc->general_profile_compatibility_flags); + + /* unsigned int(48) general_constraint_indicator_flags; */ + avio_wb32(pb, hvcc->general_constraint_indicator_flags >> 16); + avio_wb16(pb, hvcc->general_constraint_indicator_flags); + + /* unsigned int(8) general_level_idc; */ + avio_w8(pb, hvcc->general_level_idc); + + /* + * bit(4) reserved = ‘1111’b; + * unsigned int(12) min_spatial_segmentation_idc; + */ + avio_wb16(pb, hvcc->min_spatial_segmentation_idc | 0xf000); + + /* + * bit(6) reserved = ‘111111’b; + * unsigned int(2) parallelismType; + */ + avio_w8(pb, hvcc->parallelismType | 0xfc); + + /* + * bit(6) reserved = ‘111111’b; + * unsigned int(2) chromaFormat; + */ + avio_w8(pb, hvcc->chromaFormat | 0xfc); + + /* + * bit(5) reserved = ‘11111’b; + * unsigned int(3) bitDepthLumaMinus8; + */ + avio_w8(pb, hvcc->bitDepthLumaMinus8 | 0xf8); + + /* + * bit(5) reserved = ‘11111’b; + * unsigned int(3) bitDepthChromaMinus8; + */ + avio_w8(pb, hvcc->bitDepthChromaMinus8 | 0xf8); + + /* bit(16) avgFrameRate; */ + avio_wb16(pb, hvcc->avgFrameRate); + + /* + * bit(2) constantFrameRate; + * bit(3) numTemporalLayers; + * bit(1) temporalIdNested; + * unsigned int(2) lengthSizeMinusOne; + */ + avio_w8(pb, hvcc->constantFrameRate << 6 | + hvcc->numTemporalLayers << 3 | + hvcc->temporalIdNested << 2 | + hvcc->lengthSizeMinusOne); + + /* unsigned int(8) numOfArrays; */ + avio_w8(pb, hvcc->numOfArrays); + + for (i = 0; i < hvcc->numOfArrays; i++) { + /* + * bit(1) array_completeness; + * unsigned int(1) reserved = 0; + * unsigned int(6) NAL_unit_type; + */ + avio_w8(pb, hvcc->array[i].array_completeness << 7 | + hvcc->array[i].NAL_unit_type & 0x3f); + + /* unsigned int(16) numNalus; */ + avio_wb16(pb, hvcc->array[i].numNalus); + + for (j = 0; j < hvcc->array[i].numNalus; j++) { + /* unsigned int(16) nalUnitLength; */ + avio_wb16(pb, hvcc->array[i].nalUnitLength[j]); + + /* bit(8*nalUnitLength) nalUnit; */ + avio_write(pb, hvcc->array[i].nalUnit[j], + hvcc->array[i].nalUnitLength[j]); + } + } + + return 0; +} + +int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, + int size, int filter_ps, int *ps_count) +{ + int num_ps = 0, ret = 0; + uint8_t *buf, *end, *start = NULL; + + if (!filter_ps) { + ret = ff_avc_parse_nal_units(pb, buf_in, size); + goto end; + } + + ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size); + if (ret < 0) + goto end; + + ret = 0; + buf = start; + end = start + size; + + while (end - buf > 4) { + uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); + uint8_t type = (buf[4] >> 1) & 0x3f; + + buf += 4; + + switch (type) { + case NAL_VPS: + case NAL_SPS: + case NAL_PPS: + num_ps++; + break; + default: + ret += 4 + len; + avio_wb32(pb, len); + avio_write(pb, buf, len); + break; + } + + buf += len; + } + +end: + av_free(start); + if (ps_count) + *ps_count = num_ps; + return ret; +} + +int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, + int *size, int filter_ps, int *ps_count) +{ + AVIOContext *pb; + int ret; + + ret = avio_open_dyn_buf(&pb); + if (ret < 0) + return ret; + + ret = ff_hevc_annexb2mp4(pb, buf_in, *size, filter_ps, ps_count); + *size = avio_close_dyn_buf(pb, buf_out); + + return ret; +} + +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); + + if (size < 6) { + /* We can't write a valid hvcC from the provided data */ + ret = AVERROR_INVALIDDATA; + goto end; + } else if (*data == 1) { + /* Data is already hvcC-formatted */ + avio_write(pb, data, size); + goto end; + } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) { + /* Not a valid Annex B start code prefix */ + ret = AVERROR_INVALIDDATA; + goto end; + } + + ret = ff_avc_parse_nal_units_buf(data, &start, &size); + if (ret < 0) + goto end; + + buf = start; + end = start + size; + + while (end - buf > 4) { + uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); + uint8_t type = (buf[4] >> 1) & 0x3f; + + buf += 4; + + switch (type) { + case NAL_VPS: + case NAL_SPS: + case NAL_PPS: + case NAL_SEI_PREFIX: + case NAL_SEI_SUFFIX: + ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc); + if (ret < 0) + goto end; + break; + default: + break; + } + + buf += len; + } + + ret = hvcc_write(pb, &hvcc); + +end: + hvcc_close(&hvcc); + av_free(start); + return ret; +} diff --git a/chromium/third_party/ffmpeg/libavformat/hevc.h b/chromium/third_party/ffmpeg/libavformat/hevc.h new file mode 100644 index 00000000000..796eaf40b16 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/hevc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Tim Walker <tdskywalker@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 + */ + +/** + * @file + * internal header for HEVC (de)muxer utilities + */ + +#ifndef AVFORMAT_HEVC_H +#define AVFORMAT_HEVC_H + +#include <stdint.h> +#include "avio.h" + +/** + * Writes Annex B formatted HEVC NAL units to the provided AVIOContext. + * + * The NAL units are converted to an MP4-compatible format (start code prefixes + * are replaced by 4-byte size fields, as per ISO/IEC 14496-15). + * + * If filter_ps is non-zero, any HEVC parameter sets found in the input will be + * discarded, and *ps_count will be set to the number of discarded PS NAL units. + * + * @param pb address of the AVIOContext where the data shall be written + * @param buf_in address of the buffer holding the input data + * @param size size (in bytes) of the input buffer + * @param filter_ps whether to write parameter set NAL units to the output (0) + * or to discard them (non-zero) + * @param ps_count address of the variable where the number of discarded + * parameter set NAL units shall be written, may be NULL + * @return the amount (in bytes) of data written in case of success, a negative + * value corresponding to an AVERROR code in case of failure + */ +int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, + int size, int filter_ps, int *ps_count); + +/** + * Writes Annex B formatted HEVC NAL units to a data buffer. + * + * The NAL units are converted to an MP4-compatible format (start code prefixes + * are replaced by 4-byte size fields, as per ISO/IEC 14496-15). + * + * If filter_ps is non-zero, any HEVC parameter sets found in the input will be + * discarded, and *ps_count will be set to the number of discarded PS NAL units. + * + * On output, *size holds the size (in bytes) of the output data buffer. + * + * @param buf_in address of the buffer holding the input data + * @param size address of the variable holding the size (in bytes) of the input + * buffer (on input) and of the output buffer (on output) + * @param buf_out address of the variable holding the address of the output + * buffer + * @param filter_ps whether to write parameter set NAL units to the output (0) + * or to discard them (non-zero) + * @param ps_count address of the variable where the number of discarded + * parameter set NAL units shall be written, may be NULL + * @return the amount (in bytes) of data written in case of success, a negative + * value corresponding to an AVERROR code in case of failure + */ +int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, + int *size, int filter_ps, int *ps_count); + +/** + * Writes HEVC extradata (parameter sets, declarative SEI NAL units) to the + * provided AVIOContext. + * + * If the extradata is Annex B format, it gets converted to hvcC format before + * writing. + * + * @param pb address of the AVIOContext where the hvcC shall be written + * @param data address of the buffer holding the data needed to write the hvcC + * @param size size (in bytes) of the data buffer + * @param ps_array_completeness whether all parameter sets are in the hvcC (1) + * or there may be additional parameter sets in the bitstream (0) + * @return >=0 in case of success, a negative value corresponding to an AVERROR + * code in case of failure + */ +int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, + int size, int ps_array_completeness); + +#endif /* AVFORMAT_HEVC_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/hls.c b/chromium/third_party/ffmpeg/libavformat/hls.c index 471a62dc9c4..3897723b7de 100644 --- a/chromium/third_party/ffmpeg/libavformat/hls.c +++ b/chromium/third_party/ffmpeg/libavformat/hls.c @@ -1,6 +1,7 @@ /* * Apple HTTP Live Streaming demuxer * Copyright (c) 2010 Martin Storsjo + * Copyright (c) 2013 Anssi Hannula * * This file is part of FFmpeg. * @@ -26,6 +27,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" @@ -35,9 +37,16 @@ #include "internal.h" #include "avio_internal.h" #include "url.h" +#include "id3v2.h" #define INITIAL_BUFFER_SIZE 32768 +#define MAX_FIELD_LEN 64 +#define MAX_CHARACTERISTICS_LEN 512 + +#define MPEG_TIME_BASE 90000 +#define MPEG_TIME_BASE_Q (AVRational){1, MPEG_TIME_BASE} + /* * An apple http stream consists of a playlist with media segment files, * played sequentially. There may be several playlists with the same @@ -57,19 +66,28 @@ enum KeyType { struct segment { int64_t duration; - char url[MAX_URL_SIZE]; - char key[MAX_URL_SIZE]; + int64_t url_offset; + int64_t size; + char *url; + char *key; enum KeyType key_type; uint8_t iv[16]; }; +struct rendition; + +enum PlaylistType { + PLS_TYPE_UNSPECIFIED, + PLS_TYPE_EVENT, + PLS_TYPE_VOD +}; + /* - * Each variant has its own demuxer. If it currently is active, + * Each playlist has its own demuxer. If it currently is active, * it has an open AVIOContext too, and potentially an AVPacket * containing the next packet from this stream. */ -struct variant { - int bandwidth; +struct playlist { char url[MAX_URL_SIZE]; AVIOContext pb; uint8_t* read_buffer; @@ -81,27 +99,82 @@ struct variant { int stream_offset; int finished; + enum PlaylistType type; int64_t target_duration; int start_seq_no; int n_segments; struct segment **segments; int needed, cur_needed; int cur_seq_no; + int64_t cur_seg_offset; int64_t last_load_time; char key_url[MAX_URL_SIZE]; uint8_t key[16]; + + /* ID3 timestamp handling (elementary audio streams have ID3 timestamps + * (and possibly other ID3 tags) in the beginning of each segment) */ + int is_id3_timestamped; /* -1: not yet known */ + int64_t id3_mpegts_timestamp; /* in mpegts tb */ + int64_t id3_offset; /* in stream original tb */ + uint8_t* id3_buf; /* temp buffer for id3 parsing */ + unsigned int id3_buf_size; + AVDictionary *id3_initial; /* data from first id3 tag */ + int id3_found; /* ID3 tag found at some point */ + int id3_changed; /* ID3 tag data has changed at some point */ + ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */ + + int64_t seek_timestamp; + int seek_flags; + int seek_stream_index; /* into subdemuxer stream array */ + + /* Renditions associated with this playlist, if any. + * Alternative rendition playlists have a single rendition associated + * with them, and variant main Media Playlists may have + * multiple (playlist-less) renditions associated with them. */ + int n_renditions; + struct rendition **renditions; +}; + +/* + * Renditions are e.g. alternative subtitle or audio streams. + * The rendition may either be an external playlist or it may be + * contained in the main Media Playlist of the variant (in which case + * playlist is NULL). + */ +struct rendition { + enum AVMediaType type; + struct playlist *playlist; + char group_id[MAX_FIELD_LEN]; + char language[MAX_FIELD_LEN]; + char name[MAX_FIELD_LEN]; + int disposition; +}; + +struct variant { + int bandwidth; + + /* every variant contains at least the main Media Playlist in index 0 */ + int n_playlists; + struct playlist **playlists; + + char audio_group[MAX_FIELD_LEN]; + char video_group[MAX_FIELD_LEN]; + char subtitles_group[MAX_FIELD_LEN]; }; typedef struct HLSContext { int n_variants; struct variant **variants; + int n_playlists; + struct playlist **playlists; + int n_renditions; + struct rendition **renditions; + int cur_seq_no; - int end_of_segment; int first_packet; int64_t first_timestamp; - int64_t seek_timestamp; - int seek_flags; + int64_t cur_timestamp; AVIOInterruptCB *interrupt_callback; char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context @@ -116,13 +189,42 @@ static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) return len; } -static void free_segment_list(struct variant *var) +static void free_segment_list(struct playlist *pls) +{ + int i; + for (i = 0; i < pls->n_segments; i++) { + av_free(pls->segments[i]->key); + av_free(pls->segments[i]->url); + av_free(pls->segments[i]); + } + av_freep(&pls->segments); + pls->n_segments = 0; +} + +static void free_playlist_list(HLSContext *c) { int i; - for (i = 0; i < var->n_segments; i++) - av_free(var->segments[i]); - av_freep(&var->segments); - var->n_segments = 0; + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + free_segment_list(pls); + av_freep(&pls->renditions); + av_freep(&pls->id3_buf); + av_dict_free(&pls->id3_initial); + ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); + av_free_packet(&pls->pkt); + av_free(pls->pb.buffer); + if (pls->input) + ffurl_close(pls->input); + if (pls->ctx) { + pls->ctx->pb = NULL; + avformat_close_input(&pls->ctx); + } + av_free(pls); + } + av_freep(&c->playlists); + av_freep(&c->cookies); + av_freep(&c->user_agent); + c->n_playlists = 0; } static void free_variant_list(HLSContext *c) @@ -130,23 +232,22 @@ static void free_variant_list(HLSContext *c) int i; for (i = 0; i < c->n_variants; i++) { struct variant *var = c->variants[i]; - free_segment_list(var); - av_free_packet(&var->pkt); - av_free(var->pb.buffer); - if (var->input) - ffurl_close(var->input); - if (var->ctx) { - var->ctx->pb = NULL; - avformat_close_input(&var->ctx); - } + av_freep(&var->playlists); av_free(var); } av_freep(&c->variants); - av_freep(&c->cookies); - av_freep(&c->user_agent); c->n_variants = 0; } +static void free_rendition_list(HLSContext *c) +{ + int i; + for (i = 0; i < c->n_renditions; i++) + av_free(c->renditions[i]); + av_freep(&c->renditions); + c->n_renditions = 0; +} + /* * Used to reset a statically allocated AVPacket to a clean slate, * containing no data. @@ -157,29 +258,72 @@ static void reset_packet(AVPacket *pkt) pkt->data = NULL; } -static struct variant *new_variant(HLSContext *c, int bandwidth, - const char *url, const char *base) +static struct playlist *new_playlist(HLSContext *c, const char *url, + const char *base) { - struct variant *var = av_mallocz(sizeof(struct variant)); - if (!var) + struct playlist *pls = av_mallocz(sizeof(struct playlist)); + if (!pls) return NULL; - reset_packet(&var->pkt); - var->bandwidth = bandwidth; - ff_make_absolute_url(var->url, sizeof(var->url), base, url); - dynarray_add(&c->variants, &c->n_variants, var); - return var; + reset_packet(&pls->pkt); + ff_make_absolute_url(pls->url, sizeof(pls->url), base, url); + pls->seek_timestamp = AV_NOPTS_VALUE; + + pls->is_id3_timestamped = -1; + pls->id3_mpegts_timestamp = AV_NOPTS_VALUE; + + dynarray_add(&c->playlists, &c->n_playlists, pls); + return pls; } struct variant_info { char bandwidth[20]; + /* variant group ids: */ + char audio[MAX_FIELD_LEN]; + char video[MAX_FIELD_LEN]; + char subtitles[MAX_FIELD_LEN]; }; +static struct variant *new_variant(HLSContext *c, struct variant_info *info, + const char *url, const char *base) +{ + struct variant *var; + struct playlist *pls; + + pls = new_playlist(c, url, base); + if (!pls) + return NULL; + + var = av_mallocz(sizeof(struct variant)); + if (!var) + return NULL; + + if (info) { + var->bandwidth = atoi(info->bandwidth); + strcpy(var->audio_group, info->audio); + strcpy(var->video_group, info->video); + strcpy(var->subtitles_group, info->subtitles); + } + + dynarray_add(&c->variants, &c->n_variants, var); + dynarray_add(&var->playlists, &var->n_playlists, pls); + return var; +} + static void handle_variant_args(struct variant_info *info, const char *key, int key_len, char **dest, int *dest_len) { if (!strncmp(key, "BANDWIDTH=", key_len)) { *dest = info->bandwidth; *dest_len = sizeof(info->bandwidth); + } else if (!strncmp(key, "AUDIO=", key_len)) { + *dest = info->audio; + *dest_len = sizeof(info->audio); + } else if (!strncmp(key, "VIDEO=", key_len)) { + *dest = info->video; + *dest_len = sizeof(info->video); + } else if (!strncmp(key, "SUBTITLES=", key_len)) { + *dest = info->subtitles; + *dest_len = sizeof(info->subtitles); } } @@ -204,10 +348,153 @@ static void handle_key_args(struct key_info *info, const char *key, } } +struct rendition_info { + char type[16]; + char uri[MAX_URL_SIZE]; + char group_id[MAX_FIELD_LEN]; + char language[MAX_FIELD_LEN]; + char assoc_language[MAX_FIELD_LEN]; + char name[MAX_FIELD_LEN]; + char defaultr[4]; + char forced[4]; + char characteristics[MAX_CHARACTERISTICS_LEN]; +}; + +static struct rendition *new_rendition(HLSContext *c, struct rendition_info *info, + const char *url_base) +{ + struct rendition *rend; + enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; + char *characteristic; + char *chr_ptr; + char *saveptr; + + if (!strcmp(info->type, "AUDIO")) + type = AVMEDIA_TYPE_AUDIO; + else if (!strcmp(info->type, "VIDEO")) + type = AVMEDIA_TYPE_VIDEO; + else if (!strcmp(info->type, "SUBTITLES")) + type = AVMEDIA_TYPE_SUBTITLE; + else if (!strcmp(info->type, "CLOSED-CAPTIONS")) + /* CLOSED-CAPTIONS is ignored since we do not support CEA-608 CC in + * AVC SEI RBSP anyway */ + return NULL; + + if (type == AVMEDIA_TYPE_UNKNOWN) + return NULL; + + /* URI is mandatory for subtitles as per spec */ + if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0]) + return NULL; + + /* TODO: handle subtitles (each segment has to parsed separately) */ + if (type == AVMEDIA_TYPE_SUBTITLE) + return NULL; + + rend = av_mallocz(sizeof(struct rendition)); + if (!rend) + return NULL; + + dynarray_add(&c->renditions, &c->n_renditions, rend); + + rend->type = type; + strcpy(rend->group_id, info->group_id); + strcpy(rend->language, info->language); + strcpy(rend->name, info->name); + + /* add the playlist if this is an external rendition */ + if (info->uri[0]) { + rend->playlist = new_playlist(c, info->uri, url_base); + if (rend->playlist) + dynarray_add(&rend->playlist->renditions, + &rend->playlist->n_renditions, rend); + } + + if (info->assoc_language[0]) { + int langlen = strlen(rend->language); + if (langlen < sizeof(rend->language) - 3) { + rend->language[langlen] = ','; + strncpy(rend->language + langlen + 1, info->assoc_language, + sizeof(rend->language) - langlen - 2); + } + } + + if (!strcmp(info->defaultr, "YES")) + rend->disposition |= AV_DISPOSITION_DEFAULT; + if (!strcmp(info->forced, "YES")) + rend->disposition |= AV_DISPOSITION_FORCED; + + chr_ptr = info->characteristics; + while ((characteristic = av_strtok(chr_ptr, ",", &saveptr))) { + if (!strcmp(characteristic, "public.accessibility.describes-music-and-sound")) + rend->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; + else if (!strcmp(characteristic, "public.accessibility.describes-video")) + rend->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + + chr_ptr = NULL; + } + + return rend; +} + +static void handle_rendition_args(struct rendition_info *info, const char *key, + int key_len, char **dest, int *dest_len) +{ + if (!strncmp(key, "TYPE=", key_len)) { + *dest = info->type; + *dest_len = sizeof(info->type); + } else if (!strncmp(key, "URI=", key_len)) { + *dest = info->uri; + *dest_len = sizeof(info->uri); + } else if (!strncmp(key, "GROUP-ID=", key_len)) { + *dest = info->group_id; + *dest_len = sizeof(info->group_id); + } else if (!strncmp(key, "LANGUAGE=", key_len)) { + *dest = info->language; + *dest_len = sizeof(info->language); + } else if (!strncmp(key, "ASSOC-LANGUAGE=", key_len)) { + *dest = info->assoc_language; + *dest_len = sizeof(info->assoc_language); + } else if (!strncmp(key, "NAME=", key_len)) { + *dest = info->name; + *dest_len = sizeof(info->name); + } else if (!strncmp(key, "DEFAULT=", key_len)) { + *dest = info->defaultr; + *dest_len = sizeof(info->defaultr); + } else if (!strncmp(key, "FORCED=", key_len)) { + *dest = info->forced; + *dest_len = sizeof(info->forced); + } else if (!strncmp(key, "CHARACTERISTICS=", key_len)) { + *dest = info->characteristics; + *dest_len = sizeof(info->characteristics); + } + /* + * ignored: + * - AUTOSELECT: client may autoselect based on e.g. system language + * - INSTREAM-ID: EIA-608 closed caption number ("CC1".."CC4") + */ +} + +/* used by parse_playlist to allocate a new variant+playlist when the + * playlist is detected to be a Media Playlist (not Master Playlist) + * and we have no parent Master Playlist (parsing of which would have + * allocated the variant and playlist already) */ +static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url) +{ + if (*pls) + return 0; + if (!new_variant(c, NULL, url, NULL)) + return AVERROR(ENOMEM); + *pls = c->playlists[c->n_playlists - 1]; + return 0; +} + +/* pls = NULL => Master Playlist or parentless Media Playlist + * pls = !NULL => parented Media Playlist, playlist+variant allocated */ static int parse_playlist(HLSContext *c, const char *url, - struct variant *var, AVIOContext *in) + struct playlist *pls, AVIOContext *in) { - int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + int ret = 0, is_segment = 0, is_variant = 0; int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; @@ -216,7 +503,11 @@ static int parse_playlist(HLSContext *c, const char *url, char line[MAX_URL_SIZE]; const char *ptr; int close_in = 0; + int64_t seg_offset = 0; + int64_t seg_size = -1; uint8_t *new_url = NULL; + struct variant_info variant_info; + char tmp_str[MAX_URL_SIZE]; if (!in) { AVDictionary *opts = NULL; @@ -245,18 +536,18 @@ static int parse_playlist(HLSContext *c, const char *url, goto fail; } - if (var) { - free_segment_list(var); - var->finished = 0; + if (pls) { + free_segment_list(pls); + pls->finished = 0; + pls->type = PLS_TYPE_UNSPECIFIED; } while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { - struct variant_info info = {{0}}; is_variant = 1; + memset(&variant_info, 0, sizeof(variant_info)); ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, - &info); - bandwidth = atoi(info.bandwidth); + &variant_info); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, @@ -270,49 +561,58 @@ static int parse_playlist(HLSContext *c, const char *url, has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); + } else if (av_strstart(line, "#EXT-X-MEDIA:", &ptr)) { + struct rendition_info info = {{0}}; + ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_rendition_args, + &info); + new_rendition(c, &info, url); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { - if (!var) { - var = new_variant(c, 0, url, NULL); - if (!var) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - var->target_duration = atoi(ptr) * AV_TIME_BASE; + ret = ensure_playlist(c, &pls, url); + if (ret < 0) + goto fail; + pls->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { - if (!var) { - var = new_variant(c, 0, url, NULL); - if (!var) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - var->start_seq_no = atoi(ptr); + ret = ensure_playlist(c, &pls, url); + if (ret < 0) + goto fail; + pls->start_seq_no = atoi(ptr); + } else if (av_strstart(line, "#EXT-X-PLAYLIST-TYPE:", &ptr)) { + ret = ensure_playlist(c, &pls, url); + if (ret < 0) + goto fail; + if (!strcmp(ptr, "EVENT")) + pls->type = PLS_TYPE_EVENT; + else if (!strcmp(ptr, "VOD")) + pls->type = PLS_TYPE_VOD; } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { - if (var) - var->finished = 1; + if (pls) + pls->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; + } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) { + seg_size = atoi(ptr); + ptr = strchr(ptr, '@'); + if (ptr) + seg_offset = atoi(ptr+1); } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { - if (!new_variant(c, bandwidth, line, url)) { + if (!new_variant(c, &variant_info, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; - bandwidth = 0; } if (is_segment) { struct segment *seg; - if (!var) { - var = new_variant(c, 0, url, NULL); - if (!var) { + if (!pls) { + if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } + pls = c->playlists[c->n_playlists - 1]; } seg = av_malloc(sizeof(struct segment)); if (!seg) { @@ -324,19 +624,49 @@ static int parse_playlist(HLSContext *c, const char *url, if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { - int seq = var->start_seq_no + var->n_segments; + int seq = pls->start_seq_no + pls->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } - ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); - ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); - dynarray_add(&var->segments, &var->n_segments, seg); + + if (key_type != KEY_NONE) { + ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); + seg->key = av_strdup(tmp_str); + if (!seg->key) { + av_free(seg); + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + seg->key = NULL; + } + + ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line); + seg->url = av_strdup(tmp_str); + if (!seg->url) { + av_free(seg->key); + av_free(seg); + ret = AVERROR(ENOMEM); + goto fail; + } + + dynarray_add(&pls->segments, &pls->n_segments, seg); is_segment = 0; + + seg->size = seg_size; + if (seg_size >= 0) { + seg->url_offset = seg_offset; + seg_offset += seg_size; + seg_size = -1; + } else { + seg->url_offset = 0; + seg_offset = 0; + } } } } - if (var) - var->last_load_time = av_gettime(); + if (pls) + pls->last_load_time = av_gettime(); fail: av_free(new_url); @@ -345,11 +675,237 @@ fail: return ret; } -static int open_input(HLSContext *c, struct variant *var) +enum ReadFromURLMode { + READ_NORMAL, + READ_COMPLETE, +}; + +/* read from URLContext, limiting read to current segment */ +static int read_from_url(struct playlist *pls, uint8_t *buf, int buf_size, + enum ReadFromURLMode mode) +{ + int ret; + struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; + + /* limit read if the segment was only a part of a file */ + if (seg->size >= 0) + buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset); + + if (mode == READ_COMPLETE) + ret = ffurl_read_complete(pls->input, buf, buf_size); + else + ret = ffurl_read(pls->input, buf, buf_size); + + if (ret > 0) + pls->cur_seg_offset += ret; + + return ret; +} + +/* Parse the raw ID3 data and pass contents to caller */ +static void parse_id3(AVFormatContext *s, AVIOContext *pb, + AVDictionary **metadata, int64_t *dts, + ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta **extra_meta) +{ + static const char id3_priv_owner_ts[] = "com.apple.streaming.transportStreamTimestamp"; + ID3v2ExtraMeta *meta; + + 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; + if (priv->datasize == 8 && !strcmp(priv->owner, id3_priv_owner_ts)) { + /* 33-bit MPEG timestamp */ + int64_t ts = AV_RB64(priv->data); + av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp %"PRId64"\n", ts); + if ((ts & ~((1ULL << 33) - 1)) == 0) + *dts = ts; + else + av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts); + } + } else if (!strcmp(meta->tag, "APIC") && apic) + *apic = meta->data; + } +} + +/* Check if the ID3 metadata contents have changed */ +static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata, + ID3v2ExtraMetaAPIC *apic) +{ + AVDictionaryEntry *entry = NULL; + AVDictionaryEntry *oldentry; + /* check that no keys have changed values */ + while ((entry = av_dict_get(metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) { + oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, AV_DICT_MATCH_CASE); + if (!oldentry || strcmp(oldentry->value, entry->value) != 0) + return 1; + } + + /* check if apic appeared */ + if (apic && (pls->ctx->nb_streams != 2 || !pls->ctx->streams[1]->attached_pic.data)) + return 1; + + if (apic) { + int size = pls->ctx->streams[1]->attached_pic.size; + if (size != apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE) + return 1; + + if (memcmp(apic->buf->data, pls->ctx->streams[1]->attached_pic.data, size) != 0) + return 1; + } + + return 0; +} + +/* Parse ID3 data and handle the found data */ +static void handle_id3(AVIOContext *pb, struct playlist *pls) +{ + AVDictionary *metadata = NULL; + ID3v2ExtraMetaAPIC *apic = NULL; + ID3v2ExtraMeta *extra_meta = NULL; + int64_t timestamp = AV_NOPTS_VALUE; + + parse_id3(pls->ctx, pb, &metadata, ×tamp, &apic, &extra_meta); + + if (timestamp != AV_NOPTS_VALUE) { + pls->id3_mpegts_timestamp = timestamp; + pls->id3_offset = 0; + } + + if (!pls->id3_found) { + /* initial ID3 tags */ + av_assert0(!pls->id3_deferred_extra); + pls->id3_found = 1; + + /* get picture attachment and set text metadata */ + if (pls->ctx->nb_streams) + ff_id3v2_parse_apic(pls->ctx, &extra_meta); + else + /* demuxer not yet opened, defer picture attachment */ + pls->id3_deferred_extra = extra_meta; + + av_dict_copy(&pls->ctx->metadata, metadata, 0); + pls->id3_initial = metadata; + + } else { + if (!pls->id3_changed && id3_has_changed_values(pls, metadata, apic)) { + avpriv_report_missing_feature(pls->ctx, "Changing ID3 metadata in HLS audio elementary stream"); + pls->id3_changed = 1; + } + av_dict_free(&metadata); + } + + if (!pls->id3_deferred_extra) + ff_id3v2_free_extra_meta(&extra_meta); +} + +/* Intercept and handle ID3 tags between URLContext and AVIOContext */ +static void intercept_id3(struct playlist *pls, uint8_t *buf, + int buf_size, int *len) +{ + /* intercept id3 tags, we do not want to pass them to the raw + * demuxer on all segment switches */ + int bytes; + int id3_buf_pos = 0; + int fill_buf = 0; + + /* gather all the id3 tags */ + while (1) { + /* see if we can retrieve enough data for ID3 header */ + if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) { + bytes = read_from_url(pls, buf + *len, ID3v2_HEADER_SIZE - *len, READ_COMPLETE); + if (bytes > 0) { + + if (bytes == ID3v2_HEADER_SIZE - *len) + /* no EOF yet, so fill the caller buffer again after + * we have stripped the ID3 tags */ + fill_buf = 1; + + *len += bytes; + + } else if (*len <= 0) { + /* error/EOF */ + *len = bytes; + fill_buf = 0; + } + } + + if (*len < ID3v2_HEADER_SIZE) + break; + + if (ff_id3v2_match(buf, ID3v2_DEFAULT_MAGIC)) { + struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; + int64_t maxsize = seg->size >= 0 ? seg->size : 1024*1024; + int taglen = ff_id3v2_tag_len(buf); + int tag_got_bytes = FFMIN(taglen, *len); + int remaining = taglen - tag_got_bytes; + + if (taglen > maxsize) { + av_log(pls->ctx, AV_LOG_ERROR, "Too large HLS ID3 tag (%d > %"PRId64" bytes)\n", + taglen, maxsize); + break; + } + + /* + * Copy the id3 tag to our temporary id3 buffer. + * We could read a small id3 tag directly without memcpy, but + * we would still need to copy the large tags, and handling + * both of those cases together with the possibility for multiple + * tags would make the handling a bit complex. + */ + pls->id3_buf = av_fast_realloc(pls->id3_buf, &pls->id3_buf_size, id3_buf_pos + taglen); + if (!pls->id3_buf) + break; + memcpy(pls->id3_buf + id3_buf_pos, buf, tag_got_bytes); + id3_buf_pos += tag_got_bytes; + + /* strip the intercepted bytes */ + *len -= tag_got_bytes; + memmove(buf, buf + tag_got_bytes, *len); + av_log(pls->ctx, AV_LOG_DEBUG, "Stripped %d HLS ID3 bytes\n", tag_got_bytes); + + if (remaining > 0) { + /* read the rest of the tag in */ + if (read_from_url(pls, pls->id3_buf + id3_buf_pos, remaining, READ_COMPLETE) != remaining) + break; + id3_buf_pos += remaining; + av_log(pls->ctx, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining); + } + + } else { + /* no more ID3 tags */ + break; + } + } + + /* re-fill buffer for the caller unless EOF */ + if (*len >= 0 && (fill_buf || *len == 0)) { + bytes = read_from_url(pls, buf + *len, buf_size - *len, READ_NORMAL); + + /* ignore error if we already had some data */ + if (bytes >= 0) + *len += bytes; + else if (*len == 0) + *len = bytes; + } + + if (pls->id3_buf) { + /* Now parse all the ID3 tags */ + AVIOContext id3ioctx; + ffio_init_context(&id3ioctx, pls->id3_buf, id3_buf_pos, 0, NULL, NULL, NULL, NULL); + handle_id3(&id3ioctx, pls); + } + + if (pls->is_id3_timestamped == -1) + pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE); +} + +static int open_input(HLSContext *c, struct playlist *pls) { AVDictionary *opts = NULL; + AVDictionary *opts2 = NULL; int ret; - struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; + struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); @@ -357,18 +913,37 @@ static int open_input(HLSContext *c, struct variant *var) av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "seekable", "0", 0); + // Same opts for key request (ffurl_open mutilates the opts so it cannot be used twice) + av_dict_copy(&opts2, opts, 0); + + if (seg->size >= 0) { + /* try to restrict the HTTP request to the part we want + * (if this is in fact a HTTP request) */ + char offset[24] = { 0 }; + char end_offset[24] = { 0 }; + snprintf(offset, sizeof(offset) - 1, "%"PRId64, + seg->url_offset); + snprintf(end_offset, sizeof(end_offset) - 1, "%"PRId64, + seg->url_offset + seg->size); + av_dict_set(&opts, "offset", offset, 0); + av_dict_set(&opts, "end_offset", end_offset, 0); + } + + av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n", + seg->url, seg->url_offset, pls->index); + if (seg->key_type == KEY_NONE) { - ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, - &var->parent->interrupt_callback, &opts); - goto cleanup; + ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ, + &pls->parent->interrupt_callback, &opts); + } else if (seg->key_type == KEY_AES_128) { char iv[33], key[33], url[MAX_URL_SIZE]; - if (strcmp(seg->key, var->key_url)) { + if (strcmp(seg->key, pls->key_url)) { URLContext *uc; if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, - &var->parent->interrupt_callback, &opts) == 0) { - if (ffurl_read_complete(uc, var->key, sizeof(var->key)) - != sizeof(var->key)) { + &pls->parent->interrupt_callback, &opts2) == 0) { + if (ffurl_read_complete(uc, pls->key, sizeof(pls->key)) + != sizeof(pls->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", seg->key); } @@ -377,26 +952,24 @@ static int open_input(HLSContext *c, struct variant *var) av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", seg->key); } - av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); + av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url)); } ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); - ff_data_to_hex(key, var->key, sizeof(var->key), 0); + ff_data_to_hex(key, pls->key, sizeof(pls->key), 0); iv[32] = key[32] = '\0'; if (strstr(seg->url, "://")) snprintf(url, sizeof(url), "crypto+%s", seg->url); else snprintf(url, sizeof(url), "crypto:%s", seg->url); - if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ, - &var->parent->interrupt_callback)) < 0) + if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ, + &pls->parent->interrupt_callback)) < 0) goto cleanup; - av_opt_set(var->input->priv_data, "key", key, 0); - av_opt_set(var->input->priv_data, "iv", iv, 0); - /* Need to repopulate options */ - av_dict_free(&opts); - av_dict_set(&opts, "seekable", "0", 0); - if ((ret = ffurl_connect(var->input, &opts)) < 0) { - ffurl_close(var->input); - var->input = NULL; + av_opt_set(pls->input->priv_data, "key", key, 0); + av_opt_set(pls->input->priv_data, "iv", iv, 0); + + if ((ret = ffurl_connect(pls->input, &opts)) < 0) { + ffurl_close(pls->input); + pls->input = NULL; goto cleanup; } ret = 0; @@ -404,30 +977,76 @@ static int open_input(HLSContext *c, struct variant *var) else ret = AVERROR(ENOSYS); + /* Seek to the requested position. If this was a HTTP request, the offset + * should already be where want it to, but this allows e.g. local testing + * without a HTTP server. */ + if (ret == 0 && seg->key_type == KEY_NONE) { + int seekret = ffurl_seek(pls->input, 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); + ret = seekret; + ffurl_close(pls->input); + pls->input = NULL; + } + } + cleanup: av_dict_free(&opts); + av_dict_free(&opts2); + pls->cur_seg_offset = 0; return ret; } +static int64_t default_reload_interval(struct playlist *pls) +{ + return pls->n_segments > 0 ? + pls->segments[pls->n_segments - 1]->duration : + pls->target_duration; +} + static int read_data(void *opaque, uint8_t *buf, int buf_size) { - struct variant *v = opaque; + struct playlist *v = opaque; HLSContext *c = v->parent->priv_data; int ret, i; + int just_opened = 0; restart: + if (!v->needed) + return AVERROR_EOF; + if (!v->input) { + int64_t reload_interval; + + /* Check that the playlist is still needed before opening a new + * segment. */ + if (v->ctx && v->ctx->nb_streams && + v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { + v->needed = 0; + for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; + i++) { + if (v->parent->streams[i]->discard < AVDISCARD_ALL) + v->needed = 1; + } + } + if (!v->needed) { + av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", + v->index); + return AVERROR_EOF; + } + /* If this is a live stream and the reload interval has elapsed since - * the last playlist reload, reload the variant playlists now. */ - int64_t reload_interval = v->n_segments > 0 ? - v->segments[v->n_segments - 1]->duration : - v->target_duration; + * the last playlist reload, reload the playlists now. */ + reload_interval = default_reload_interval(v); reload: if (!v->finished && av_gettime() - v->last_load_time >= reload_interval) { - if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) + if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) { + av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n", + v->index); return ret; + } /* If we need to reload the playlist again below (if * there's still no more segments), switch to a reload * interval of half the target duration. */ @@ -452,34 +1071,169 @@ reload: } ret = open_input(c, v); - if (ret < 0) + if (ret < 0) { + av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n", + v->index); return ret; + } + just_opened = 1; } - ret = ffurl_read(v->input, buf, buf_size); - if (ret > 0) + + ret = read_from_url(v, buf, buf_size, READ_NORMAL); + if (ret > 0) { + if (just_opened && v->is_id3_timestamped != 0) { + /* Intercept ID3 tags here, elementary audio streams are required + * to convey timestamps using them in the beginning of each segment. */ + intercept_id3(v, buf, buf_size, &ret); + } + return ret; + } ffurl_close(v->input); v->input = NULL; v->cur_seq_no++; - c->end_of_segment = 1; c->cur_seq_no = v->cur_seq_no; - if (v->ctx && v->ctx->nb_streams && - v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { - v->needed = 0; - for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; - i++) { - if (v->parent->streams[i]->discard < AVDISCARD_ALL) - v->needed = 1; + goto restart; +} + +static int playlist_in_multiple_variants(HLSContext *c, struct playlist *pls) +{ + int variant_count = 0; + int i, j; + + for (i = 0; i < c->n_variants && variant_count < 2; i++) { + struct variant *v = c->variants[i]; + + for (j = 0; j < v->n_playlists; j++) { + if (v->playlists[j] == pls) { + variant_count++; + break; + } } } - if (!v->needed) { - av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n", - v->index); - return AVERROR_EOF; + + return variant_count >= 2; +} + +static void add_renditions_to_variant(HLSContext *c, struct variant *var, + enum AVMediaType type, const char *group_id) +{ + int i; + + for (i = 0; i < c->n_renditions; i++) { + struct rendition *rend = c->renditions[i]; + + if (rend->type == type && !strcmp(rend->group_id, group_id)) { + + if (rend->playlist) + /* rendition is an external playlist + * => add the playlist to the variant */ + dynarray_add(&var->playlists, &var->n_playlists, rend->playlist); + else + /* rendition is part of the variant main Media Playlist + * => add the rendition to the main Media Playlist */ + dynarray_add(&var->playlists[0]->renditions, + &var->playlists[0]->n_renditions, + rend); + } + } +} + +static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pls, + enum AVMediaType type) +{ + int rend_idx = 0; + int i; + + for (i = 0; i < pls->ctx->nb_streams; i++) { + AVStream *st = s->streams[pls->stream_offset + i]; + + if (st->codec->codec_type != type) + continue; + + for (; rend_idx < pls->n_renditions; rend_idx++) { + struct rendition *rend = pls->renditions[rend_idx]; + + if (rend->type != type) + continue; + + if (rend->language[0]) + av_dict_set(&st->metadata, "language", rend->language, 0); + if (rend->name[0]) + av_dict_set(&st->metadata, "comment", rend->name, 0); + + st->disposition |= rend->disposition; + } + if (rend_idx >=pls->n_renditions) + break; } - goto restart; +} + +/* if timestamp was in valid range: returns 1 and sets seq_no + * if not: returns 0 and sets seq_no to closest segment */ +static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, + int64_t timestamp, int *seq_no) +{ + int i; + int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? + 0 : c->first_timestamp; + + if (timestamp < pos) { + *seq_no = pls->start_seq_no; + return 0; + } + + for (i = 0; i < pls->n_segments; i++) { + int64_t diff = pos + pls->segments[i]->duration - timestamp; + if (diff > 0) { + *seq_no = pls->start_seq_no + i; + return 1; + } + pos += pls->segments[i]->duration; + } + + *seq_no = pls->start_seq_no + pls->n_segments - 1; + + return 0; +} + +static int select_cur_seq_no(HLSContext *c, struct playlist *pls) +{ + int seq_no; + + if (!pls->finished && !c->first_packet && + av_gettime() - pls->last_load_time >= default_reload_interval(pls)) + /* reload the playlist since it was suspended */ + parse_playlist(c, pls->url, pls, NULL); + + /* If playback is already in progress (we are just selecting a new + * playlist) and this is a complete file, find the matching segment + * by counting durations. */ + if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { + find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); + return seq_no; + } + + if (!pls->finished) { + if (!c->first_packet && /* we are doing a segment selection during playback */ + c->cur_seq_no >= pls->start_seq_no && + c->cur_seq_no < pls->start_seq_no + pls->n_segments) + /* While spec 3.4.3 says that we cannot assume anything about the + * content at the same sequence number on different playlists, + * in practice this seems to work and doing it otherwise would + * require us to download a segment to inspect its timestamps. */ + return c->cur_seq_no; + + /* If this is a live stream with more than 3 segments, start at the + * third last segment. */ + if (pls->n_segments > 3) + return pls->start_seq_no + pls->n_segments - 3; + } + + /* Otherwise just start on the first segment. */ + return pls->start_seq_no; } static int hls_read_header(AVFormatContext *s) @@ -490,6 +1244,10 @@ static int hls_read_header(AVFormatContext *s) c->interrupt_callback = &s->interrupt_callback; + c->first_packet = 1; + c->first_timestamp = AV_NOPTS_VALUE; + c->cur_timestamp = AV_NOPTS_VALUE; + // if the URL context is good, read important options we must broker later if (u && u->prot->priv_data_class) { // get the previous user agent & set back to null if string size is zero @@ -519,17 +1277,17 @@ static int hls_read_header(AVFormatContext *s) ret = AVERROR_EOF; goto fail; } - /* If the playlist only contained variants, parse each individual - * variant playlist. */ - if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { - for (i = 0; i < c->n_variants; i++) { - struct variant *v = c->variants[i]; - if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) + /* If the playlist only contained playlists (Master Playlist), + * parse each individual playlist. */ + if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) { + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) goto fail; } } - if (c->variants[0]->n_segments == 0) { + if (c->variants[0]->playlists[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; @@ -537,97 +1295,140 @@ static int hls_read_header(AVFormatContext *s) /* If this isn't a live stream, calculate the total duration of the * stream. */ - if (c->variants[0]->finished) { + if (c->variants[0]->playlists[0]->finished) { int64_t duration = 0; - for (i = 0; i < c->variants[0]->n_segments; i++) - duration += c->variants[0]->segments[i]->duration; + for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++) + duration += c->variants[0]->playlists[0]->segments[i]->duration; s->duration = duration; } - /* Open the demuxer for each variant */ + /* Associate renditions with variants */ for (i = 0; i < c->n_variants; i++) { - struct variant *v = c->variants[i]; + struct variant *var = c->variants[i]; + + if (var->audio_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group); + if (var->video_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group); + if (var->subtitles_group[0]) + add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); + } + + /* Open the demuxer for each playlist */ + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; AVInputFormat *in_fmt = NULL; - char bitrate_str[20]; - AVProgram *program; - if (v->n_segments == 0) + if (pls->n_segments == 0) continue; - if (!(v->ctx = avformat_alloc_context())) { + if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } - v->index = i; - v->needed = 1; - v->parent = s; - - /* If this is a live stream with more than 3 segments, start at the - * third last segment. */ - v->cur_seq_no = v->start_seq_no; - if (!v->finished && v->n_segments > 3) - v->cur_seq_no = v->start_seq_no + v->n_segments - 3; + pls->index = i; + pls->needed = 1; + pls->parent = s; + pls->cur_seq_no = select_cur_seq_no(c, pls); - v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); - ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, + pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); + ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls, read_data, NULL, NULL); - v->pb.seekable = 0; - ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, + pls->pb.seekable = 0; + ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url, NULL, 0, 0); if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If * avformat_open_input fails below, it frees and zeros the * context, so it doesn't need any special treatment like this. */ - av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url); - avformat_free_context(v->ctx); - v->ctx = NULL; + av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", pls->segments[0]->url); + avformat_free_context(pls->ctx); + pls->ctx = NULL; goto fail; } - v->ctx->pb = &v->pb; - v->stream_offset = stream_offset; - ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); + pls->ctx->pb = &pls->pb; + pls->stream_offset = stream_offset; + ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; - v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; - ret = avformat_find_stream_info(v->ctx, NULL); + if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) { + ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra); + avformat_queue_attached_pictures(pls->ctx); + ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); + pls->id3_deferred_extra = NULL; + } + + pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; + ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; - snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); - program = av_new_program(s, i); - if (!program) - goto fail; - av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); + if (pls->is_id3_timestamped == -1) + av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n"); - /* Create new AVStreams for each stream in this variant */ - for (j = 0; j < v->ctx->nb_streams; j++) { + /* Create new AVStreams for each stream in this playlist */ + for (j = 0; j < pls->ctx->nb_streams; j++) { AVStream *st = avformat_new_stream(s, NULL); - AVStream *ist = v->ctx->streams[j]; + AVStream *ist = pls->ctx->streams[j]; if (!st) { ret = AVERROR(ENOMEM); goto fail; } - ff_program_add_stream_index(s, i, stream_offset + j); st->id = i; - avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); - avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); - if (v->bandwidth) - av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, - 0); + + avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec); + + if (pls->is_id3_timestamped) /* custom timestamps via id3 */ + avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); + else + avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); } - stream_offset += v->ctx->nb_streams; + + add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO); + add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO); + add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); + + stream_offset += pls->ctx->nb_streams; } - c->first_packet = 1; - c->first_timestamp = AV_NOPTS_VALUE; - c->seek_timestamp = AV_NOPTS_VALUE; + /* Create a program for each variant */ + for (i = 0; i < c->n_variants; i++) { + struct variant *v = c->variants[i]; + char bitrate_str[20]; + AVProgram *program; + + snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); + + program = av_new_program(s, i); + if (!program) + goto fail; + av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); + + for (j = 0; j < v->n_playlists; j++) { + struct playlist *pls = v->playlists[j]; + int is_shared = playlist_in_multiple_variants(c, pls); + int k; + + for (k = 0; k < pls->ctx->nb_streams; k++) { + struct AVStream *st = s->streams[pls->stream_offset + k]; + + ff_program_add_stream_index(s, i, pls->stream_offset + k); + + /* Set variant_bitrate for streams unique to this variant */ + if (!is_shared && v->bandwidth) + av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); + } + } + } return 0; fail: + free_playlist_list(c); free_variant_list(c); + free_rendition_list(c); return ret; } @@ -637,127 +1438,171 @@ static int recheck_discard_flags(AVFormatContext *s, int first) int i, changed = 0; /* Check if any new streams are needed */ - for (i = 0; i < c->n_variants; i++) - c->variants[i]->cur_needed = 0; + for (i = 0; i < c->n_playlists; i++) + c->playlists[i]->cur_needed = 0; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - struct variant *var = c->variants[s->streams[i]->id]; + struct playlist *pls = c->playlists[s->streams[i]->id]; if (st->discard < AVDISCARD_ALL) - var->cur_needed = 1; + pls->cur_needed = 1; } - for (i = 0; i < c->n_variants; i++) { - struct variant *v = c->variants[i]; - if (v->cur_needed && !v->needed) { - v->needed = 1; + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + if (pls->cur_needed && !pls->needed) { + pls->needed = 1; changed = 1; - v->cur_seq_no = c->cur_seq_no; - v->pb.eof_reached = 0; - av_log(s, AV_LOG_INFO, "Now receiving variant %d\n", i); - } else if (first && !v->cur_needed && v->needed) { - if (v->input) - ffurl_close(v->input); - v->input = NULL; - v->needed = 0; + pls->cur_seq_no = select_cur_seq_no(c, pls); + pls->pb.eof_reached = 0; + if (c->cur_timestamp != AV_NOPTS_VALUE) { + /* catch up */ + pls->seek_timestamp = c->cur_timestamp; + pls->seek_flags = AVSEEK_FLAG_ANY; + pls->seek_stream_index = -1; + } + av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %d\n", i, pls->cur_seq_no); + } else if (first && !pls->cur_needed && pls->needed) { + if (pls->input) + ffurl_close(pls->input); + pls->input = NULL; + pls->needed = 0; changed = 1; - av_log(s, AV_LOG_INFO, "No longer receiving variant %d\n", i); + av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i); } } return changed; } +static void fill_timing_for_id3_timestamped_stream(struct playlist *pls) +{ + if (pls->id3_offset >= 0) { + pls->pkt.dts = pls->id3_mpegts_timestamp + + av_rescale_q(pls->id3_offset, + pls->ctx->streams[pls->pkt.stream_index]->time_base, + MPEG_TIME_BASE_Q); + if (pls->pkt.duration) + pls->id3_offset += pls->pkt.duration; + else + pls->id3_offset = -1; + } else { + /* there have been packets with unknown duration + * since the last id3 tag, should not normally happen */ + pls->pkt.dts = AV_NOPTS_VALUE; + } + + if (pls->pkt.duration) + pls->pkt.duration = av_rescale_q(pls->pkt.duration, + pls->ctx->streams[pls->pkt.stream_index]->time_base, + MPEG_TIME_BASE_Q); + + pls->pkt.pts = AV_NOPTS_VALUE; +} + +static AVRational get_timebase(struct playlist *pls) +{ + if (pls->is_id3_timestamped) + return MPEG_TIME_BASE_Q; + + return pls->ctx->streams[pls->pkt.stream_index]->time_base; +} + +static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a, + int64_t ts_b, struct playlist *pls_b) +{ + int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q); + int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q); + + return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33); +} + static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) { HLSContext *c = s->priv_data; - int ret, i, minvariant = -1; + int ret, i, minplaylist = -1; - if (c->first_packet) { - recheck_discard_flags(s, 1); - c->first_packet = 0; - } + recheck_discard_flags(s, c->first_packet); -start: - c->end_of_segment = 0; - for (i = 0; i < c->n_variants; i++) { - struct variant *var = c->variants[i]; - /* Make sure we've got one buffered packet from each open variant + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + /* Make sure we've got one buffered packet from each open playlist * stream */ - if (var->needed && !var->pkt.data) { + if (pls->needed && !pls->pkt.data) { while (1) { int64_t ts_diff; - AVStream *st; - ret = av_read_frame(var->ctx, &var->pkt); + AVRational tb; + ret = av_read_frame(pls->ctx, &pls->pkt); if (ret < 0) { - if (!url_feof(&var->pb) && ret != AVERROR_EOF) + if (!url_feof(&pls->pb) && ret != AVERROR_EOF) return ret; - reset_packet(&var->pkt); + reset_packet(&pls->pkt); break; } else { + /* stream_index check prevents matching picture attachments etc. */ + if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) { + /* audio elementary streams are id3 timestamped */ + fill_timing_for_id3_timestamped_stream(pls); + } + if (c->first_timestamp == AV_NOPTS_VALUE && - var->pkt.dts != AV_NOPTS_VALUE) - c->first_timestamp = av_rescale_q(var->pkt.dts, - var->ctx->streams[var->pkt.stream_index]->time_base, - AV_TIME_BASE_Q); + pls->pkt.dts != AV_NOPTS_VALUE) + c->first_timestamp = av_rescale_q(pls->pkt.dts, + get_timebase(pls), AV_TIME_BASE_Q); } - if (c->seek_timestamp == AV_NOPTS_VALUE) + if (pls->seek_timestamp == AV_NOPTS_VALUE) break; - if (var->pkt.dts == AV_NOPTS_VALUE) { - c->seek_timestamp = AV_NOPTS_VALUE; - break; - } + if (pls->seek_stream_index < 0 || + pls->seek_stream_index == pls->pkt.stream_index) { - st = var->ctx->streams[var->pkt.stream_index]; - ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE, - st->time_base.den, AV_ROUND_DOWN) - - c->seek_timestamp; - if (ts_diff >= 0 && (c->seek_flags & AVSEEK_FLAG_ANY || - var->pkt.flags & AV_PKT_FLAG_KEY)) { - c->seek_timestamp = AV_NOPTS_VALUE; - break; + if (pls->pkt.dts == AV_NOPTS_VALUE) { + pls->seek_timestamp = AV_NOPTS_VALUE; + break; + } + + tb = get_timebase(pls); + ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE, + tb.den, AV_ROUND_DOWN) - + pls->seek_timestamp; + if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY || + pls->pkt.flags & AV_PKT_FLAG_KEY)) { + pls->seek_timestamp = AV_NOPTS_VALUE; + break; + } } - av_free_packet(&var->pkt); - reset_packet(&var->pkt); + av_free_packet(&pls->pkt); + reset_packet(&pls->pkt); } } - /* Check if this stream still is on an earlier segment number, or - * has the packet with the lowest dts */ - if (var->pkt.data) { - struct variant *minvar = minvariant < 0 ? - NULL : c->variants[minvariant]; - if (minvariant < 0 || var->cur_seq_no < minvar->cur_seq_no) { - minvariant = i; - } else if (var->cur_seq_no == minvar->cur_seq_no) { - int64_t dts = var->pkt.dts; - int64_t mindts = minvar->pkt.dts; - AVStream *st = var->ctx->streams[var->pkt.stream_index]; - AVStream *minst = minvar->ctx->streams[minvar->pkt.stream_index]; - - if (dts == AV_NOPTS_VALUE) { - minvariant = i; - } else if (mindts != AV_NOPTS_VALUE) { - if (st->start_time != AV_NOPTS_VALUE) - dts -= st->start_time; - if (minst->start_time != AV_NOPTS_VALUE) - mindts -= minst->start_time; - - if (av_compare_ts(dts, st->time_base, - mindts, minst->time_base) < 0) - minvariant = i; - } + /* Check if this stream has the packet with the lowest dts */ + if (pls->pkt.data) { + struct playlist *minpls = minplaylist < 0 ? + NULL : c->playlists[minplaylist]; + if (minplaylist < 0) { + minplaylist = i; + } else { + int64_t dts = pls->pkt.dts; + int64_t mindts = minpls->pkt.dts; + + if (dts == AV_NOPTS_VALUE || + (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0)) + minplaylist = i; } } } - if (c->end_of_segment) { - if (recheck_discard_flags(s, 0)) - goto start; - } + /* If we got a packet, return it */ - if (minvariant >= 0) { - *pkt = c->variants[minvariant]->pkt; - pkt->stream_index += c->variants[minvariant]->stream_offset; - reset_packet(&c->variants[minvariant]->pkt); + if (minplaylist >= 0) { + struct playlist *pls = c->playlists[minplaylist]; + *pkt = pls->pkt; + pkt->stream_index += pls->stream_offset; + reset_packet(&c->playlists[minplaylist]->pkt); + + if (pkt->dts != AV_NOPTS_VALUE) + c->cur_timestamp = av_rescale_q(pkt->dts, + pls->ctx->streams[pls->pkt.stream_index]->time_base, + AV_TIME_BASE_Q); + return 0; } return AVERROR_EOF; @@ -767,7 +1612,9 @@ static int hls_close(AVFormatContext *s) { HLSContext *c = s->priv_data; + free_playlist_list(c); free_variant_list(c); + free_rendition_list(c); return 0; } @@ -775,58 +1622,80 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { HLSContext *c = s->priv_data; - int i, j, ret; + struct playlist *seek_pls = NULL; + int i, seq_no; + int64_t first_timestamp, seek_timestamp, duration; - if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished) + if ((flags & AVSEEK_FLAG_BYTE) || + !(c->variants[0]->playlists[0]->finished || c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT)) return AVERROR(ENOSYS); - c->seek_flags = flags; - c->seek_timestamp = stream_index < 0 ? timestamp : - av_rescale_rnd(timestamp, AV_TIME_BASE, - s->streams[stream_index]->time_base.den, - flags & AVSEEK_FLAG_BACKWARD ? - AV_ROUND_DOWN : AV_ROUND_UP); - timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, stream_index >= 0 ? - s->streams[stream_index]->time_base.den : - AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? - AV_ROUND_DOWN : AV_ROUND_UP); - if (s->duration < c->seek_timestamp) { - c->seek_timestamp = AV_NOPTS_VALUE; + first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ? + 0 : c->first_timestamp; + + seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, + s->streams[stream_index]->time_base.den, + flags & AVSEEK_FLAG_BACKWARD ? + AV_ROUND_DOWN : AV_ROUND_UP); + + duration = s->duration == AV_NOPTS_VALUE ? + 0 : s->duration; + + if (0 < duration && duration < seek_timestamp - first_timestamp) return AVERROR(EIO); + + /* find the playlist with the specified stream */ + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + if (stream_index >= pls->stream_offset && + stream_index - pls->stream_offset < pls->ctx->nb_streams) { + seek_pls = pls; + break; + } } + /* check if the timestamp is valid for the playlist with the + * specified stream index */ + if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)) + return AVERROR(EIO); - ret = AVERROR(EIO); - for (i = 0; i < c->n_variants; i++) { + /* set segment now so we do not need to search again below */ + seek_pls->cur_seq_no = seq_no; + seek_pls->seek_stream_index = stream_index - seek_pls->stream_offset; + + for (i = 0; i < c->n_playlists; i++) { /* Reset reading */ - struct variant *var = c->variants[i]; - int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? - 0 : c->first_timestamp; - if (var->input) { - ffurl_close(var->input); - var->input = NULL; + struct playlist *pls = c->playlists[i]; + if (pls->input) { + ffurl_close(pls->input); + pls->input = NULL; } - av_free_packet(&var->pkt); - reset_packet(&var->pkt); - var->pb.eof_reached = 0; + av_free_packet(&pls->pkt); + reset_packet(&pls->pkt); + pls->pb.eof_reached = 0; /* Clear any buffered data */ - var->pb.buf_end = var->pb.buf_ptr = var->pb.buffer; + pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer; /* Reset the pos, to let the mpegts demuxer know we've seeked. */ - var->pb.pos = 0; - - /* Locate the segment that contains the target timestamp */ - for (j = 0; j < var->n_segments; j++) { - if (timestamp >= pos && - timestamp < pos + var->segments[j]->duration) { - var->cur_seq_no = var->start_seq_no + j; - ret = 0; - break; - } - pos += var->segments[j]->duration; + pls->pb.pos = 0; + /* Flush the packet queue of the subdemuxer. */ + ff_read_frame_flush(pls->ctx); + + pls->seek_timestamp = seek_timestamp; + pls->seek_flags = flags; + + if (pls != seek_pls) { + /* set closest segment seq_no for playlists not handled above */ + find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no); + /* seek the playlist to the given position without taking + * keyframes into account since this playlist does not have the + * specified stream where we should look for the keyframes */ + pls->seek_stream_index = -1; + pls->seek_flags |= AVSEEK_FLAG_ANY; } - if (ret) - c->seek_timestamp = AV_NOPTS_VALUE; } - return ret; + + c->cur_timestamp = seek_timestamp; + + return 0; } static int hls_probe(AVProbeData *p) diff --git a/chromium/third_party/ffmpeg/libavformat/hlsenc.c b/chromium/third_party/ffmpeg/libavformat/hlsenc.c index b9bf60543fa..12bd07b2d43 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsenc.c @@ -33,7 +33,7 @@ typedef struct ListEntry { char name[1024]; - int duration; + double duration; struct ListEntry *next; } ListEntry; @@ -41,6 +41,7 @@ typedef struct HLSContext { const AVClass *class; // Class for private options. unsigned number; int64_t sequence; + int64_t start_sequence; AVOutputFormat *oformat; AVFormatContext *avf; float time; // Set by a private option. @@ -50,11 +51,12 @@ typedef struct HLSContext { int has_video; int64_t start_pts; int64_t end_pts; - int64_t duration; // last segment duration computed so far, in seconds + double duration; // last segment duration computed so far, in seconds int nb_entries; ListEntry *list; ListEntry *end_list; char *basename; + char *baseurl; AVIOContext *pb; } HLSContext; @@ -70,6 +72,7 @@ static int hls_mux_init(AVFormatContext *s) oc->oformat = hls->oformat; oc->interrupt_callback = s->interrupt_callback; + av_dict_copy(&oc->metadata, s->metadata, 0); for (i = 0; i < s->nb_streams; i++) { AVStream *st; @@ -82,7 +85,7 @@ static int hls_mux_init(AVFormatContext *s) return 0; } -static int append_entry(HLSContext *hls, uint64_t duration) +static int append_entry(HLSContext *hls, double duration) { ListEntry *en = av_malloc(sizeof(*en)); @@ -101,7 +104,7 @@ static int append_entry(HLSContext *hls, uint64_t duration) hls->end_list = en; - if (hls->nb_entries >= hls->size) { + if (hls->size && hls->nb_entries >= hls->size) { en = hls->list; hls->list = en->next; av_free(en); @@ -130,6 +133,7 @@ static int hls_window(AVFormatContext *s, int last) ListEntry *en; int target_duration = 0; int ret = 0; + int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries); if ((ret = avio_open2(&hls->pb, s->filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) @@ -137,17 +141,21 @@ static int hls_window(AVFormatContext *s, int last) for (en = hls->list; en; en = en->next) { if (target_duration < en->duration) - target_duration = en->duration; + target_duration = (int) floor(en->duration + 0.5); } avio_printf(hls->pb, "#EXTM3U\n"); avio_printf(hls->pb, "#EXT-X-VERSION:3\n"); avio_printf(hls->pb, "#EXT-X-TARGETDURATION:%d\n", target_duration); - avio_printf(hls->pb, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", - FFMAX(0, hls->sequence - hls->size)); + avio_printf(hls->pb, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + + av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", + sequence); for (en = hls->list; en; en = en->next) { - avio_printf(hls->pb, "#EXTINF:%d,\n", en->duration); + avio_printf(hls->pb, "#EXTINF:%f,\n", en->duration); + if (hls->baseurl) + avio_printf(hls->pb, "%s", hls->baseurl); avio_printf(hls->pb, "%s\n", en->name); } @@ -166,7 +174,7 @@ static int hls_start(AVFormatContext *s) int err = 0; if (av_get_frame_filename(oc->filename, sizeof(oc->filename), - c->basename, c->wrap ? c->number % c->wrap : c->number) < 0) { + c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) { av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename); return AVERROR(EINVAL); } @@ -190,8 +198,7 @@ static int hls_write_header(AVFormatContext *s) const char *pattern = "%d.ts"; int basename_size = strlen(s->filename) + strlen(pattern) + 1; - hls->number = 0; - + hls->sequence = hls->start_sequence; hls->recording_time = hls->time * AV_TIME_BASE; hls->start_pts = AV_NOPTS_VALUE; @@ -269,8 +276,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) is_ref_pkt = can_split = 0; if (is_ref_pkt) - hls->duration = av_rescale(pkt->pts - hls->end_pts, - st->time_base.num, st->time_base.den); + hls->duration = (double)(pkt->pts - hls->end_pts) + * st->time_base.num / st->time_base.den; if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base, end_pts, AV_TIME_BASE_Q) >= 0) { @@ -320,10 +327,11 @@ static int hls_write_trailer(struct AVFormatContext *s) #define OFFSET(x) offsetof(HLSContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - {"start_number", "set first number in the sequence", OFFSET(sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E}, + {"start_number", "set first number in the sequence", OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E}, {"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E}, {"hls_list_size", "set maximum number of playlist entries", OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E}, {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E}, + {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/hnm.c b/chromium/third_party/ffmpeg/libavformat/hnm.c index 47a1808afba..1320fa52062 100644 --- a/chromium/third_party/ffmpeg/libavformat/hnm.c +++ b/chromium/third_party/ffmpeg/libavformat/hnm.c @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" @@ -90,7 +92,7 @@ static int hnm_read_header(AVFormatContext *s) hnm->currentframe = 0; - if (hnm->width < 320 || hnm->width > 640 || + if (hnm->width < 256 || hnm->width > 640 || hnm->height < 150 || hnm->height > 480) { av_log(s, AV_LOG_ERROR, "invalid resolution: %ux%u\n", hnm->width, hnm->height); @@ -149,8 +151,9 @@ static int hnm_read_packet(AVFormatContext *s, AVPacket *pkt) avio_skip(pb, 2); if (chunk_size > hnm->superchunk_remaining || !chunk_size) { - av_log(s, AV_LOG_ERROR, "invalid chunk size: %u, offset: %u\n", - chunk_size, (int) avio_tell(pb)); + av_log(s, AV_LOG_ERROR, + "invalid chunk size: %"PRIu32", offset: %"PRId64"\n", + chunk_size, avio_tell(pb)); avio_skip(pb, hnm->superchunk_remaining - 8); hnm->superchunk_remaining = 0; } @@ -172,8 +175,8 @@ static int hnm_read_packet(AVFormatContext *s, AVPacket *pkt) break; default: - av_log(s, AV_LOG_WARNING, "unknown chunk found: %d, offset: %d\n", - chunk_id, (int) avio_tell(pb)); + av_log(s, AV_LOG_WARNING, "unknown chunk found: %"PRIu16", offset: %"PRId64"\n", + chunk_id, avio_tell(pb)); avio_skip(pb, chunk_size - 8); hnm->superchunk_remaining -= chunk_size; break; diff --git a/chromium/third_party/ffmpeg/libavformat/http.c b/chromium/third_party/ffmpeg/libavformat/http.c index 0619e2a06cf..3e172e36455 100644 --- a/chromium/third_party/ffmpeg/libavformat/http.c +++ b/chromium/third_party/ffmpeg/libavformat/http.c @@ -49,29 +49,37 @@ typedef struct { unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end; int line_count; int http_code; - int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */ - char *content_type; - char *user_agent; - int64_t off, filesize; - int icy_data_read; ///< how much data was read since last ICY metadata packet - int icy_metaint; ///< after how many bytes of read data a new metadata packet will be found + /* Used if "Transfer-Encoding: chunked" otherwise -1. */ + int64_t chunksize; + int64_t off, end_off, filesize; char *location; HTTPAuthState auth_state; HTTPAuthState proxy_auth_state; char *headers; - int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */ + char *mime_type; + char *user_agent; + char *content_type; + /* Set if the server correctly handles Connection: close and will close + * the connection after feeding us the content. */ + int willclose; int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */ int chunked_post; - int end_chunked_post; /**< A flag which indicates if the end of chunked encoding has been sent. */ - int end_header; /**< A flag which indicates we have finished to read POST reply. */ - int multiple_requests; /**< A flag which indicates if we use persistent connections. */ + /* A flag which indicates if the end of chunked encoding has been sent. */ + int end_chunked_post; + /* A flag which indicates we have finished to read POST reply. */ + int end_header; + /* A flag which indicates if we use persistent connections. */ + int multiple_requests; uint8_t *post_data; int post_datalen; int is_akamai; int is_mediagateway; - char *mime_type; char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) int icy; + /* how much data was read since the last ICY metadata packet */ + int icy_data_read; + /* after how many bytes of read data a new metadata packet will be found */ + int icy_metaint; char *icy_metadata_headers; char *icy_metadata_packet; #if CONFIG_ZLIB @@ -91,20 +99,23 @@ static const AVOption options[] = { {"seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, D }, {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, -{"content_type", "force a content type", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, +{"content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, +{"user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D }, {"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D }, {"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, {"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E }, -{"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, +{"mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, {"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D }, {"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, -{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, -{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, +{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT }, +{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT }, {"auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, {.i64 = HTTP_AUTH_NONE}, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D|E, "auth_type" }, {"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" }, {"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" }, {"send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E }, {"location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, +{"offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, +{"end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, {NULL} }; #define HTTP_CLASS(flavor)\ @@ -285,7 +296,7 @@ static int http_getc(HTTPContext *s) if (len < 0) { return len; } else if (len == 0) { - return -1; + return AVERROR_EOF; } else { s->buf_ptr = s->buffer; s->buf_end = s->buffer + len; @@ -318,11 +329,110 @@ static int http_get_line(HTTPContext *s, char *line, int line_size) } } +static int check_http_code(URLContext *h, int http_code, const char *end) +{ + HTTPContext *s = h->priv_data; + /* error codes are 4xx and 5xx, but regard 401 as a success, so we + * don't abort until all headers have been parsed. */ + if (http_code >= 400 && http_code < 600 && + (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) && + (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) { + end += strspn(end, SPACE_CHARS); + av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end); + return AVERROR(EIO); + } + return 0; +} + +static int parse_location(HTTPContext *s, const char *p) +{ + char redirected_location[MAX_URL_SIZE], *new_loc; + ff_make_absolute_url(redirected_location, sizeof(redirected_location), + s->location, p); + new_loc = av_strdup(redirected_location); + if (!new_loc) + return AVERROR(ENOMEM); + av_free(s->location); + s->location = new_loc; + return 0; +} + +/* "bytes $from-$to/$document_size" */ +static void parse_content_range(URLContext *h, const char *p) +{ + HTTPContext *s = h->priv_data; + const char *slash; + + if (!strncmp(p, "bytes ", 6)) { + p += 6; + s->off = strtoll(p, NULL, 10); + if ((slash = strchr(p, '/')) && strlen(slash) > 0) + s->filesize = strtoll(slash+1, NULL, 10); + } + if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) + h->is_streamed = 0; /* we _can_ in fact seek */ +} + +static int parse_content_encoding(URLContext *h, const char *p) +{ + HTTPContext *s = h->priv_data; + + if (!av_strncasecmp(p, "gzip", 4) || + !av_strncasecmp(p, "deflate", 7)) { +#if CONFIG_ZLIB + s->compressed = 1; + inflateEnd(&s->inflate_stream); + if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) { + av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n", + s->inflate_stream.msg); + return AVERROR(ENOSYS); + } + if (zlibCompileFlags() & (1 << 17)) { + av_log(h, AV_LOG_WARNING, + "Your zlib was compiled without gzip support.\n"); + return AVERROR(ENOSYS); + } +#else + av_log(h, AV_LOG_WARNING, + "Compressed (%s) content, need zlib with gzip support\n", p); + return AVERROR(ENOSYS); +#endif + } else if (!av_strncasecmp(p, "identity", 8)) { + // The normal, no-encoding case (although servers shouldn't include + // the header at all if this is the case). + } else { + av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p); + } + return 0; +} + +// Concat all Icy- header lines +static int parse_icy(HTTPContext *s, const char *tag, const char *p) +{ + int len = 4 + strlen(p) + strlen(tag); + int is_first = !s->icy_metadata_headers; + int ret; + + if (s->icy_metadata_headers) + len += strlen(s->icy_metadata_headers); + + if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0) + return ret; + + if (is_first) + *s->icy_metadata_headers = '\0'; + + av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p); + + return 0; +} + static int process_line(URLContext *h, char *line, int line_count, int *new_location) { HTTPContext *s = h->priv_data; char *tag, *p, *end; + int ret; /* end of header */ if (line[0] == '\0') { @@ -340,16 +450,8 @@ static int process_line(URLContext *h, char *line, int line_count, av_log(h, AV_LOG_DEBUG, "http_code=%d\n", s->http_code); - /* error codes are 4xx and 5xx, but regard 401 as a success, so we - * don't abort until all headers have been parsed. */ - if (s->http_code >= 400 && s->http_code < 600 && (s->http_code != 401 - || s->auth_state.auth_type != HTTP_AUTH_NONE) && - (s->http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) { - end += strspn(end, SPACE_CHARS); - av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", - s->http_code, end); - return -1; - } + if ((ret = check_http_code(h, s->http_code, end)) < 0) + return ret; } else { while (*p != '\0' && *p != ':') p++; @@ -362,40 +464,28 @@ static int process_line(URLContext *h, char *line, int line_count, while (av_isspace(*p)) p++; if (!av_strcasecmp(tag, "Location")) { - char redirected_location[MAX_URL_SIZE], *new_loc; - ff_make_absolute_url(redirected_location, sizeof(redirected_location), - s->location, p); - new_loc = av_strdup(redirected_location); - if (!new_loc) - return AVERROR(ENOMEM); - av_free(s->location); - s->location = new_loc; + if ((ret = parse_location(s, p)) < 0) + return ret; *new_location = 1; - } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) { + } else if (!av_strcasecmp(tag, "Content-Length") && s->filesize == -1) { s->filesize = strtoll(p, NULL, 10); - } else if (!av_strcasecmp (tag, "Content-Range")) { - /* "bytes $from-$to/$document_size" */ - const char *slash; - if (!strncmp (p, "bytes ", 6)) { - p += 6; - s->off = strtoll(p, NULL, 10); - if ((slash = strchr(p, '/')) && strlen(slash) > 0) - s->filesize = strtoll(slash+1, NULL, 10); - } - if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) - h->is_streamed = 0; /* we _can_ in fact seek */ - } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5) && s->seekable == -1) { + } else if (!av_strcasecmp(tag, "Content-Range")) { + parse_content_range(h, p); + } else if (!av_strcasecmp(tag, "Accept-Ranges") && + !strncmp(p, "bytes", 5) && + s->seekable == -1) { h->is_streamed = 0; - } else if (!av_strcasecmp (tag, "Transfer-Encoding") && !av_strncasecmp(p, "chunked", 7)) { + } else if (!av_strcasecmp(tag, "Transfer-Encoding") && + !av_strncasecmp(p, "chunked", 7)) { s->filesize = -1; s->chunksize = 0; - } else if (!av_strcasecmp (tag, "WWW-Authenticate")) { + } else if (!av_strcasecmp(tag, "WWW-Authenticate")) { ff_http_auth_handle_header(&s->auth_state, tag, p); - } else if (!av_strcasecmp (tag, "Authentication-Info")) { + } else if (!av_strcasecmp(tag, "Authentication-Info")) { ff_http_auth_handle_header(&s->auth_state, tag, p); - } else if (!av_strcasecmp (tag, "Proxy-Authenticate")) { + } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) { ff_http_auth_handle_header(&s->proxy_auth_state, tag, p); - } else if (!av_strcasecmp (tag, "Connection")) { + } else if (!av_strcasecmp(tag, "Connection")) { if (!strcmp(p, "close")) s->willclose = 1; } else if (!av_strcasecmp (tag, "Server")) { @@ -405,7 +495,8 @@ static int process_line(URLContext *h, char *line, int line_count, s->is_mediagateway = 1; } } else if (!av_strcasecmp (tag, "Content-Type")) { - av_free(s->mime_type); s->mime_type = av_strdup(p); + av_free(s->mime_type); + s->mime_type = av_strdup(p); } else if (!av_strcasecmp (tag, "Set-Cookie")) { if (!s->cookies) { if (!(s->cookies = av_strdup(p))) @@ -423,37 +514,11 @@ static int process_line(URLContext *h, char *line, int line_count, } else if (!av_strcasecmp (tag, "Icy-MetaInt")) { s->icy_metaint = strtoll(p, NULL, 10); } else if (!av_strncasecmp(tag, "Icy-", 4)) { - // Concat all Icy- header lines - char *buf = av_asprintf("%s%s: %s\n", - s->icy_metadata_headers ? s->icy_metadata_headers : "", tag, p); - if (!buf) - return AVERROR(ENOMEM); - av_freep(&s->icy_metadata_headers); - s->icy_metadata_headers = buf; - } else if (!av_strcasecmp (tag, "Content-Encoding")) { - if (!av_strncasecmp(p, "gzip", 4) || !av_strncasecmp(p, "deflate", 7)) { -#if CONFIG_ZLIB - s->compressed = 1; - inflateEnd(&s->inflate_stream); - if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) { - av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n", - s->inflate_stream.msg); - return AVERROR(ENOSYS); - } - if (zlibCompileFlags() & (1 << 17)) { - av_log(h, AV_LOG_WARNING, "Your zlib was compiled without gzip support.\n"); - return AVERROR(ENOSYS); - } -#else - av_log(h, AV_LOG_WARNING, "Compressed (%s) content, need zlib with gzip support\n", p); - return AVERROR(ENOSYS); -#endif - } else if (!av_strncasecmp(p, "identity", 8)) { - // The normal, no-encoding case (although servers shouldn't include - // the header at all if this is the case). - } else { - av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p); - } + if ((ret = parse_icy(s, tag, p)) < 0) + return ret; + } else if (!av_strcasecmp(tag, "Content-Encoding")) { + if ((ret = parse_content_encoding(h, p)) < 0) + return ret; } } return 1; @@ -488,8 +553,11 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, av_free(cpath); cpath = av_strdup(¶m[5]); } else if (!av_strncasecmp("domain=", param, 7)) { + // if the cookie specifies a sub-domain, skip the leading dot thereby + // supporting URLs that point to sub-domains and the master domain + int leading_dot = (param[7] == '.'); av_free(cdomain); - cdomain = av_strdup(¶m[7]); + cdomain = av_strdup(¶m[7+leading_dot]); } else if (!av_strncasecmp("secure", param, 6) || !av_strncasecmp("comment", param, 7) || !av_strncasecmp("max-age", param, 7) || @@ -643,9 +711,15 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, // Note: we send this on purpose even when s->off is 0 when we're probing, // since it allows us to detect more reliably if a (non-conforming) // server supports seeking by analysing the reply headers. - if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1)) + if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) { len += av_strlcatf(headers + len, sizeof(headers) - len, - "Range: bytes=%"PRId64"-\r\n", s->off); + "Range: bytes=%"PRId64"-", s->off); + if (s->end_off) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "%"PRId64, s->end_off - 1); + len += av_strlcpy(headers + len, "\r\n", + sizeof(headers) - len); + } if (send_expect_100 && !has_header(s->headers, "\r\nExpect: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "Expect: 100-continue\r\n"); @@ -666,12 +740,13 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data) len += av_strlcatf(headers + len, sizeof(headers) - len, "Content-Length: %d\r\n", s->post_datalen); + if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type) len += av_strlcatf(headers + len, sizeof(headers) - len, "Content-Type: %s\r\n", s->content_type); if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) { char *cookies = NULL; - if (!get_cookies(s, &cookies, path, hoststr)) { + if (!get_cookies(s, &cookies, path, hoststr) && cookies) { len += av_strlcatf(headers + len, sizeof(headers) - len, "Cookie: %s\r\n", cookies); av_free(cookies); @@ -700,17 +775,14 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, authstr ? authstr : "", proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : ""); - av_freep(&authstr); - av_freep(&proxyauthstr); - av_log(h, AV_LOG_DEBUG, "request: %s\n", s->buffer); if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0) - return err; + goto done; if (s->post_data) if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0) - return err; + goto done; /* init input buffer */ s->buf_ptr = s->buffer; @@ -727,15 +799,20 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, * we've still to send the POST data, but the code calling this * function will check http_code after we return. */ s->http_code = 200; - return 0; + err = 0; + goto done; } /* wait for header */ err = http_read_header(h, new_location); if (err < 0) - return err; + goto done; - return (off == s->off) ? 0 : -1; + err = (off == s->off) ? 0 : -1; +done: + av_freep(&authstr); + av_freep(&proxyauthstr); + return err; } @@ -757,7 +834,6 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) } if (len > 0) { s->off += len; - s->icy_data_read += len; if (s->chunksize > 0) s->chunksize -= len; } @@ -796,7 +872,7 @@ static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size) } #endif -static int http_read(URLContext *h, uint8_t *buf, int size) +static int http_read_stream(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int err, new_location; @@ -814,7 +890,6 @@ static int http_read(URLContext *h, uint8_t *buf, int size) if (!s->chunksize) { char line[32]; - for(;;) { do { if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; @@ -826,37 +901,9 @@ static int http_read(URLContext *h, uint8_t *buf, int size) if (!s->chunksize) return 0; - break; - } } size = FFMIN(size, s->chunksize); } - if (s->icy_metaint > 0) { - int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ - if (!remaining) { - // The metadata packet is variable sized. It has a 1 byte header - // which sets the length of the packet (divided by 16). If it's 0, - // the metadata doesn't change. After the packet, icy_metaint bytes - // of normal data follow. - int ch = http_getc(s); - if (ch < 0) - return ch; - if (ch > 0) { - char data[255 * 16 + 1]; - int n; - int ret; - ch *= 16; - for (n = 0; n < ch; n++) - data[n] = http_getc(s); - data[ch + 1] = 0; - if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) - return ret; - } - s->icy_data_read = 0; - remaining = s->icy_metaint; - } - size = FFMIN(size, remaining); - } #if CONFIG_ZLIB if (s->compressed) return http_buf_read_compressed(h, buf, size); @@ -864,6 +911,72 @@ static int http_read(URLContext *h, uint8_t *buf, int size) return http_buf_read(h, buf, size); } +// Like http_read_stream(), but no short reads. +// Assumes partial reads are an error. +static int http_read_stream_all(URLContext *h, uint8_t *buf, int size) +{ + int pos = 0; + while (pos < size) { + int len = http_read_stream(h, buf + pos, size - pos); + if (len < 0) + return len; + pos += len; + } + return pos; +} + +static int store_icy(URLContext *h, int size) +{ + HTTPContext *s = h->priv_data; + /* until next metadata packet */ + int remaining = s->icy_metaint - s->icy_data_read; + + if (remaining < 0) + return AVERROR_INVALIDDATA; + + if (!remaining) { + // The metadata packet is variable sized. It has a 1 byte header + // which sets the length of the packet (divided by 16). If it's 0, + // the metadata doesn't change. After the packet, icy_metaint bytes + // of normal data follow. + uint8_t ch; + int len = http_read_stream_all(h, &ch, 1); + if (len < 0) + return len; + if (ch > 0) { + char data[255 * 16 + 1]; + int ret; + len = ch * 16; + ret = http_read_stream_all(h, data, len); + if (ret < 0) + return ret; + data[len + 1] = 0; + if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) + return ret; + } + s->icy_data_read = 0; + remaining = s->icy_metaint; + } + + return FFMIN(size, remaining); +} + +static int http_read(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + + if (s->icy_metaint > 0) { + size = store_icy(h, size); + if (size < 0) + return size; + } + + size = http_read_stream(h, buf, size); + if (size > 0) + s->icy_data_read += size; + return size; +} + /* used only when posting data */ static int http_write(URLContext *h, const uint8_t *buf, int size) { @@ -934,34 +1047,42 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence) URLContext *old_hd = s->hd; int64_t old_off = s->off; uint8_t old_buf[BUFFER_SIZE]; - int old_buf_size; + int old_buf_size, ret; AVDictionary *options = NULL; if (whence == AVSEEK_SIZE) return s->filesize; + else if ((whence == SEEK_CUR && off == 0) || + (whence == SEEK_SET && off == s->off)) + return s->off; else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed) - return -1; + return AVERROR(ENOSYS); - /* we save the old context in case the seek fails */ - old_buf_size = s->buf_end - s->buf_ptr; - memcpy(old_buf, s->buf_ptr, old_buf_size); - s->hd = NULL; if (whence == SEEK_CUR) off += s->off; else if (whence == SEEK_END) off += s->filesize; + else if (whence != SEEK_SET) + return AVERROR(EINVAL); + if (off < 0) + return AVERROR(EINVAL); s->off = off; + /* we save the old context in case the seek fails */ + old_buf_size = s->buf_end - s->buf_ptr; + memcpy(old_buf, s->buf_ptr, old_buf_size); + s->hd = NULL; + /* if it fails, continue on old connection */ av_dict_copy(&options, s->chained_options, 0); - if (http_open_cnx(h, &options) < 0) { + if ((ret = http_open_cnx(h, &options)) < 0) { av_dict_free(&options); memcpy(s->buffer, old_buf, old_buf_size); s->buf_ptr = s->buffer; s->buf_end = s->buffer + old_buf_size; s->hd = old_hd; s->off = old_off; - return -1; + return ret; } av_dict_free(&options); ffurl_close(old_hd); diff --git a/chromium/third_party/ffmpeg/libavformat/httpauth.c b/chromium/third_party/ffmpeg/libavformat/httpauth.c index 5ca48b9c1de..dbe3eff48f5 100644 --- a/chromium/third_party/ffmpeg/libavformat/httpauth.c +++ b/chromium/third_party/ffmpeg/libavformat/httpauth.c @@ -224,8 +224,11 @@ static char *make_digest_auth(HTTPAuthState *state, const char *username, av_strlcatf(authstr, len, ",nonce=\"%s\"", digest->nonce); av_strlcatf(authstr, len, ",uri=\"%s\"", uri); av_strlcatf(authstr, len, ",response=\"%s\"", response); + + // we are violating the RFC and use "" because all others seem to do that too. if (digest->algorithm[0]) - av_strlcatf(authstr, len, ",algorithm=%s", digest->algorithm); + av_strlcatf(authstr, len, ",algorithm=\"%s\"", digest->algorithm); + if (digest->opaque[0]) av_strlcatf(authstr, len, ",opaque=\"%s\"", digest->opaque); if (digest->qop[0]) { diff --git a/chromium/third_party/ffmpeg/libavformat/icodec.c b/chromium/third_party/ffmpeg/libavformat/icodec.c index 4c038e96146..847f0eea2f0 100644 --- a/chromium/third_party/ffmpeg/libavformat/icodec.c +++ b/chromium/third_party/ffmpeg/libavformat/icodec.c @@ -58,7 +58,7 @@ static int read_header(AVFormatContext *s) avio_skip(pb, 4); ico->nb_images = avio_rl16(pb); - ico->images = av_malloc(ico->nb_images * sizeof(IcoImage)); + ico->images = av_malloc_array(ico->nb_images, sizeof(IcoImage)); if (!ico->images) return AVERROR(ENOMEM); diff --git a/chromium/third_party/ffmpeg/libavformat/icoenc.c b/chromium/third_party/ffmpeg/libavformat/icoenc.c index 561c6cadcc9..dcf906513af 100644 --- a/chromium/third_party/ffmpeg/libavformat/icoenc.c +++ b/chromium/third_party/ffmpeg/libavformat/icoenc.c @@ -101,7 +101,7 @@ static int ico_write_header(AVFormatContext *s) avio_skip(pb, 16); } - ico->images = av_mallocz(ico->nb_images * sizeof(IcoMuxContext)); + ico->images = av_mallocz_array(ico->nb_images, sizeof(IcoMuxContext)); if (!ico->images) return AVERROR(ENOMEM); diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.c b/chromium/third_party/ffmpeg/libavformat/id3v2.c index 4bc76a321ca..fb89e83944b 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.c +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.c @@ -59,6 +59,7 @@ const AVMetadataConv ff_id3v2_34_metadata_conv[] = { }; const AVMetadataConv ff_id3v2_4_metadata_conv[] = { + { "TCMP", "compilation" }, { "TDRL", "date" }, { "TDRC", "date" }, { "TDEN", "creation_time" }, @@ -71,6 +72,7 @@ const AVMetadataConv ff_id3v2_4_metadata_conv[] = { static const AVMetadataConv id3v2_2_metadata_conv[] = { { "TAL", "album" }, { "TCO", "genre" }, + { "TCP", "compilation" }, { "TT2", "title" }, { "TEN", "encoded_by" }, { "TP1", "artist" }, @@ -313,7 +315,7 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct. */ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, - char *tag, ID3v2ExtraMeta **extra_meta) + char *tag, ID3v2ExtraMeta **extra_meta, int isv34) { ID3v2ExtraMetaGEOB *geob_data = NULL; ID3v2ExtraMeta *new_extra = NULL; @@ -325,14 +327,14 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB)); if (!geob_data) { - av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", + 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 %zu bytes\n", + av_log(s, AV_LOG_ERROR, "Failed to alloc %"SIZE_SPECIFIER" bytes\n", sizeof(ID3v2ExtraMeta)); goto fail; } @@ -445,7 +447,7 @@ static void free_apic(void *obj) } static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, - char *tag, ID3v2ExtraMeta **extra_meta) + char *tag, ID3v2ExtraMeta **extra_meta, int isv34) { int enc, pic_type; char mimetype[64]; @@ -467,7 +469,12 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, taglen--; /* mimetype */ + if (isv34) { taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype)); + } else { + avio_read(pb, mimetype, 3); + mimetype[3] = 0; + } while (mime->id != AV_CODEC_ID_NONE) { if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) { id = mime->id; @@ -518,7 +525,7 @@ fail: avio_seek(pb, end, SEEK_SET); } -static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *ttag, ID3v2ExtraMeta **extra_meta) +static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *ttag, ID3v2ExtraMeta **extra_meta, int isv34) { AVRational time_base = {1, 1000}; uint32_t start, end; @@ -527,6 +534,14 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *tta int taglen; char tag[5]; + if (!s) { + /* We should probably just put the chapter data to extra_meta here + * and do the AVFormatContext-needing part in a separate + * ff_id3v2_parse_apic()-like function. */ + av_log(NULL, AV_LOG_DEBUG, "No AVFormatContext, skipped ID3 chapter data\n"); + return; + } + if (decode_str(s, pb, 0, &dst, &len) < 0) return; if (len < 16) @@ -544,15 +559,14 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *tta len -= 16; while (len > 10) { - avio_read(pb, tag, 4); + if (avio_read(pb, tag, 4) < 4) + goto end; tag[4] = 0; taglen = avio_rb32(pb); avio_skip(pb, 2); len -= 10; - if (taglen < 0 || taglen > len) { - av_free(dst); - return; - } + if (taglen < 0 || taglen > len) + goto end; if (tag[0] == 'T') read_ttag(s, pb, taglen, &chapter->metadata, tag); else @@ -562,14 +576,60 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *tta ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_34_metadata_conv); ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_4_metadata_conv); +end: av_free(dst); } +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, + char *tag, ID3v2ExtraMeta **extra_meta, int isv34) +{ + ID3v2ExtraMeta *meta; + ID3v2ExtraMetaPRIV *priv; + + meta = av_mallocz(sizeof(*meta)); + priv = av_mallocz(sizeof(*priv)); + + if (!meta || !priv) + goto fail; + + if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &priv->owner, &taglen) < 0) + goto fail; + + priv->data = av_malloc(taglen); + if (!priv->data) + goto fail; + + priv->datasize = taglen; + + if (avio_read(pb, priv->data, priv->datasize) != priv->datasize) + goto fail; + + meta->tag = "PRIV"; + meta->data = priv; + meta->next = *extra_meta; + *extra_meta = meta; + + return; + +fail: + if (priv) + free_priv(priv); + av_freep(&meta); +} + typedef struct ID3v2EMFunc { const char *tag3; const char *tag4; void (*read)(AVFormatContext *, AVIOContext *, int, char *, - ID3v2ExtraMeta **); + ID3v2ExtraMeta **, int isv34); void (*free)(void *obj); } ID3v2EMFunc; @@ -577,6 +637,7 @@ static const ID3v2EMFunc id3v2_extra_meta_funcs[] = { { "GEO", "GEOB", read_geobtag, free_geobtag }, { "PIC", "APIC", read_apic, free_apic }, { "CHAP","CHAP", read_chapter, NULL }, + { "PRIV","PRIV", read_priv, free_priv }, { NULL } }; @@ -599,16 +660,17 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34) return NULL; } -static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, +static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata, + AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta) { int isv34, unsync; unsigned tlen; char tag[5]; - int64_t next, end = avio_tell(s->pb) + len; + int64_t next, end = avio_tell(pb) + len; int taghdrlen; const char *reason = NULL; - AVIOContext pb; + AVIOContext pb_local; AVIOContext *pbx; unsigned char *buffer = NULL; int buffer_size = 0; @@ -642,7 +704,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, unsync = flags & 0x80; if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */ - int extlen = get_size(s->pb, 4); + int extlen = get_size(pb, 4); if (version == 4) /* In v2.4 the length includes the length field we just read. */ extlen -= 4; @@ -651,7 +713,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, reason = "invalid extended header length"; goto error; } - avio_skip(s->pb, extlen); + avio_skip(pb, extlen); len -= extlen + 4; if (len < 0) { reason = "extended header too long."; @@ -667,18 +729,20 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, unsigned long dlen; if (isv34) { - avio_read(s->pb, tag, 4); + if (avio_read(pb, tag, 4) < 4) + break; tag[4] = 0; if (version == 3) { - tlen = avio_rb32(s->pb); + tlen = avio_rb32(pb); } else - tlen = get_size(s->pb, 4); - tflags = avio_rb16(s->pb); + tlen = get_size(pb, 4); + tflags = avio_rb16(pb); tunsync = tflags & ID3v2_FLAG_UNSYNCH; } else { - avio_read(s->pb, tag, 3); + if (avio_read(pb, tag, 3) < 3) + break; tag[3] = 0; - tlen = avio_rb24(s->pb); + tlen = avio_rb24(pb); } if (tlen > (1<<28)) break; @@ -687,7 +751,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, if (len < 0) break; - next = avio_tell(s->pb) + tlen; + next = avio_tell(pb) + tlen; if (!tlen) { if (tag[0]) @@ -699,7 +763,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, if (tflags & ID3v2_FLAG_DATALEN) { if (tlen < 4) break; - dlen = avio_rb32(s->pb); + dlen = avio_rb32(pb); tlen -= 4; } else dlen = tlen; @@ -718,12 +782,12 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, type = "encrypted and compressed"; av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag); - avio_skip(s->pb, tlen); + avio_skip(pb, tlen); /* check for text tag or supported special meta tag */ } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) { - pbx = s->pb; + pbx = pb; if (unsync || tunsync || tcomp) { av_fast_malloc(&buffer, &buffer_size, tlen); @@ -733,23 +797,23 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, } } if (unsync || tunsync) { - int64_t end = avio_tell(s->pb) + tlen; + int64_t end = avio_tell(pb) + tlen; uint8_t *b; b = buffer; - while (avio_tell(s->pb) < end && b - buffer < tlen && !s->pb->eof_reached) { - *b++ = avio_r8(s->pb); - if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 && + while (avio_tell(pb) < end && b - buffer < tlen && !pb->eof_reached) { + *b++ = avio_r8(pb); + if (*(b - 1) == 0xff && avio_tell(pb) < end - 1 && b - buffer < tlen && - !s->pb->eof_reached ) { - uint8_t val = avio_r8(s->pb); - *b++ = val ? val : avio_r8(s->pb); + !pb->eof_reached ) { + uint8_t val = avio_r8(pb); + *b++ = val ? val : avio_r8(pb); } } - ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL, + ffio_init_context(&pb_local, buffer, b - buffer, 0, NULL, NULL, NULL, NULL); tlen = b - buffer; - pbx = &pb; // read from sync buffer + pbx = &pb_local; // read from sync buffer } #if CONFIG_ZLIB @@ -765,7 +829,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, } if (!(unsync || tunsync)) { - err = avio_read(s->pb, buffer, tlen); + err = avio_read(pb, buffer, tlen); if (err < 0) { av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n"); goto seek; @@ -778,26 +842,26 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err); goto seek; } - ffio_init_context(&pb, uncompressed_buffer, dlen, 0, NULL, NULL, NULL, NULL); + ffio_init_context(&pb_local, uncompressed_buffer, dlen, 0, NULL, NULL, NULL, NULL); tlen = dlen; - pbx = &pb; // read from sync buffer + pbx = &pb_local; // read from sync buffer } #endif if (tag[0] == 'T') /* parse text tag */ - read_ttag(s, pbx, tlen, &s->metadata, tag); + read_ttag(s, pbx, tlen, metadata, tag); else /* parse special meta tag */ - extra_func->read(s, pbx, tlen, tag, extra_meta); + extra_func->read(s, pbx, tlen, tag, extra_meta, isv34); } else if (!tag[0]) { if (tag[1]) av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n"); - avio_skip(s->pb, tlen); + avio_skip(pb, tlen); break; } /* Skip to end of tag */ seek: - avio_seek(s->pb, next, SEEK_SET); + avio_seek(pb, next, SEEK_SET); } /* Footer preset, always 10 bytes, skip over it */ @@ -808,26 +872,36 @@ error: if (reason) av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); - avio_seek(s->pb, end, SEEK_SET); + avio_seek(pb, end, SEEK_SET); av_free(buffer); av_free(uncompressed_buffer); return; } -void ff_id3v2_read(AVFormatContext *s, const char *magic, - ID3v2ExtraMeta **extra_meta) +static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, + AVFormatContext *s, const char *magic, + ID3v2ExtraMeta **extra_meta, int64_t max_search_size) { int len, ret; uint8_t buf[ID3v2_HEADER_SIZE]; int found_header; - int64_t off; + int64_t start, off; + + if (max_search_size && max_search_size < ID3v2_HEADER_SIZE) + return; + start = avio_tell(pb); do { /* save the current offset in case there's nothing to read/skip */ - off = avio_tell(s->pb); - ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE); + off = avio_tell(pb); + if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) { + avio_seek(pb, off, SEEK_SET); + break; + } + + ret = avio_read(pb, buf, ID3v2_HEADER_SIZE); if (ret != ID3v2_HEADER_SIZE) { - avio_seek(s->pb, off, SEEK_SET); + avio_seek(pb, off, SEEK_SET); break; } found_header = ff_id3v2_match(buf, magic); @@ -837,15 +911,27 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic, ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f); - id3v2_parse(s, len, buf[3], buf[5], extra_meta); + id3v2_parse(pb, metadata, s, len, buf[3], buf[5], extra_meta); } else { - avio_seek(s->pb, off, SEEK_SET); + avio_seek(pb, off, SEEK_SET); } } while (found_header); - ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv); - ff_metadata_conv(&s->metadata, NULL, id3v2_2_metadata_conv); - ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv); - merge_date(&s->metadata); + ff_metadata_conv(metadata, NULL, ff_id3v2_34_metadata_conv); + ff_metadata_conv(metadata, NULL, id3v2_2_metadata_conv); + ff_metadata_conv(metadata, NULL, ff_id3v2_4_metadata_conv); + merge_date(metadata); +} + +void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, + const char *magic, ID3v2ExtraMeta **extra_meta) +{ + id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0); +} + +void ff_id3v2_read(AVFormatContext *s, const char *magic, + ID3v2ExtraMeta **extra_meta, unsigned int max_search_size) +{ + id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size); } void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) @@ -860,6 +946,8 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) av_freep(¤t); current = next; } + + *extra_meta = NULL; } int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.h b/chromium/third_party/ffmpeg/libavformat/id3v2.h index e893922133e..9d7bf1c03c1 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.h +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.h @@ -73,6 +73,12 @@ typedef struct ID3v2ExtraMetaAPIC { enum AVCodecID id; } ID3v2ExtraMetaAPIC; +typedef struct ID3v2ExtraMetaPRIV { + uint8_t *owner; + uint8_t *data; + uint32_t datasize; +} ID3v2ExtraMetaPRIV; + /** * Detect ID3v2 Header. * @param buf must be ID3v2_HEADER_SIZE byte long @@ -89,11 +95,27 @@ int ff_id3v2_match(const uint8_t *buf, const char *magic); int ff_id3v2_tag_len(const uint8_t *buf); /** - * Read an ID3v2 tag, including supported extra metadata + * Read an ID3v2 tag into specified dictionary and retrieve supported extra metadata. + * + * Chapters are not currently read by this variant. + * + * @param metadata Parsed metadata is stored here + * @param extra_meta If not NULL, extra metadata is parsed into a list of + * ID3v2ExtraMeta structs and *extra_meta points to the head of the list + */ +void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta); + +/** + * Read an ID3v2 tag, including supported extra metadata and chapters. + * + * Data is read from and stored to AVFormatContext. + * * @param extra_meta If not NULL, extra metadata is parsed into a list of * ID3v2ExtraMeta structs and *extra_meta points to the head of the list + * @param[opt] max_search_search restrict ID3 magic number search (bytes from start) */ -void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); +void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta, + unsigned int max_search_size); /** * Initialize an ID3v2 tag. @@ -114,7 +136,7 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) /** * Finalize an opened ID3v2 tag. */ -void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb); +void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb, int padding_bytes); /** * Write an ID3v2 tag containing all global metadata from s. diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2enc.c b/chromium/third_party/ffmpeg/libavformat/id3v2enc.c index 60522444fc6..4d555b3d241 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2enc.c +++ b/chromium/third_party/ffmpeg/libavformat/id3v2enc.c @@ -29,8 +29,6 @@ #include "avio_internal.h" #include "id3v2.h" -#define PADDING_BYTES 10 - static void id3v2_put_size(AVIOContext *pb, int size) { avio_w8(pb, size >> 21 & 0x7f); @@ -324,15 +322,23 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) return 0; } -void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb) +void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb, + int padding_bytes) { int64_t cur_pos; - /* adding an arbitrary amount of padding bytes at the end of the - * ID3 metadata fixes cover art display for some software (iTunes, - * Traktor, Serato, Torq) */ - ffio_fill(pb, 0, PADDING_BYTES); - id3->len += PADDING_BYTES; + if (padding_bytes < 0) + padding_bytes = 10; + + /* The ID3v2.3 specification states that 28 bits are used to represent the + * size of the whole tag. Therefore the current size of the tag needs to be + * subtracted from the upper limit of 2^28-1 to clip the value correctly. */ + /* The minimum of 10 is an arbitrary amount of padding at the end of the tag + * to fix cover art display with some software such as iTunes, Traktor, + * Serato, Torq. */ + padding_bytes = av_clip(padding_bytes, 10, 268435455 - id3->len); + ffio_fill(pb, 0, padding_bytes); + id3->len += padding_bytes; cur_pos = avio_tell(pb); avio_seek(pb, id3->size_pos, SEEK_SET); @@ -349,7 +355,7 @@ int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, ff_id3v2_start(&id3, s->pb, id3v2_version, magic); if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0) return ret; - ff_id3v2_finish(&id3, s->pb); + ff_id3v2_finish(&id3, s->pb, s->metadata_header_padding); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/idcin.c b/chromium/third_party/ffmpeg/libavformat/idcin.c index f2d5548a4f1..cc25fb0e38d 100644 --- a/chromium/third_party/ffmpeg/libavformat/idcin.c +++ b/chromium/third_party/ffmpeg/libavformat/idcin.c @@ -205,15 +205,8 @@ static int idcin_read_header(AVFormatContext *s) st->codec->height = height; /* load up the Huffman tables into extradata */ - if (ff_alloc_extradata(st->codec, HUFFMAN_TABLE_SIZE)) - return AVERROR(ENOMEM); - ret = avio_read(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE); - if (ret < 0) { + if ((ret = ff_get_extradata(st->codec, pb, HUFFMAN_TABLE_SIZE)) < 0) return ret; - } else if (ret != HUFFMAN_TABLE_SIZE) { - av_log(s, AV_LOG_ERROR, "incomplete header\n"); - return AVERROR(EIO); - } if (idcin->audio_present) { idcin->audio_present = 1; diff --git a/chromium/third_party/ffmpeg/libavformat/idroqenc.c b/chromium/third_party/ffmpeg/libavformat/idroqenc.c index 50c428046ba..28a3aba9d43 100644 --- a/chromium/third_party/ffmpeg/libavformat/idroqenc.c +++ b/chromium/third_party/ffmpeg/libavformat/idroqenc.c @@ -25,9 +25,35 @@ static int roq_write_header(struct AVFormatContext *s) { - static const uint8_t header[] = { - 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x00 + uint8_t header[] = { + 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, /* fps: */ 0x1E, 0x00 }; + int n; + AVCodecContext *avctx; + +// set the actual fps + for(n=0;n<s->nb_streams;n++) { + if ((avctx=s->streams[n]->codec)->codec_type == AVMEDIA_TYPE_VIDEO) { + unsigned int fps; + + if (avctx->time_base.num != 1) { + av_log(avctx, AV_LOG_ERROR, "Frame rate must be integer\n"); + return AVERROR(EINVAL); + } + + if ((fps=avctx->time_base.den) > 255) { + av_log(avctx, AV_LOG_ERROR, "Frame rate may not exceed 255fps\n"); + return AVERROR(EINVAL); + } + + if (fps != 30) { + av_log(avctx, AV_LOG_WARNING, "For vintage compatibility fps must be 30\n"); + } + + header[6] = fps; + break; + } + } avio_write(s->pb, header, 8); avio_flush(s->pb); diff --git a/chromium/third_party/ffmpeg/libavformat/iff.c b/chromium/third_party/ffmpeg/libavformat/iff.c index edf308b1355..62f0b8387c2 100644 --- a/chromium/third_party/ffmpeg/libavformat/iff.c +++ b/chromium/third_party/ffmpeg/libavformat/iff.c @@ -28,12 +28,15 @@ * http://wiki.multimedia.cx/index.php?title=IFF */ +#include <inttypes.h> + #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "libavcodec/bytestream.h" #include "avformat.h" +#include "id3v2.h" #include "internal.h" #define ID_8SVX MKTAG('8','S','V','X') @@ -55,8 +58,10 @@ #define ID_DEEP MKTAG('D','E','E','P') #define ID_RGB8 MKTAG('R','G','B','8') #define ID_RGBN MKTAG('R','G','B','N') +#define ID_DSD MKTAG('D','S','D',' ') #define ID_FORM MKTAG('F','O','R','M') +#define ID_FRM8 MKTAG('F','R','M','8') #define ID_ANNO MKTAG('A','N','N','O') #define ID_AUTH MKTAG('A','U','T','H') #define ID_CHRS MKTAG('C','H','R','S') @@ -93,6 +98,7 @@ typedef enum { } svx8_compression_type; typedef struct { + int is_64bit; ///< chunk size is 64-bit int64_t body_pos; int64_t body_end; uint32_t body_size; @@ -118,7 +124,7 @@ static int get_metadata(AVFormatContext *s, if (!buf) return AVERROR(ENOMEM); - if (avio_read(s->pb, buf, data_size) < 0) { + if (avio_read(s->pb, buf, data_size) != data_size) { av_free(buf); return AVERROR(EIO); } @@ -131,7 +137,7 @@ static int iff_probe(AVProbeData *p) { const uint8_t *d = p->buf; - if ( AV_RL32(d) == ID_FORM && + if ( (AV_RL32(d) == ID_FORM && (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_16SV || AV_RL32(d+8) == ID_MAUD || @@ -140,11 +146,188 @@ static int iff_probe(AVProbeData *p) AV_RL32(d+8) == ID_DEEP || AV_RL32(d+8) == ID_ILBM || AV_RL32(d+8) == ID_RGB8 || - AV_RL32(d+8) == ID_RGBN) ) + AV_RL32(d+8) == ID_RGB8 || + AV_RL32(d+8) == ID_RGBN)) || + (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) return AVPROBE_SCORE_MAX; return 0; } +static const AVCodecTag dsd_codec_tags[] = { + { AV_CODEC_ID_DSD_MSBF, ID_DSD }, + { AV_CODEC_ID_NONE, 0 }, +}; + + +#define DSD_SLFT MKTAG('S','L','F','T') +#define DSD_SRGT MKTAG('S','R','G','T') +#define DSD_MLFT MKTAG('M','L','F','T') +#define DSD_MRGT MKTAG('M','R','G','T') +#define DSD_C MKTAG('C',' ',' ',' ') +#define DSD_LS MKTAG('L','S',' ',' ') +#define DSD_RS MKTAG('R','S',' ',' ') +#define DSD_LFE MKTAG('L','F','E',' ') + +static const uint32_t dsd_stereo[] = { DSD_SLFT, DSD_SRGT }; +static const uint32_t dsd_5point0[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LS, DSD_RS }; +static const uint32_t dsd_5point1[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LFE, DSD_LS, DSD_RS }; + +typedef struct { + uint64_t layout; + const uint32_t * dsd_layout; +} DSDLayoutDesc; + +static const DSDLayoutDesc dsd_channel_layout[] = { + { AV_CH_LAYOUT_STEREO, dsd_stereo }, + { AV_CH_LAYOUT_5POINT0, dsd_5point0 }, + { AV_CH_LAYOUT_5POINT1, dsd_5point1 }, +}; + +static const uint64_t dsd_loudspeaker_config[] = { + AV_CH_LAYOUT_STEREO, + 0, 0, + AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_5POINT1, +}; + +static const char * dsd_source_comment[] = { + "dsd_source_comment", + "analogue_source_comment", + "pcm_source_comment", +}; + +static const char * dsd_history_comment[] = { + "general_remark", + "operator_name", + "creating_machine", + "timezone", + "file_revision" +}; + +static int parse_dsd_diin(AVFormatContext *s, AVStream *st, uint64_t eof) +{ + AVIOContext *pb = s->pb; + + while (avio_tell(pb) + 12 <= eof) { + uint32_t tag = avio_rl32(pb); + uint64_t size = avio_rb64(pb); + uint64_t orig_pos = avio_tell(pb); + const char * metadata_tag = NULL; + + switch(tag) { + case MKTAG('D','I','A','R'): metadata_tag = "artist"; break; + case MKTAG('D','I','T','I'): metadata_tag = "title"; break; + } + + if (metadata_tag && size > 4) { + unsigned int tag_size = avio_rb32(pb); + int ret = get_metadata(s, metadata_tag, FFMIN(tag_size, size - 4)); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); + return ret; + } + } + + avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); + } + + return 0; +} + +static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) +{ + AVIOContext *pb = s->pb; + char abss[24]; + int hour, min, sec, i, ret, config; + int dsd_layout[6]; + ID3v2ExtraMeta *id3v2_extra_meta; + + while (avio_tell(pb) + 12 <= eof) { + uint32_t tag = avio_rl32(pb); + uint64_t size = avio_rb64(pb); + uint64_t orig_pos = avio_tell(pb); + + switch(tag) { + case MKTAG('A','B','S','S'): + if (size < 8) + return AVERROR_INVALIDDATA; + hour = avio_rb16(pb); + min = avio_r8(pb); + sec = avio_r8(pb); + snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb)); + av_dict_set(&st->metadata, "absolute_start_time", abss, 0); + break; + + case MKTAG('C','H','N','L'): + if (size < 2) + return AVERROR_INVALIDDATA; + st->codec->channels = avio_rb16(pb); + if (size < 2 + st->codec->channels * 4) + return AVERROR_INVALIDDATA; + st->codec->channel_layout = 0; + if (st->codec->channels > FF_ARRAY_ELEMS(dsd_layout)) { + avpriv_request_sample(s, "channel layout"); + break; + } + for (i = 0; i < st->codec->channels; i++) + dsd_layout[i] = avio_rl32(pb); + for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) { + const DSDLayoutDesc * d = &dsd_channel_layout[i]; + if (av_get_channel_layout_nb_channels(d->layout) == st->codec->channels && + !memcmp(d->dsd_layout, dsd_layout, st->codec->channels * sizeof(uint32_t))) { + st->codec->channel_layout = d->layout; + break; + } + } + break; + + case MKTAG('C','M','P','R'): + if (size < 4) + return AVERROR_INVALIDDATA; + st->codec->codec_id = ff_codec_get_id(dsd_codec_tags, avio_rl32(pb)); + break; + + case MKTAG('F','S',' ',' '): + if (size < 4) + return AVERROR_INVALIDDATA; + st->codec->sample_rate = avio_rb32(pb) / 8; + break; + + case MKTAG('I','D','3',' '): + 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) { + ff_id3v2_free_extra_meta(&id3v2_extra_meta); + return ret; + } + ff_id3v2_free_extra_meta(&id3v2_extra_meta); + } + + if (size < avio_tell(pb) - orig_pos) { + av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n"); + return AVERROR_INVALIDDATA; + } + break; + + case MKTAG('L','S','C','O'): + if (size < 2) + return AVERROR_INVALIDDATA; + config = avio_rb16(pb); + if (config != 0xFFFF) { + if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config)) + st->codec->channel_layout = dsd_loudspeaker_config[config]; + if (!st->codec->channel_layout) + avpriv_request_sample(s, "loudspeaker configuration %d", config); + } + break; + } + + avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); + } + + return 0; +} + static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8}; @@ -157,7 +340,8 @@ static int iff_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; AVStream *st; uint8_t *buf; - uint32_t chunk_id, data_size; + uint32_t chunk_id; + uint64_t data_size; uint32_t screenmode = 0, num, den; unsigned transparency = 0; unsigned masking = 0; // no mask @@ -170,7 +354,8 @@ static int iff_read_header(AVFormatContext *s) st->codec->channels = 1; st->codec->channel_layout = AV_CH_LAYOUT_MONO; - avio_skip(pb, 8); + iff->is_64bit = avio_rl32(pb) == ID_FRM8; + avio_skip(pb, iff->is_64bit ? 8 : 4); // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content st->codec->codec_tag = avio_rl32(pb); iff->bitmap_compression = -1; @@ -182,8 +367,9 @@ static int iff_read_header(AVFormatContext *s) uint64_t orig_pos; int res; const char *metadata_tag = NULL; + int version, nb_comments, i; chunk_id = avio_rl32(pb); - data_size = avio_rb32(pb); + data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); orig_pos = avio_tell(pb); switch(chunk_id) { @@ -225,6 +411,7 @@ static int iff_read_header(AVFormatContext *s) case ID_ABIT: case ID_BODY: case ID_DBOD: + case ID_DSD: case ID_MDAT: iff->body_pos = avio_tell(pb); iff->body_end = iff->body_pos + data_size; @@ -251,7 +438,7 @@ static int iff_read_header(AVFormatContext *s) case ID_CMAP: if (data_size < 3 || data_size > 768 || data_size % 3) { - av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %d\n", + av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n", data_size); return AVERROR_INVALIDDATA; } @@ -338,6 +525,84 @@ static int iff_read_header(AVFormatContext *s) case ID_AUTH: metadata_tag = "artist"; break; case ID_COPYRIGHT: metadata_tag = "copyright"; break; case ID_NAME: metadata_tag = "title"; break; + + /* DSD tags */ + + case MKTAG('F','V','E','R'): + if (data_size < 4) + return AVERROR_INVALIDDATA; + version = avio_rb32(pb); + av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF); + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + break; + + case MKTAG('D','I','I','N'): + res = parse_dsd_diin(s, st, orig_pos + data_size); + if (res < 0) + return res; + break; + + case MKTAG('P','R','O','P'): + if (data_size < 4) + return AVERROR_INVALIDDATA; + if (avio_rl32(pb) != MKTAG('S','N','D',' ')) { + avpriv_request_sample(s, "unknown property type"); + break; + } + res = parse_dsd_prop(s, st, orig_pos + data_size); + if (res < 0) + return res; + break; + + case MKTAG('C','O','M','T'): + if (data_size < 2) + return AVERROR_INVALIDDATA; + nb_comments = avio_rb16(pb); + for (i = 0; i < nb_comments; i++) { + int year, mon, day, hour, min, type, ref; + char tmp[24]; + const char *tag; + int metadata_size; + + year = avio_rb16(pb); + mon = avio_r8(pb); + day = avio_r8(pb); + hour = avio_r8(pb); + min = avio_r8(pb); + snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min); + av_dict_set(&st->metadata, "comment_time", tmp, 0); + + type = avio_rb16(pb); + ref = avio_rb16(pb); + switch (type) { + case 1: + if (!i) + tag = "channel_comment"; + else { + snprintf(tmp, sizeof(tmp), "channel%d_comment", ref); + tag = tmp; + } + break; + case 2: + tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_history_comment[ref] : "source_comment"; + break; + case 3: + tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history"; + break; + default: + tag = "comment"; + } + + metadata_size = avio_rb32(pb); + if ((res = get_metadata(s, tag, metadata_size)) < 0) { + av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag); + return res; + } + + if (metadata_size & 1) + avio_skip(pb, 1); + } + break; } if (metadata_tag) { @@ -370,28 +635,22 @@ static int iff_read_header(AVFormatContext *s) avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits); return AVERROR_PATCHWELCOME; } - - st->codec->bits_per_coded_sample = - av_get_bits_per_sample(st->codec->codec_id); - - st->codec->block_align = - st->codec->bits_per_coded_sample * st->codec->channels / 8; - } else { - switch (iff->svx8_compression) { - case COMP_NONE: - st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; - break; - case COMP_FIB: - st->codec->codec_id = AV_CODEC_ID_8SVX_FIB; - break; - case COMP_EXP: - st->codec->codec_id = AV_CODEC_ID_8SVX_EXP; - break; - default: - av_log(s, AV_LOG_ERROR, - "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); - return -1; - } + } else if (st->codec->codec_tag != ID_DSD) { + switch (iff->svx8_compression) { + case COMP_NONE: + st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; + break; + case COMP_FIB: + st->codec->codec_id = AV_CODEC_ID_8SVX_FIB; + break; + case COMP_EXP: + st->codec->codec_id = AV_CODEC_ID_8SVX_EXP; + break; + default: + av_log(s, AV_LOG_ERROR, + "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); + return -1; + } } st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id); @@ -447,7 +706,7 @@ static int iff_read_packet(AVFormatContext *s, return AVERROR_EOF; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if (st->codec->codec_tag == ID_MAUD) { + if (st->codec->codec_tag == ID_DSD || st->codec->codec_tag == ID_MAUD) { ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * st->codec->block_align)); } else { ret = av_get_packet(pb, pkt, iff->body_size); @@ -462,6 +721,10 @@ static int iff_read_packet(AVFormatContext *s, buf = pkt->data; bytestream_put_be16(&buf, 2); ret = avio_read(pb, buf, iff->body_size); + if (ret<0) { + av_free_packet(pkt); + } else if (ret < iff->body_size) + av_shrink_packet(pkt, ret + 2); } else { av_assert0(0); } diff --git a/chromium/third_party/ffmpeg/libavformat/img2.c b/chromium/third_party/ffmpeg/libavformat/img2.c index 7539359540e..80020549f63 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2.c +++ b/chromium/third_party/ffmpeg/libavformat/img2.c @@ -32,6 +32,7 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_MJPEG, "jpeg" }, { AV_CODEC_ID_MJPEG, "jpg" }, { AV_CODEC_ID_MJPEG, "jps" }, + { AV_CODEC_ID_MJPEG, "mpo" }, { AV_CODEC_ID_LJPEG, "ljpg" }, { AV_CODEC_ID_JPEGLS, "jls" }, { AV_CODEC_ID_PNG, "png" }, @@ -43,6 +44,7 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_PGMYUV, "pgmyuv" }, { AV_CODEC_ID_PBM, "pbm" }, { AV_CODEC_ID_PAM, "pam" }, + { AV_CODEC_ID_ALIAS_PIX, "pix" }, { AV_CODEC_ID_MPEG1VIDEO, "mpg1-img" }, { AV_CODEC_ID_MPEG2VIDEO, "mpg2-img" }, { AV_CODEC_ID_MPEG4, "mpg4-img" }, @@ -55,8 +57,8 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_TIFF, "tif" }, { AV_CODEC_ID_SGI, "sgi" }, { AV_CODEC_ID_PTX, "ptx" }, + { AV_CODEC_ID_BRENDER_PIX,"pix" }, { AV_CODEC_ID_PCX, "pcx" }, - { AV_CODEC_ID_BRENDER_PIX, "pix" }, { AV_CODEC_ID_SUNRAST, "sun" }, { AV_CODEC_ID_SUNRAST, "ras" }, { AV_CODEC_ID_SUNRAST, "rs" }, diff --git a/chromium/third_party/ffmpeg/libavformat/img2.h b/chromium/third_party/ffmpeg/libavformat/img2.h new file mode 100644 index 00000000000..dc53c5cc510 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/img2.h @@ -0,0 +1,61 @@ +/* + * Image format + * Copyright (c) 2014 Michael Niedermayer + * + * 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_IMG2_H +#define AVFORMAT_IMG2_H + +#include <stdint.h> +#include "avformat.h" + +#if HAVE_GLOB +#include <glob.h> +#endif + +typedef struct { + const AVClass *class; /**< Class for private options. */ + int img_first; + int img_last; + int img_number; + int64_t pts; + int img_count; + int is_pipe; + int split_planes; /**< use independent file for each Y, U, V plane */ + char path[1024]; + char *pixel_format; /**< Set by a private option. */ + int width, height; /**< Set by a private option. */ + AVRational framerate; /**< Set by a private option. */ + int loop; + enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type; + int use_glob; +#if HAVE_GLOB + glob_t globstate; +#endif + int start_number; + int start_number_range; + int frame_size; + int ts_from_file; +} VideoDemuxData; + +int ff_img_read_header(AVFormatContext *s1); + +int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt); + +#endif diff --git a/chromium/third_party/ffmpeg/libavformat/img2_alias_pix.c b/chromium/third_party/ffmpeg/libavformat/img2_alias_pix.c new file mode 100644 index 00000000000..a3d5cfa0c4b --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/img2_alias_pix.c @@ -0,0 +1,65 @@ +/* + * Alias PIX image demuxer + * Copyright (c) 2014 Michael Niedermayer + * + * 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 "img2.h" +#include "libavcodec/bytestream.h" + +static int brender_read_probe(AVProbeData *p) +{ + const uint8_t *b = p->buf; + const uint8_t *end = b + p->buf_size; + int width = bytestream_get_be16(&b); + int height = bytestream_get_be16(&b); + av_unused int ox = bytestream_get_be16(&b); + av_unused int oy = bytestream_get_be16(&b); + int bpp = bytestream_get_be16(&b); + int x, y; + + if (!width || !height) + return 0; + + if (bpp != 24 && bpp != 8) + return 0; + + for (y=0; y<2 && y<height; y++) { + for (x=0; x<width; ) { + int count = *b++; + if (count == 0 || x + count > width) + return 0; + if (b > end) + return AVPROBE_SCORE_MAX / 8; + b += bpp / 8; + x += count; + } + } + + return AVPROBE_SCORE_EXTENSION + 1; +} + +AVInputFormat ff_image2_alias_pix_demuxer = { + .name = "alias_pix", + .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), + .priv_data_size = sizeof(VideoDemuxData), + .read_probe = brender_read_probe, + .read_header = ff_img_read_header, + .read_packet = ff_img_read_packet, + .raw_codec_id = AV_CODEC_ID_ALIAS_PIX, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/img2_brender_pix.c b/chromium/third_party/ffmpeg/libavformat/img2_brender_pix.c new file mode 100644 index 00000000000..f7306267c4b --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/img2_brender_pix.c @@ -0,0 +1,49 @@ +/* + * BRender PIX image demuxer + * Copyright (c) 2014 Michael Niedermayer + * + * 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 "img2.h" +#include "libavutil/intreadwrite.h" + +static int aliaspix_read_probe(AVProbeData *p) +{ + static const uint8_t brender_magic[16] = { + 0,0,0,0x12,0,0,0,8,0,0,0,2,0,0,0,2 + }; + + if (memcmp(p->buf, brender_magic, sizeof(brender_magic))) + return 0; + + if (AV_RB32(p->buf+16) != 0x03 && + AV_RB32(p->buf+16) != 0x3D) + return 0; + + return AVPROBE_SCORE_MAX-10; +} + +AVInputFormat ff_image2_brender_pix_demuxer = { + .name = "brender_pix", + .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"), + .priv_data_size = sizeof(VideoDemuxData), + .read_probe = aliaspix_read_probe, + .read_header = ff_img_read_header, + .read_packet = ff_img_read_packet, + .raw_codec_id = AV_CODEC_ID_BRENDER_PIX, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/img2dec.c b/chromium/third_party/ffmpeg/libavformat/img2dec.c index 5163e69f65b..dc962dbb33a 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/img2dec.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _BSD_SOURCE #include <sys/stat.h> #include "libavutil/avstring.h" #include "libavutil/log.h" @@ -28,9 +29,9 @@ #include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" -#if HAVE_GLOB -#include <glob.h> +#include "img2.h" +#if HAVE_GLOB /* Locally define as 0 (bitwise-OR no-op) any missing glob options that are non-posix glibc/bsd extensions. */ #ifndef GLOB_NOMAGIC @@ -42,31 +43,6 @@ #endif /* HAVE_GLOB */ -typedef struct { - const AVClass *class; /**< Class for private options. */ - int img_first; - int img_last; - int img_number; - int64_t pts; - int img_count; - int is_pipe; - int split_planes; /**< use independent file for each Y, U, V plane */ - char path[1024]; - char *pixel_format; /**< Set by a private option. */ - int width, height; /**< Set by a private option. */ - AVRational framerate; /**< Set by a private option. */ - int loop; - enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type; - int use_glob; -#if HAVE_GLOB - glob_t globstate; -#endif - int start_number; - int start_number_range; - int frame_size; - int ts_from_file; -} VideoDemuxData; - static const int sizes[][2] = { { 640, 480 }, { 720, 480 }, @@ -192,7 +168,7 @@ static int img_read_probe(AVProbeData *p) return 0; } -static int img_read_header(AVFormatContext *s1) +int ff_img_read_header(AVFormatContext *s1) { VideoDemuxData *s = s1->priv_data; int first_index, last_index; @@ -225,7 +201,13 @@ static int img_read_header(AVFormatContext *s1) st->need_parsing = AVSTREAM_PARSE_FULL; } - if (s->ts_from_file) + if (s->ts_from_file == 2) { +#if !HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + av_log(s1, AV_LOG_ERROR, "POSIX.1-2008 not supported, nanosecond file timestamps unavailable\n"); + return AVERROR(ENOSYS); +#endif + avpriv_set_pts_info(st, 64, 1, 1000000000); + } else if (s->ts_from_file) avpriv_set_pts_info(st, 64, 1, 1); else avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num); @@ -313,6 +295,9 @@ static int img_read_header(AVFormatContext *s1) } else if (s1->audio_codec_id) { st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = s1->audio_codec_id; + } else if (s1->iformat->raw_codec_id) { + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = s1->iformat->raw_codec_id; } else { const char *str = strrchr(s->path, '.'); s->split_planes = str && !av_strcasecmp(str + 1, "y"); @@ -320,6 +305,8 @@ static int img_read_header(AVFormatContext *s1) st->codec->codec_id = ff_guess_image2_codec(s->path); if (st->codec->codec_id == AV_CODEC_ID_LJPEG) st->codec->codec_id = AV_CODEC_ID_MJPEG; + if (st->codec->codec_id == AV_CODEC_ID_ALIAS_PIX) // we cannot distingiush this from BRENDER_PIX + st->codec->codec_id = AV_CODEC_ID_NONE; } if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pix_fmt != AV_PIX_FMT_NONE) @@ -328,7 +315,7 @@ static int img_read_header(AVFormatContext *s1) return 0; } -static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) +int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt) { VideoDemuxData *s = s1->priv_data; char filename_bytes[1024]; @@ -371,6 +358,27 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) filename[strlen(filename) - 1] = 'U' + i; } + if (codec->codec_id == AV_CODEC_ID_NONE) { + AVProbeData pd; + AVInputFormat *ifmt; + uint8_t header[PROBE_BUF_MIN + AVPROBE_PADDING_SIZE]; + int ret; + int score = 0; + + ret = avio_read(f[0], header, PROBE_BUF_MIN); + if (ret < 0) + return ret; + memset(header + ret, 0, sizeof(header) - ret); + avio_skip(f[0], -ret); + pd.buf = header; + pd.buf_size = ret; + pd.filename = filename; + + ifmt = av_probe_input_format3(&pd, 1, &score); + if (ifmt && ifmt->read_packet == ff_img_read_packet && ifmt->raw_codec_id) + codec->codec_id = ifmt->raw_codec_id; + } + if (codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->width) infer_size(&codec->width, &codec->height, size[0]); } else { @@ -393,6 +401,10 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) if (stat(filename, &img_stat)) return AVERROR(EIO); pkt->pts = (int64_t)img_stat.st_mtime; +#if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + if (s->ts_from_file == 2) + pkt->pts = 1000000000*pkt->pts + img_stat.st_mtim.tv_nsec; +#endif av_add_index_entry(s1->streams[0], s->img_number, pkt->pts, 0, 0, AVINDEX_KEYFRAME); } else if (!s->is_pipe) { pkt->pts = s->pts; @@ -467,7 +479,10 @@ static const AVOption options[] = { { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC }, { "video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, { "frame_size", "force frame size in bytes", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC }, - { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC }, + { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "ts_type" }, + { "none", "none", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 2, DEC, "ts_type" }, + { "sec", "second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 2, DEC, "ts_type" }, + { "ns", "nano second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 2, DEC, "ts_type" }, { NULL }, }; @@ -483,8 +498,8 @@ AVInputFormat ff_image2_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), .priv_data_size = sizeof(VideoDemuxData), .read_probe = img_read_probe, - .read_header = img_read_header, - .read_packet = img_read_packet, + .read_header = ff_img_read_header, + .read_packet = ff_img_read_packet, .read_close = img_read_close, .read_seek = img_read_seek, .flags = AVFMT_NOFILE, @@ -502,8 +517,8 @@ AVInputFormat ff_image2pipe_demuxer = { .name = "image2pipe", .long_name = NULL_IF_CONFIG_SMALL("piped image2 sequence"), .priv_data_size = sizeof(VideoDemuxData), - .read_header = img_read_header, - .read_packet = img_read_packet, + .read_header = ff_img_read_header, + .read_packet = ff_img_read_packet, .priv_class = &img2pipe_class, }; #endif diff --git a/chromium/third_party/ffmpeg/libavformat/img2enc.c b/chromium/third_party/ffmpeg/libavformat/img2enc.c index 3529e12c55b..37dfbecce31 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2enc.c +++ b/chromium/third_party/ffmpeg/libavformat/img2enc.c @@ -194,7 +194,7 @@ AVOutputFormat ff_image2_muxer = { .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), .extensions = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png," "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24," - "sunras,xbm,xface", + "sunras,webp,xbm,xface,pix,y", .priv_data_size = sizeof(VideoMuxData), .video_codec = AV_CODEC_ID_MJPEG, .write_header = write_header, diff --git a/chromium/third_party/ffmpeg/libavformat/internal.h b/chromium/third_party/ffmpeg/libavformat/internal.h index edc6a11685c..66fb5d64af2 100644 --- a/chromium/third_party/ffmpeg/libavformat/internal.h +++ b/chromium/third_party/ffmpeg/libavformat/internal.h @@ -28,7 +28,7 @@ /** size of probe buffer, for guessing file type from file contents */ #define PROBE_BUF_MIN 2048 -#define PROBE_BUF_MAX (1<<20) +#define PROBE_BUF_MAX (1 << 20) #ifdef DEBUG # define hex_dump_debug(class, buf, size) av_hex_dump_log(class, AV_LOG_DEBUG, buf, size) @@ -46,6 +46,16 @@ typedef struct CodecMime{ enum AVCodecID id; } CodecMime; +struct AVFormatInternal { + /** + * Number of streams relevant for interleaving. + * Muxing only. + */ + int nb_interleaved_streams; + + int inject_global_side_data; +}; + #ifdef __GNUC__ #define dynarray_add(tab, nb_ptr, elem)\ do {\ @@ -350,11 +360,11 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags); /** * Chooses a timebase for muxing the specified stream. * - * The choosen timebase allows sample accurate timestamps based + * The chosen timebase allows sample accurate timestamps based * on the framerate or sample rate for audio streams. It also is - * at least as precisse as 1/min_precission would be. + * at least as precise as 1/min_precision would be. */ -AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission); +AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precision); /** * Generate standard extradata for AVC-Intra based on width/height and field @@ -372,6 +382,15 @@ int ff_generate_avci_extradata(AVStream *st); int ff_alloc_extradata(AVCodecContext *avctx, int size); /** + * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end + * which is always set to 0 and fill it from pb. + * + * @param size size of extradata + * @return >= 0 if OK, AVERROR_xxx on error + */ +int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size); + +/** * add frame for rfps calculation. * * @param dts timestamp of the i-th frame @@ -381,4 +400,18 @@ int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts); void ff_rfps_calculate(AVFormatContext *ic); +/** + * Flags for AVFormatContext.write_uncoded_frame() + */ +enum AVWriteUncodedFrameFlags { + + /** + * Query whether the feature is possible on this stream. + * The frame argument is ignored. + */ + AV_WRITE_UNCODED_FRAME_QUERY = 0x0001, + +}; + + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/ipmovie.c b/chromium/third_party/ffmpeg/libavformat/ipmovie.c index 368c05922da..4a766ef3bac 100644 --- a/chromium/third_party/ffmpeg/libavformat/ipmovie.c +++ b/chromium/third_party/ffmpeg/libavformat/ipmovie.c @@ -321,7 +321,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_CREATE_TIMER: av_dlog(NULL, "create timer\n"); - if ((opcode_version > 0) || (opcode_size > 6)) { + if ((opcode_version > 0) || (opcode_size != 6)) { av_dlog(NULL, "bad create_timer opcode\n"); chunk_type = CHUNK_BAD; break; @@ -339,7 +339,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_INIT_AUDIO_BUFFERS: av_dlog(NULL, "initialize audio buffers\n"); - if ((opcode_version > 1) || (opcode_size > 10)) { + if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) { av_dlog(NULL, "bad init_audio_buffers opcode\n"); chunk_type = CHUNK_BAD; break; @@ -376,7 +376,9 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_INIT_VIDEO_BUFFERS: av_dlog(NULL, "initialize video buffers\n"); - if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4) { + if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4 + || opcode_version == 2 && opcode_size < 8 + ) { av_dlog(NULL, "bad init_video_buffers opcode\n"); chunk_type = CHUNK_BAD; break; @@ -449,8 +451,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, av_dlog(NULL, "set palette\n"); /* check for the logical maximum palette size * (3 * 256 + 4 bytes) */ - if (opcode_size > 0x304) { - av_dlog(NULL, "demux_ipmovie: set_palette opcode too large\n"); + if (opcode_size > 0x304 || opcode_size < 4) { + av_dlog(NULL, "demux_ipmovie: set_palette opcode with invalid size\n"); chunk_type = CHUNK_BAD; break; } @@ -463,7 +465,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, first_color = AV_RL16(&scratch[0]); last_color = first_color + AV_RL16(&scratch[2]) - 1; /* sanity check (since they are 16 bit values) */ - if ((first_color > 0xFF) || (last_color > 0xFF)) { + if ( (first_color > 0xFF) || (last_color > 0xFF) + || (last_color - first_color + 1)*3 + 4 > opcode_size) { av_dlog(NULL, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", first_color, last_color); chunk_type = CHUNK_BAD; diff --git a/chromium/third_party/ffmpeg/libavformat/isom.c b/chromium/third_party/ffmpeg/libavformat/isom.c index de9d20ccab2..b34398b4f3c 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.c +++ b/chromium/third_party/ffmpeg/libavformat/isom.c @@ -26,6 +26,8 @@ #include "isom.h" #include "libavcodec/mpeg4audio.h" #include "libavcodec/mpegaudiodata.h" +#include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" /* http://www.mp4ra.org */ /* ordered by muxing preference */ @@ -33,6 +35,7 @@ const AVCodecTag ff_mp4_obj_type[] = { { AV_CODEC_ID_MOV_TEXT , 0x08 }, { AV_CODEC_ID_MPEG4 , 0x20 }, { AV_CODEC_ID_H264 , 0x21 }, + { AV_CODEC_ID_HEVC , 0x23 }, { AV_CODEC_ID_AAC , 0x40 }, { AV_CODEC_ID_MP4ALS , 0x40 }, /* 14496-3 ALS */ { AV_CODEC_ID_MPEG2VIDEO , 0x61 }, /* MPEG2 Main */ @@ -80,7 +83,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('b', '1', '6', 'g') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('b', '4', '8', 'r') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'b', 'g') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'b', 'g') }, /* BOXX */ { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'r', 'g') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('b', 'x', 'y', 'v') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'O', '1', '6') }, @@ -151,8 +154,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('W', 'R', 'A', 'W') }, - { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* HEVC/H.265 which indicates parameter sets may be in ES */ + { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'p') }, /* AVC-Intra 50M 720p24/30/60 */ @@ -167,12 +170,12 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '3') }, /* AVC-Intra 100M 1080p24/30/60 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '5') }, /* AVC-Intra 100M 1080i50 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '6') }, /* AVC-Intra 100M 1080i60 */ - { AV_CODEC_ID_H264, MKTAG('a', 'i', 'v', 'x') }, /* XAVC 4:2:2 10bit */ { AV_CODEC_ID_H264, MKTAG('A', 'V', 'i', 'n') }, /* AVC-Intra with implicit SPS/PPS */ + { AV_CODEC_ID_H264, MKTAG('a', 'i', 'v', 'x') }, /* XAVC 4:2:2 10bit */ + { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */ - { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', '2', 'v', '1') }, /* Apple MPEG-2 Camcorder */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '1') }, /* MPEG2 HDV 720p30 */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 HDV 1080i60 */ @@ -218,6 +221,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', 'h', 'd') }, /* XDCAM HD 540p */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', 'h', '2') }, /* XDCAM HD422 540p */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('A', 'V', 'm', 'p') }, /* AVID IMX PAL */ + { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '2', 'v') }, /* FCP5 */ { AV_CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, /* JPEG 2000 produced by FCP */ @@ -299,7 +303,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = { { AV_CODEC_ID_QDM2, MKTAG('Q', 'D', 'M', '2') }, { AV_CODEC_ID_QDMC, MKTAG('Q', 'D', 'M', 'C') }, { AV_CODEC_ID_SPEEX, MKTAG('s', 'p', 'e', 'x') }, /* Flash Media Server */ - { AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', 'N') }, + { AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', 'N') }, /* ZygoAudio (quality 10 mode) */ { AV_CODEC_ID_WMAV2, MKTAG('W', 'M', 'A', '2') }, { AV_CODEC_ID_EVRC, MKTAG('s', 'e', 'v', 'c') }, /* 3GPP2 */ { AV_CODEC_ID_SMV, MKTAG('s', 's', 'm', 'v') }, /* 3GPP2 */ @@ -438,6 +442,7 @@ static const AVCodecTag mp4_audio_types[] = { int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb) { int len, tag; + int ret; int object_type_id = avio_r8(pb); avio_r8(pb); /* stream type */ avio_rb24(pb); /* buffer size db */ @@ -457,11 +462,10 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext if (!len || (uint64_t)len > (1<<30)) return -1; av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, len)) - return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, len); + if ((ret = ff_get_extradata(st->codec, pb, len)) < 0) + return ret; if (st->codec->codec_id == AV_CODEC_ID_AAC) { - MPEG4AudioConfig cfg; + MPEG4AudioConfig cfg = {0}; avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, st->codec->extradata_size * 8, 1); st->codec->channels = cfg.channels; @@ -574,3 +578,12 @@ void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout) avio_wb32(pb, 0); // mNumberChannelDescriptions } +const struct AVCodecTag *avformat_get_mov_video_tags(void) +{ + return ff_codec_movvideo_tags; +} + +const struct AVCodecTag *avformat_get_mov_audio_tags(void) +{ + return ff_codec_movaudio_tags; +} diff --git a/chromium/third_party/ffmpeg/libavformat/isom.h b/chromium/third_party/ffmpeg/libavformat/isom.h index 2834b11b3e8..a929ebf05ef 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.h +++ b/chromium/third_party/ffmpeg/libavformat/isom.h @@ -142,6 +142,9 @@ typedef struct MOVStreamContext { int start_pad; ///< amount of samples to skip due to enc-dec delay unsigned int rap_group_count; MOVSbgp *rap_group; + + int nb_frames_for_fps; + int64_t duration_for_fps; } MOVStreamContext; typedef struct MOVContext { diff --git a/chromium/third_party/ffmpeg/libavformat/iss.c b/chromium/third_party/ffmpeg/libavformat/iss.c index e4335b4cbfb..e9945313d69 100644 --- a/chromium/third_party/ffmpeg/libavformat/iss.c +++ b/chromium/third_party/ffmpeg/libavformat/iss.c @@ -76,14 +76,23 @@ static av_cold int iss_read_header(AVFormatContext *s) get_token(pb, token, sizeof(token)); //"IMA_ADPCM_Sound" get_token(pb, token, sizeof(token)); //packet size - sscanf(token, "%d", &iss->packet_size); + if (sscanf(token, "%d", &iss->packet_size) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing packet size\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //File ID get_token(pb, token, sizeof(token)); //out size get_token(pb, token, sizeof(token)); //stereo - sscanf(token, "%d", &stereo); + if (sscanf(token, "%d", &stereo) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing stereo flag\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //Unknown1 get_token(pb, token, sizeof(token)); //RateDivisor - sscanf(token, "%d", &rate_divisor); + if (sscanf(token, "%d", &rate_divisor) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing rate_divisor\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //Unknown2 get_token(pb, token, sizeof(token)); //Version ID get_token(pb, token, sizeof(token)); //Size diff --git a/chromium/third_party/ffmpeg/libavformat/jvdec.c b/chromium/third_party/ffmpeg/libavformat/jvdec.c index 69ac8f27fd3..eab450d862b 100644 --- a/chromium/third_party/ffmpeg/libavformat/jvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/jvdec.c @@ -27,6 +27,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" + #include "avformat.h" #include "internal.h" @@ -59,6 +60,15 @@ static int read_probe(AVProbeData *pd) return 0; } +static int read_close(AVFormatContext *s) +{ + JVDemuxContext *jv = s->priv_data; + + av_freep(&jv->frames); + + return 0; +} + static int read_header(AVFormatContext *s) { JVDemuxContext *jv = s->priv_data; @@ -87,17 +97,18 @@ static int read_header(AVFormatContext *s) avio_skip(pb, 4); - ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->codec->codec_id = AV_CODEC_ID_PCM_U8; - ast->codec->codec_tag = 0; /* no fourcc */ - ast->codec->sample_rate = avio_rl16(pb); - ast->codec->channels = 1; + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + ast->codec->codec_id = AV_CODEC_ID_PCM_U8; + ast->codec->codec_tag = 0; /* no fourcc */ + ast->codec->sample_rate = avio_rl16(pb); + ast->codec->channels = 1; ast->codec->channel_layout = AV_CH_LAYOUT_MONO; avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate); avio_skip(pb, 10); - ast->index_entries = av_malloc(ast->nb_index_entries * sizeof(*ast->index_entries)); + ast->index_entries = av_malloc(ast->nb_index_entries * + sizeof(*ast->index_entries)); if (!ast->index_entries) return AVERROR(ENOMEM); @@ -106,28 +117,41 @@ static int read_header(AVFormatContext *s) return AVERROR(ENOMEM); offset = 0x68 + ast->nb_index_entries * 16; - for(i = 0; i < ast->nb_index_entries; i++) { + for (i = 0; i < ast->nb_index_entries; i++) { AVIndexEntry *e = ast->index_entries + i; JVFrame *jvf = jv->frames + i; /* total frame size including audio, video, palette data and padding */ - e->size = avio_rl32(pb); - e->timestamp = i; - e->pos = offset; - offset += e->size; + e->size = avio_rl32(pb); + e->timestamp = i; + e->pos = offset; + offset += e->size; - jvf->audio_size = avio_rl32(pb); - jvf->video_size = avio_rl32(pb); + jvf->audio_size = avio_rl32(pb); + jvf->video_size = avio_rl32(pb); jvf->palette_size = avio_r8(pb) ? 768 : 0; - jvf->video_size = FFMIN(FFMAX(jvf->video_size, 0), - INT_MAX - JV_PREAMBLE_SIZE - jvf->palette_size); + + if ((jvf->video_size | jvf->audio_size) & ~0xFFFFFF || + e->size - jvf->audio_size + - jvf->video_size + - jvf->palette_size < 0) { + if (s->error_recognition & AV_EF_EXPLODE) { + read_close(s); + return AVERROR_INVALIDDATA; + } + jvf->audio_size = + jvf->video_size = + jvf->palette_size = 0; + } + if (avio_r8(pb)) - av_log(s, AV_LOG_WARNING, "unsupported audio codec\n"); + av_log(s, AV_LOG_WARNING, "unsupported audio codec\n"); + jvf->video_type = avio_r8(pb); avio_skip(pb, 1); e->timestamp = jvf->audio_size ? audio_pts : AV_NOPTS_VALUE; - audio_pts += jvf->audio_size; + audio_pts += jvf->audio_size; e->flags = jvf->video_type != 1 ? AVINDEX_KEYFRAME : 0; } @@ -146,10 +170,10 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) const AVIndexEntry *e = ast->index_entries + jv->pts; const JVFrame *jvf = jv->frames + jv->pts; - switch(jv->state) { + switch (jv->state) { case JV_AUDIO: jv->state++; - if (jvf->audio_size ) { + if (jvf->audio_size) { if (av_get_packet(s->pb, pkt, jvf->audio_size) < 0) return AVERROR(ENOMEM); pkt->stream_index = 0; @@ -160,16 +184,22 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) case JV_VIDEO: jv->state++; if (jvf->video_size || jvf->palette_size) { + int ret; int size = jvf->video_size + jvf->palette_size; if (av_new_packet(pkt, size + JV_PREAMBLE_SIZE)) return AVERROR(ENOMEM); AV_WL32(pkt->data, jvf->video_size); - pkt->data[4] = jvf->video_type; - if ((size = avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size)) < 0) - return AVERROR(EIO); - - pkt->size = size + JV_PREAMBLE_SIZE; + pkt->data[4] = jvf->video_type; + ret = avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size); + if (ret < 0) + return ret; + if (ret < size) { + memset(pkt->data + JV_PREAMBLE_SIZE + ret, 0, + FF_INPUT_BUFFER_PADDING_SIZE); + pkt->flags |= AV_PKT_FLAG_CORRUPT; + } + pkt->size = ret + JV_PREAMBLE_SIZE; pkt->stream_index = 1; pkt->pts = jv->pts; if (jvf->video_type != 1) @@ -184,6 +214,9 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) } } + if (s->pb->eof_reached) + return AVERROR_EOF; + return AVERROR(EIO); } @@ -194,10 +227,10 @@ static int read_seek(AVFormatContext *s, int stream_index, AVStream *ast = s->streams[0]; int i; - if (flags & (AVSEEK_FLAG_BYTE|AVSEEK_FLAG_FRAME)) + if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) return AVERROR(ENOSYS); - switch(stream_index) { + switch (stream_index) { case 0: i = av_index_search_timestamp(ast, ts, flags); break; @@ -218,15 +251,6 @@ static int read_seek(AVFormatContext *s, int stream_index, return 0; } -static int read_close(AVFormatContext *s) -{ - JVDemuxContext *jv = s->priv_data; - - av_freep(&jv->frames); - - return 0; -} - AVInputFormat ff_jv_demuxer = { .name = "jv", .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"), diff --git a/chromium/third_party/ffmpeg/libavformat/libmodplug.c b/chromium/third_party/ffmpeg/libavformat/libmodplug.c index 836b7c2ec06..3f00dbf2a42 100644 --- a/chromium/third_party/ffmpeg/libavformat/libmodplug.c +++ b/chromium/third_party/ffmpeg/libavformat/libmodplug.c @@ -22,6 +22,7 @@ * @todo better probing than extensions matching */ +#define MODPLUG_STATIC #include <libmodplug/modplug.h> #include "libavutil/avstring.h" #include "libavutil/eval.h" diff --git a/chromium/third_party/ffmpeg/libavformat/libnut.c b/chromium/third_party/ffmpeg/libavformat/libnut.c index be8f3cb283e..4a9a21a7668 100644 --- a/chromium/third_party/ffmpeg/libavformat/libnut.c +++ b/chromium/third_party/ffmpeg/libavformat/libnut.c @@ -70,7 +70,7 @@ static int nut_write_header(AVFormatContext * avf) { nut_stream_header_tt * s; int i; - priv->s = s = av_mallocz((avf->nb_streams + 1) * sizeof*s); + priv->s = s = av_mallocz_array(avf->nb_streams + 1, sizeof*s); if(!s) return AVERROR(ENOMEM); diff --git a/chromium/third_party/ffmpeg/libavformat/librtmp.c b/chromium/third_party/ffmpeg/libavformat/librtmp.c index 5b4c39dde5c..5172c5148ab 100644 --- a/chromium/third_party/ffmpeg/libavformat/librtmp.c +++ b/chromium/third_party/ffmpeg/libavformat/librtmp.c @@ -37,7 +37,16 @@ typedef struct LibRTMPContext { const AVClass *class; RTMP rtmp; char *app; + char *conn; + char *subscribe; char *playpath; + char *tcurl; + char *flashver; + char *swfurl; + char *swfverify; + char *pageurl; + char *client_buffer_time; + int live; } LibRTMPContext; static void rtmp_log(int level, const char *fmt, va_list args) @@ -83,6 +92,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) RTMP *r = &ctx->rtmp; int rc = 0, level; char *filename = s->filename; + int len = strlen(s->filename) + 1; switch (av_log_get_level()) { default: @@ -96,22 +106,111 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) RTMP_LogSetLevel(level); RTMP_LogSetCallback(rtmp_log); - if (ctx->app || ctx->playpath) { - int len = strlen(s->filename) + 1; - if (ctx->app) len += strlen(ctx->app) + sizeof(" app="); - if (ctx->playpath) len += strlen(ctx->playpath) + sizeof(" playpath="); + if (ctx->app) len += strlen(ctx->app) + sizeof(" app="); + if (ctx->tcurl) len += strlen(ctx->tcurl) + sizeof(" tcUrl="); + if (ctx->pageurl) len += strlen(ctx->pageurl) + sizeof(" pageUrl="); + if (ctx->flashver) len += strlen(ctx->flashver) + sizeof(" flashver="); + + if (ctx->conn) { + char *sep, *p = ctx->conn; + int options = 0; + + while (p) { + options++; + p += strspn(p, " "); + if (!*p) + break; + sep = strchr(p, ' '); + if (sep) + p = sep + 1; + else + break; + } + len += options * sizeof(" conn="); + len += strlen(ctx->conn); + } + + if (ctx->playpath) + len += strlen(ctx->playpath) + sizeof(" playpath="); + if (ctx->live) + len += sizeof(" live=1"); + if (ctx->subscribe) + len += strlen(ctx->subscribe) + sizeof(" subscribe="); - if (!(filename = av_malloc(len))) - return AVERROR(ENOMEM); + if (ctx->client_buffer_time) + len += strlen(ctx->client_buffer_time) + sizeof(" buffer="); - av_strlcpy(filename, s->filename, len); - if (ctx->app) { - av_strlcat(filename, " app=", len); - av_strlcat(filename, ctx->app, len); + if (ctx->swfurl || ctx->swfverify) { + len += sizeof(" swfUrl="); + + if (ctx->swfverify) + len += strlen(ctx->swfverify) + sizeof(" swfVfy=1"); + else + len += strlen(ctx->swfurl); + } + + if (!(filename = av_malloc(len))) + return AVERROR(ENOMEM); + + av_strlcpy(filename, s->filename, len); + if (ctx->app) { + av_strlcat(filename, " app=", len); + av_strlcat(filename, ctx->app, len); + } + if (ctx->tcurl) { + av_strlcat(filename, " tcUrl=", len); + av_strlcat(filename, ctx->tcurl, len); + } + if (ctx->pageurl) { + av_strlcat(filename, " pageUrl=", len); + av_strlcat(filename, ctx->pageurl, len); + } + if (ctx->swfurl) { + av_strlcat(filename, " swfUrl=", len); + av_strlcat(filename, ctx->pageurl, len); + } + if (ctx->flashver) { + av_strlcat(filename, " flashVer=", len); + av_strlcat(filename, ctx->flashver, len); + } + if (ctx->conn) { + char *sep, *p = ctx->conn; + while (p) { + av_strlcat(filename, " conn=", len); + p += strspn(p, " "); + if (!*p) + break; + sep = strchr(p, ' '); + if (sep) + *sep = '\0'; + av_strlcat(filename, p, len); + + if (sep) + p = sep + 1; } - if (ctx->playpath) { - av_strlcat(filename, " playpath=", len); - av_strlcat(filename, ctx->playpath, len); + } + if (ctx->playpath) { + av_strlcat(filename, " playpath=", len); + av_strlcat(filename, ctx->playpath, len); + } + if (ctx->live) + av_strlcat(filename, " live=1", len); + if (ctx->subscribe) { + av_strlcat(filename, " subscribe=", len); + av_strlcat(filename, ctx->subscribe, len); + } + if (ctx->client_buffer_time) { + av_strlcat(filename, " buffer=", len); + av_strlcat(filename, ctx->client_buffer_time, len); + } + if (ctx->swfurl || ctx->swfverify) { + av_strlcat(filename, " swfUrl=", len); + + if (ctx->swfverify) { + av_strlcat(filename, ctx->swfverify, len); + av_strlcat(filename, " swfVfy=1", len); + } else { + av_strlcat(filename, ctx->swfurl, len); } } @@ -134,6 +233,9 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) fail: if (filename != s->filename) av_freep(&filename); + if (rc) + RTMP_Close(r); + return rc; } @@ -194,8 +296,20 @@ static int rtmp_get_file_handle(URLContext *s) #define DEC AV_OPT_FLAG_DECODING_PARAM #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, - {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_STRING, {.str = "3000"}, 0, 0, DEC|ENC}, + {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_live"}, + {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"}, + {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"}, + {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"}, + {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, + {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, + {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically. (unimplemented)", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, + {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/libssh.c b/chromium/third_party/ffmpeg/libavformat/libssh.c index 4a9b8674cf4..b20e93bbab9 100644 --- a/chromium/third_party/ffmpeg/libavformat/libssh.c +++ b/chromium/third_party/ffmpeg/libavformat/libssh.c @@ -19,9 +19,11 @@ */ #include <fcntl.h> +#define LIBSSH_STATIC #include <libssh/sftp.h> #include "libavutil/avstring.h" #include "libavutil/opt.h" +#include "libavutil/attributes.h" #include "avformat.h" #include "internal.h" #include "url.h" @@ -34,106 +36,179 @@ typedef struct { int64_t filesize; int rw_timeout; int trunc; + char *priv_key; } LIBSSHContext; -static int libssh_close(URLContext *h) +static av_cold int libssh_create_ssh_session(LIBSSHContext *libssh, const char* hostname, unsigned int port) { - LIBSSHContext *s = h->priv_data; - if (s->file) - sftp_close(s->file); - if (s->sftp) - sftp_free(s->sftp); - if (s->session) { - ssh_disconnect(s->session); - ssh_free(s->session); + static const int verbosity = SSH_LOG_NOLOG; + + if (!(libssh->session = ssh_new())) { + av_log(libssh, AV_LOG_ERROR, "SSH session creation failed: %s\n", ssh_get_error(libssh->session)); + return AVERROR(ENOMEM); + } + ssh_options_set(libssh->session, SSH_OPTIONS_HOST, hostname); + ssh_options_set(libssh->session, SSH_OPTIONS_PORT, &port); + ssh_options_set(libssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + if (libssh->rw_timeout > 0) { + long timeout = libssh->rw_timeout * 1000; + ssh_options_set(libssh->session, SSH_OPTIONS_TIMEOUT_USEC, &timeout); + } + + if (ssh_connect(libssh->session) != SSH_OK) { + av_log(libssh, AV_LOG_ERROR, "Connection failed: %s\n", ssh_get_error(libssh->session)); + return AVERROR(EIO); } + return 0; } -static int libssh_open(URLContext *h, const char *url, int flags) +static av_cold int libssh_authentication(LIBSSHContext *libssh, const char *user, const char *password) { - static const int verbosity = SSH_LOG_NOLOG; - LIBSSHContext *s = h->priv_data; - char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024]; - int port = 22, access, ret; - long timeout = s->rw_timeout * 1000; - const char *user = NULL, *pass = NULL; - char *end = NULL; - sftp_attributes stat; + int authorized = 0; + int auth_methods; - av_url_split(proto, sizeof(proto), - credencials, sizeof(credencials), - hostname, sizeof(hostname), - &port, - path, sizeof(path), - url); + if (user) + ssh_options_set(libssh->session, SSH_OPTIONS_USER, user); - if (port <= 0 || port > 65535) - port = 22; + auth_methods = ssh_userauth_list(libssh->session, NULL); - if (!(s->session = ssh_new())) { - ret = AVERROR(ENOMEM); - goto fail; + if (auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { + if (libssh->priv_key) { + ssh_string pub_key; + ssh_private_key priv_key; + int type; + if (!ssh_try_publickey_from_file(libssh->session, libssh->priv_key, &pub_key, &type)) { + priv_key = privatekey_from_file(libssh->session, libssh->priv_key, type, password); + if (ssh_userauth_pubkey(libssh->session, NULL, pub_key, priv_key) == SSH_AUTH_SUCCESS) { + av_log(libssh, AV_LOG_DEBUG, "Authentication successful with selected private key.\n"); + authorized = 1; + } + } else { + av_log(libssh, AV_LOG_DEBUG, "Invalid key is provided.\n"); + return AVERROR(EACCES); + } + } else if (ssh_userauth_autopubkey(libssh->session, password) == SSH_AUTH_SUCCESS) { + av_log(libssh, AV_LOG_DEBUG, "Authentication successful with auto selected key.\n"); + authorized = 1; + } } - user = av_strtok(credencials, ":", &end); - pass = av_strtok(end, ":", &end); - ssh_options_set(s->session, SSH_OPTIONS_HOST, hostname); - ssh_options_set(s->session, SSH_OPTIONS_PORT, &port); - ssh_options_set(s->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); - if (timeout > 0) - ssh_options_set(s->session, SSH_OPTIONS_TIMEOUT_USEC, &timeout); - if (user) - ssh_options_set(s->session, SSH_OPTIONS_USER, user); - if (ssh_connect(s->session) != SSH_OK) { - av_log(h, AV_LOG_ERROR, "Connection failed. %s\n", ssh_get_error(s->session)); - ret = AVERROR(EIO); - goto fail; + if (!authorized && (auth_methods & SSH_AUTH_METHOD_PASSWORD)) { + if (ssh_userauth_password(libssh->session, NULL, password) == SSH_AUTH_SUCCESS) { + av_log(libssh, AV_LOG_DEBUG, "Authentication successful with password.\n"); + authorized = 1; + } } - if (pass && ssh_userauth_password(s->session, NULL, pass) != SSH_AUTH_SUCCESS) { - av_log(h, AV_LOG_ERROR, "Error authenticating with password: %s\n", ssh_get_error(s->session)); - ret = AVERROR(EACCES); - goto fail; + if (!authorized) { + av_log(libssh, AV_LOG_ERROR, "Authentication failed.\n"); + return AVERROR(EACCES); } - if (!(s->sftp = sftp_new(s->session))) { - av_log(h, AV_LOG_ERROR, "SFTP session creation failed: %s\n", ssh_get_error(s->session)); - ret = AVERROR(ENOMEM); - goto fail; + return 0; +} + +static av_cold int libssh_create_sftp_session(LIBSSHContext *libssh) +{ + if (!(libssh->sftp = sftp_new(libssh->session))) { + av_log(libssh, AV_LOG_ERROR, "SFTP session creation failed: %s\n", ssh_get_error(libssh->session)); + return AVERROR(ENOMEM); } - if (sftp_init(s->sftp) != SSH_OK) { - av_log(h, AV_LOG_ERROR, "Error initializing sftp session: %s\n", ssh_get_error(s->session)); - ret = AVERROR(EIO); - goto fail; + if (sftp_init(libssh->sftp) != SSH_OK) { + av_log(libssh, AV_LOG_ERROR, "Error initializing sftp session: %s\n", ssh_get_error(libssh->session)); + return AVERROR(EIO); } + return 0; +} + +static av_cold int libssh_open_file(LIBSSHContext *libssh, int flags, const char *file) +{ + int access; + if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) { access = O_CREAT | O_RDWR; - if (s->trunc) + if (libssh->trunc) access |= O_TRUNC; } else if (flags & AVIO_FLAG_WRITE) { access = O_CREAT | O_WRONLY; - if (s->trunc) + if (libssh->trunc) access |= O_TRUNC; - } else { + } else access = O_RDONLY; - } - if (!(s->file = sftp_open(s->sftp, path, access, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH))) { - av_log(h, AV_LOG_ERROR, "Error opening sftp file: %s\n", ssh_get_error(s->session)); - ret = AVERROR(EIO); - goto fail; + /* 0666 = -rw-rw-rw- = read+write for everyone, minus umask */ + if (!(libssh->file = sftp_open(libssh->sftp, file, access, 0666))) { + av_log(libssh, AV_LOG_ERROR, "Error opening sftp file: %s\n", ssh_get_error(libssh->session)); + return AVERROR(EIO); } - if (!(stat = sftp_fstat(s->file))) { - av_log(h, AV_LOG_WARNING, "Cannot stat remote file %s.\n", path); - s->filesize = -1; + return 0; +} + +static av_cold void libssh_stat_file(LIBSSHContext *libssh) +{ + sftp_attributes stat; + + if (!(stat = sftp_fstat(libssh->file))) { + av_log(libssh, AV_LOG_WARNING, "Cannot stat remote file.\n"); + libssh->filesize = -1; } else { - s->filesize = stat->size; + libssh->filesize = stat->size; sftp_attributes_free(stat); } +} + +static av_cold int libssh_close(URLContext *h) +{ + LIBSSHContext *libssh = h->priv_data; + if (libssh->file) + sftp_close(libssh->file); + if (libssh->sftp) + sftp_free(libssh->sftp); + if (libssh->session) { + ssh_disconnect(libssh->session); + ssh_free(libssh->session); + } + return 0; +} + +static av_cold int libssh_open(URLContext *h, const char *url, int flags) +{ + LIBSSHContext *libssh = h->priv_data; + char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024]; + int port = 22, ret; + const char *user = NULL, *pass = NULL; + char *end = NULL; + + av_url_split(proto, sizeof(proto), + credencials, sizeof(credencials), + hostname, sizeof(hostname), + &port, + path, sizeof(path), + url); + + if (port <= 0 || port > 65535) + port = 22; + + if ((ret = libssh_create_ssh_session(libssh, hostname, port)) < 0) + goto fail; + + user = av_strtok(credencials, ":", &end); + pass = av_strtok(end, ":", &end); + + if ((ret = libssh_authentication(libssh, user, pass)) < 0) + goto fail; + + if ((ret = libssh_create_sftp_session(libssh)) < 0) + goto fail; + + if ((ret = libssh_open_file(libssh, flags, path)) < 0) + goto fail; + + libssh_stat_file(libssh); return 0; @@ -144,31 +219,36 @@ static int libssh_open(URLContext *h, const char *url, int flags) static int64_t libssh_seek(URLContext *h, int64_t pos, int whence) { - LIBSSHContext *s = h->priv_data; + LIBSSHContext *libssh = h->priv_data; int64_t newpos; - if (s->filesize == -1 && (whence == AVSEEK_SIZE || whence == SEEK_END)) { + if (libssh->filesize == -1 && (whence == AVSEEK_SIZE || whence == SEEK_END)) { av_log(h, AV_LOG_ERROR, "Error during seeking.\n"); return AVERROR(EIO); } switch(whence) { case AVSEEK_SIZE: - return s->filesize; + return libssh->filesize; case SEEK_SET: newpos = pos; break; case SEEK_CUR: - newpos = sftp_tell64(s->file); + newpos = sftp_tell64(libssh->file) + pos; break; case SEEK_END: - newpos = s->filesize + pos; + newpos = libssh->filesize + pos; break; default: return AVERROR(EINVAL); } - if (sftp_seek64(s->file, newpos)) { + if (newpos < 0) { + av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n"); + return AVERROR(EINVAL); + } + + if (sftp_seek64(libssh->file, newpos)) { av_log(h, AV_LOG_ERROR, "Error during seeking.\n"); return AVERROR(EIO); } @@ -178,11 +258,11 @@ static int64_t libssh_seek(URLContext *h, int64_t pos, int whence) static int libssh_read(URLContext *h, unsigned char *buf, int size) { - LIBSSHContext *s = h->priv_data; + LIBSSHContext *libssh = h->priv_data; int bytes_read; - if ((bytes_read = sftp_read(s->file, buf, size)) < 0) { - av_log(h, AV_LOG_ERROR, "Read error.\n"); + if ((bytes_read = sftp_read(libssh->file, buf, size)) < 0) { + av_log(libssh, AV_LOG_ERROR, "Read error.\n"); return AVERROR(EIO); } return bytes_read; @@ -190,11 +270,11 @@ static int libssh_read(URLContext *h, unsigned char *buf, int size) static int libssh_write(URLContext *h, const unsigned char *buf, int size) { - LIBSSHContext *s = h->priv_data; + LIBSSHContext *libssh = h->priv_data; int bytes_written; - if ((bytes_written = sftp_write(s->file, buf, size)) < 0) { - av_log(h, AV_LOG_ERROR, "Write error.\n"); + if ((bytes_written = sftp_write(libssh->file, buf, size)) < 0) { + av_log(libssh, AV_LOG_ERROR, "Write error.\n"); return AVERROR(EIO); } return bytes_written; @@ -206,6 +286,7 @@ static int libssh_write(URLContext *h, const unsigned char *buf, int size) static const AVOption options[] = { {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, {"truncate", "Truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E }, + {"private_key", "set path to private key", OFFSET(priv_key), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D|E }, {NULL} }; diff --git a/chromium/third_party/ffmpeg/libavformat/loasdec.c b/chromium/third_party/ffmpeg/libavformat/loasdec.c index 05ef0fe3ad5..c41809be006 100644 --- a/chromium/third_party/ffmpeg/libavformat/loasdec.c +++ b/chromium/third_party/ffmpeg/libavformat/loasdec.c @@ -25,6 +25,8 @@ #include "internal.h" #include "rawdec.h" +#define LOAS_SYNC_WORD 0x2b7 + static int loas_probe(AVProbeData *p) { int max_frames = 0, first_frames = 0; @@ -35,27 +37,32 @@ static int loas_probe(AVProbeData *p) const uint8_t *end = buf0 + p->buf_size - 3; buf = buf0; - for(; buf < end; buf= buf2+1) { + for (; buf < end; buf = buf2 + 1) { buf2 = buf; - for(frames = 0; buf2 < end; frames++) { + for (frames = 0; buf2 < end; frames++) { uint32_t header = AV_RB24(buf2); - if((header >> 13) != 0x2B7) + if ((header >> 13) != LOAS_SYNC_WORD) break; fsize = (header & 0x1FFF) + 3; - if(fsize < 7) + if (fsize < 7) break; fsize = FFMIN(fsize, end - buf2); buf2 += fsize; } max_frames = FFMAX(max_frames, frames); - if(buf == buf0) - first_frames= frames; + if (buf == buf0) + first_frames = frames; } - if (first_frames>=3) return AVPROBE_SCORE_EXTENSION+1; - else if(max_frames>100)return AVPROBE_SCORE_EXTENSION; - else if(max_frames>=3) return AVPROBE_SCORE_EXTENSION / 2; - else return 0; + + if (first_frames >= 3) + return AVPROBE_SCORE_EXTENSION + 1; + else if (max_frames > 100) + return AVPROBE_SCORE_EXTENSION; + else if (max_frames >= 3) + return AVPROBE_SCORE_EXTENSION / 2; + else + return 0; } static int loas_read_header(AVFormatContext *s) diff --git a/chromium/third_party/ffmpeg/libavformat/lxfdec.c b/chromium/third_party/ffmpeg/libavformat/lxfdec.c index f0a96396b46..19f7f27385a 100644 --- a/chromium/third_party/ffmpeg/libavformat/lxfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/lxfdec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/intreadwrite.h" #include "libavcodec/bytestream.h" #include "avformat.h" @@ -128,12 +130,12 @@ static int get_packet_header(AVFormatContext *s) version = bytestream_get_le32(&p); header_size = bytestream_get_le32(&p); if (version > 1) - avpriv_request_sample(s, "Unknown format version %i\n", version); + avpriv_request_sample(s, "Unknown format version %"PRIu32"\n", version); if (header_size < (version ? 72 : 60) || header_size > LXF_MAX_PACKET_HEADER_SIZE || (header_size & 3)) { - av_log(s, AV_LOG_ERROR, "Invalid header size 0x%x\n", header_size); + av_log(s, AV_LOG_ERROR, "Invalid header size 0x%"PRIx32"\n", header_size); return AVERROR_INVALIDDATA; } @@ -301,7 +303,8 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) stream = lxf->packet_type; if (stream > 1) { - av_log(s, AV_LOG_WARNING, "got packet with illegal stream index %u\n", stream); + av_log(s, AV_LOG_WARNING, + "got packet with illegal stream index %"PRIu32"\n", stream); return AVERROR(EAGAIN); } diff --git a/chromium/third_party/ffmpeg/libavformat/matroska.c b/chromium/third_party/ffmpeg/libavformat/matroska.c index 77a88a8756c..d281ef4fd53 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroska.c +++ b/chromium/third_party/ffmpeg/libavformat/matroska.c @@ -35,7 +35,7 @@ const CodecTags ff_mkv_codec_tags[]={ {"A_MPEG/L2" , AV_CODEC_ID_MP2}, {"A_MPEG/L1" , AV_CODEC_ID_MP2}, {"A_MPEG/L3" , AV_CODEC_ID_MP3}, - {"A_OPUS", AV_CODEC_ID_OPUS}, + {"A_OPUS" , AV_CODEC_ID_OPUS}, {"A_OPUS/EXPERIMENTAL",AV_CODEC_ID_OPUS}, {"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F32LE}, {"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F64LE}, @@ -113,6 +113,7 @@ const CodecMime ff_mkv_mime_tags[] = { {"application/x-truetype-font", AV_CODEC_ID_TTF}, {"application/x-font" , AV_CODEC_ID_TTF}, {"application/vnd.ms-opentype", AV_CODEC_ID_OTF}, + {"binary" , AV_CODEC_ID_BIN_DATA}, {"" , AV_CODEC_ID_NONE} }; diff --git a/chromium/third_party/ffmpeg/libavformat/matroskadec.c b/chromium/third_party/ffmpeg/libavformat/matroskadec.c index cedb3452a51..dcbdd2f5246 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskadec.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskadec.c @@ -28,33 +28,38 @@ * @see specs available on the Matroska project page: http://www.matroska.org/ */ +#include "config.h" + +#include <inttypes.h> #include <stdio.h> +#if CONFIG_BZLIB +#include <bzlib.h> +#endif +#if CONFIG_ZLIB +#include <zlib.h> +#endif + +#include "libavutil/avstring.h" +#include "libavutil/base64.h" +#include "libavutil/dict.h" +#include "libavutil/intfloat.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/lzo.h" +#include "libavutil/mathematics.h" + +#include "libavcodec/bytestream.h" +#include "libavcodec/mpeg4audio.h" + #include "avformat.h" -#include "internal.h" #include "avio_internal.h" +#include "internal.h" +#include "isom.h" +#include "matroska.h" /* For ff_codec_get_id(). */ #include "riff.h" -#include "isom.h" #if CONFIG_SIPR_DECODER #include "rmsipr.h" #endif -#include "matroska.h" -#include "libavcodec/bytestream.h" -#include "libavcodec/mpeg4audio.h" -#include "libavutil/base64.h" -#include "libavutil/intfloat.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/avstring.h" -#if CONFIG_LZO -#include "libavutil/lzo.h" -#endif -#include "libavutil/dict.h" -#if CONFIG_ZLIB -#include <zlib.h> -#endif -#if CONFIG_BZLIB -#include <bzlib.h> -#endif static int matroska_read_close(AVFormatContext *s); @@ -170,12 +175,12 @@ typedef struct { uint64_t default_duration; uint64_t flag_default; uint64_t flag_forced; - uint64_t codec_delay; uint64_t seek_preroll; MatroskaTrackVideo video; MatroskaTrackAudio audio; MatroskaTrackOperation operation; EbmlList encodings; + uint64_t codec_delay; AVStream *stream; int64_t end_timecode; @@ -190,7 +195,7 @@ typedef struct { EbmlBin bin; AVStream *stream; -} MatroskaAttachement; +} MatroskaAttachment; typedef struct { uint64_t start; @@ -259,6 +264,7 @@ typedef struct { uint64_t time_scale; double duration; char *title; + char *muxingapp; EbmlBin date_utc; EbmlList tracks; EbmlList attachments; @@ -303,67 +309,67 @@ typedef struct { } MatroskaBlock; static EbmlSyntax ebml_header[] = { - { EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml,version), {.u=EBML_VERSION} }, - { EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml,max_size), {.u=8} }, - { EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml,id_length), {.u=4} }, - { EBML_ID_DOCTYPE, EBML_STR, 0, offsetof(Ebml,doctype), {.s="(none)"} }, - { EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, offsetof(Ebml,doctype_version), {.u=1} }, - { EBML_ID_EBMLVERSION, EBML_NONE }, - { EBML_ID_DOCTYPEVERSION, EBML_NONE }, + { EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml, version), { .u = EBML_VERSION } }, + { EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml, max_size), { .u = 8 } }, + { EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml, id_length), { .u = 4 } }, + { EBML_ID_DOCTYPE, EBML_STR, 0, offsetof(Ebml, doctype), { .s = "(none)" } }, + { EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, offsetof(Ebml, doctype_version), { .u = 1 } }, + { EBML_ID_EBMLVERSION, EBML_NONE }, + { EBML_ID_DOCTYPEVERSION, EBML_NONE }, { 0 } }; static EbmlSyntax ebml_syntax[] = { - { EBML_ID_HEADER, EBML_NEST, 0, 0, {.n=ebml_header} }, + { EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = ebml_header } }, { 0 } }; static EbmlSyntax matroska_info[] = { - { MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, offsetof(MatroskaDemuxContext,time_scale), {.u=1000000} }, - { MATROSKA_ID_DURATION, EBML_FLOAT, 0, offsetof(MatroskaDemuxContext,duration) }, - { MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext,title) }, - { MATROSKA_ID_WRITINGAPP, EBML_NONE }, - { MATROSKA_ID_MUXINGAPP, EBML_NONE }, - { MATROSKA_ID_DATEUTC, EBML_BIN, 0, offsetof(MatroskaDemuxContext,date_utc) }, - { MATROSKA_ID_SEGMENTUID, EBML_NONE }, + { MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, offsetof(MatroskaDemuxContext, time_scale), { .u = 1000000 } }, + { MATROSKA_ID_DURATION, EBML_FLOAT, 0, offsetof(MatroskaDemuxContext, duration) }, + { MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, title) }, + { MATROSKA_ID_WRITINGAPP, EBML_NONE }, + { MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, muxingapp) }, + { MATROSKA_ID_DATEUTC, EBML_BIN, 0, offsetof(MatroskaDemuxContext, date_utc) }, + { MATROSKA_ID_SEGMENTUID, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_track_video[] = { - { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT,0, offsetof(MatroskaTrackVideo,frame_rate) }, - { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_width), {.u=-1} }, - { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height), {.u=-1} }, - { MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) }, - { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) }, - { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo,color_space) }, - { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) }, - { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,alpha_mode) }, - { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE }, - { MATROSKA_ID_VIDEODISPLAYUNIT, EBML_NONE }, - { MATROSKA_ID_VIDEOFLAGINTERLACED,EBML_NONE }, - { MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE }, + { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, offsetof(MatroskaTrackVideo, frame_rate) }, + { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width), { .u=-1 } }, + { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_height), { .u=-1 } }, + { MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, pixel_width) }, + { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, pixel_height) }, + { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo, color_space) }, + { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, stereo_mode) }, + { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, alpha_mode) }, + { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, + { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, + { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, + { MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE }, + { MATROSKA_ID_VIDEODISPLAYUNIT, EBML_NONE }, + { MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_NONE }, + { MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_track_audio[] = { - { MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT,0, offsetof(MatroskaTrackAudio,samplerate), {.f=8000.0} }, - { MATROSKA_ID_AUDIOOUTSAMPLINGFREQ,EBML_FLOAT,0,offsetof(MatroskaTrackAudio,out_samplerate) }, - { MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio,bitdepth) }, - { MATROSKA_ID_AUDIOCHANNELS, EBML_UINT, 0, offsetof(MatroskaTrackAudio,channels), {.u=1} }, + { MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, samplerate), { .f = 8000.0 } }, + { MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, out_samplerate) }, + { MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio, bitdepth) }, + { MATROSKA_ID_AUDIOCHANNELS, EBML_UINT, 0, offsetof(MatroskaTrackAudio, channels), { .u = 1 } }, { 0 } }; static EbmlSyntax matroska_track_encoding_compression[] = { - { MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, offsetof(MatroskaTrackCompression,algo), {.u=0} }, - { MATROSKA_ID_ENCODINGCOMPSETTINGS,EBML_BIN, 0, offsetof(MatroskaTrackCompression,settings) }, + { MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, offsetof(MatroskaTrackCompression, algo), { .u = 0 } }, + { MATROSKA_ID_ENCODINGCOMPSETTINGS, EBML_BIN, 0, offsetof(MatroskaTrackCompression, settings) }, { 0 } }; static EbmlSyntax matroska_track_encoding_encryption[] = { - { MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, offsetof(MatroskaTrackEncryption,algo), {.u=0} }, + { MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, offsetof(MatroskaTrackEncryption,algo), {.u = 0} }, { MATROSKA_ID_ENCODINGENCKEYID, EBML_BIN, 0, offsetof(MatroskaTrackEncryption,key_id) }, { MATROSKA_ID_ENCODINGENCAESSETTINGS, EBML_NONE }, { MATROSKA_ID_ENCODINGSIGALGO, EBML_NONE }, @@ -373,16 +379,16 @@ static EbmlSyntax matroska_track_encoding_encryption[] = { { 0 } }; static EbmlSyntax matroska_track_encoding[] = { - { MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding,scope), {.u=1} }, - { MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding,type), {.u=0} }, - { MATROSKA_ID_ENCODINGCOMPRESSION,EBML_NEST, 0, offsetof(MatroskaTrackEncoding,compression), {.n=matroska_track_encoding_compression} }, - { MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding,encryption), {.n=matroska_track_encoding_encryption} }, - { MATROSKA_ID_ENCODINGORDER, EBML_NONE }, + { MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, scope), { .u = 1 } }, + { MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, type), { .u = 0 } }, + { MATROSKA_ID_ENCODINGCOMPRESSION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, compression), { .n = matroska_track_encoding_compression } }, + { MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, encryption), { .n = matroska_track_encoding_encryption } }, + { MATROSKA_ID_ENCODINGORDER, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_track_encodings[] = { - { MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack,encodings), {.n=matroska_track_encoding} }, + { MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack, encodings), { .n = matroska_track_encoding } }, { 0 } }; @@ -393,75 +399,75 @@ static EbmlSyntax matroska_track_plane[] = { }; static EbmlSyntax matroska_track_combine_planes[] = { - { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n=matroska_track_plane} }, + { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n = matroska_track_plane} }, { 0 } }; static EbmlSyntax matroska_track_operation[] = { - { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n=matroska_track_combine_planes} }, + { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = matroska_track_combine_planes} }, { 0 } }; static EbmlSyntax matroska_track[] = { - { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack,num) }, - { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack,name) }, - { MATROSKA_ID_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTrack,uid) }, - { MATROSKA_ID_TRACKTYPE, EBML_UINT, 0, offsetof(MatroskaTrack,type) }, - { MATROSKA_ID_CODECID, EBML_STR, 0, offsetof(MatroskaTrack,codec_id) }, - { MATROSKA_ID_CODECPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrack,codec_priv) }, - { MATROSKA_ID_TRACKLANGUAGE, EBML_UTF8, 0, offsetof(MatroskaTrack,language), {.s="eng"} }, - { MATROSKA_ID_TRACKDEFAULTDURATION, EBML_UINT, 0, offsetof(MatroskaTrack,default_duration) }, - { MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT,0, offsetof(MatroskaTrack,time_scale), {.f=1.0} }, - { MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTrack,flag_default), {.u=1} }, - { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack,flag_forced), {.u=0} }, - { MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, offsetof(MatroskaTrack,video), {.n=matroska_track_video} }, - { MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, offsetof(MatroskaTrack,audio), {.n=matroska_track_audio} }, - { MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, offsetof(MatroskaTrack,operation), {.n=matroska_track_operation} }, - { MATROSKA_ID_TRACKCONTENTENCODINGS,EBML_NEST, 0, 0, {.n=matroska_track_encodings} }, - { MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, offsetof(MatroskaTrack,max_block_additional_id) }, - { MATROSKA_ID_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack,codec_delay) }, - { MATROSKA_ID_SEEKPREROLL, EBML_UINT, 0, offsetof(MatroskaTrack,seek_preroll) }, - { MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE }, - { MATROSKA_ID_TRACKFLAGLACING, EBML_NONE }, - { MATROSKA_ID_CODECNAME, EBML_NONE }, - { MATROSKA_ID_CODECDECODEALL, EBML_NONE }, - { MATROSKA_ID_CODECINFOURL, EBML_NONE }, - { MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE }, - { MATROSKA_ID_TRACKMINCACHE, EBML_NONE }, - { MATROSKA_ID_TRACKMAXCACHE, EBML_NONE }, + { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack, num) }, + { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack, name) }, + { MATROSKA_ID_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTrack, uid) }, + { MATROSKA_ID_TRACKTYPE, EBML_UINT, 0, offsetof(MatroskaTrack, type) }, + { MATROSKA_ID_CODECID, EBML_STR, 0, offsetof(MatroskaTrack, codec_id) }, + { MATROSKA_ID_CODECPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrack, codec_priv) }, + { MATROSKA_ID_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack, codec_delay) }, + { MATROSKA_ID_TRACKLANGUAGE, EBML_UTF8, 0, offsetof(MatroskaTrack, language), { .s = "eng" } }, + { MATROSKA_ID_TRACKDEFAULTDURATION, EBML_UINT, 0, offsetof(MatroskaTrack, default_duration) }, + { MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, offsetof(MatroskaTrack, time_scale), { .f = 1.0 } }, + { MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTrack, flag_default), { .u = 1 } }, + { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack, flag_forced), { .u = 0 } }, + { MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, offsetof(MatroskaTrack, video), { .n = matroska_track_video } }, + { MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, offsetof(MatroskaTrack, audio), { .n = matroska_track_audio } }, + { MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, offsetof(MatroskaTrack, operation), { .n = matroska_track_operation } }, + { MATROSKA_ID_TRACKCONTENTENCODINGS, EBML_NEST, 0, 0, { .n = matroska_track_encodings } }, + { MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, offsetof(MatroskaTrack, max_block_additional_id) }, + { MATROSKA_ID_SEEKPREROLL, EBML_UINT, 0, offsetof(MatroskaTrack, seek_preroll) }, + { MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE }, + { MATROSKA_ID_TRACKFLAGLACING, EBML_NONE }, + { MATROSKA_ID_CODECNAME, EBML_NONE }, + { MATROSKA_ID_CODECDECODEALL, EBML_NONE }, + { MATROSKA_ID_CODECINFOURL, EBML_NONE }, + { MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE }, + { MATROSKA_ID_TRACKMINCACHE, EBML_NONE }, + { MATROSKA_ID_TRACKMAXCACHE, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_tracks[] = { - { MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext,tracks), {.n=matroska_track} }, + { MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext, tracks), { .n = matroska_track } }, { 0 } }; static EbmlSyntax matroska_attachment[] = { - { MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachement,uid) }, - { MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachement,filename) }, - { MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachement,mime) }, - { MATROSKA_ID_FILEDATA, EBML_BIN, 0, offsetof(MatroskaAttachement,bin) }, - { MATROSKA_ID_FILEDESC, EBML_NONE }, + { MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachment, uid) }, + { 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 }, { 0 } }; static EbmlSyntax matroska_attachments[] = { - { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachement), offsetof(MatroskaDemuxContext,attachments), {.n=matroska_attachment} }, + { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachment), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } }, { 0 } }; static EbmlSyntax matroska_chapter_display[] = { - { MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter,title) }, - { MATROSKA_ID_CHAPLANG, EBML_NONE }, + { MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter, title) }, + { MATROSKA_ID_CHAPLANG, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_chapter_entry[] = { - { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, offsetof(MatroskaChapter,start), {.u=AV_NOPTS_VALUE} }, - { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, offsetof(MatroskaChapter,end), {.u=AV_NOPTS_VALUE} }, - { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter,uid) }, - { MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, {.n=matroska_chapter_display} }, + { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } }, + { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } }, + { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter, uid) }, + { MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, { .n = matroska_chapter_display } }, { MATROSKA_ID_CHAPTERFLAGHIDDEN, EBML_NONE }, { MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE }, { MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE }, @@ -470,7 +476,7 @@ static EbmlSyntax matroska_chapter_entry[] = { }; static EbmlSyntax matroska_chapter[] = { - { MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext,chapters), {.n=matroska_chapter_entry} }, + { MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext, chapters), { .n = matroska_chapter_entry } }, { MATROSKA_ID_EDITIONUID, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_NONE }, @@ -479,13 +485,13 @@ static EbmlSyntax matroska_chapter[] = { }; static EbmlSyntax matroska_chapters[] = { - { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, {.n=matroska_chapter} }, + { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, { .n = matroska_chapter } }, { 0 } }; static EbmlSyntax matroska_index_pos[] = { - { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos,track) }, - { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos,pos) }, + { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos, track) }, + { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos, pos) }, { MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE }, { MATROSKA_ID_CUEDURATION, EBML_NONE }, { MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE }, @@ -493,71 +499,71 @@ static EbmlSyntax matroska_index_pos[] = { }; static EbmlSyntax matroska_index_entry[] = { - { MATROSKA_ID_CUETIME, EBML_UINT, 0, offsetof(MatroskaIndex,time) }, - { MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(MatroskaIndexPos), offsetof(MatroskaIndex,pos), {.n=matroska_index_pos} }, + { MATROSKA_ID_CUETIME, EBML_UINT, 0, offsetof(MatroskaIndex, time) }, + { MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(MatroskaIndexPos), offsetof(MatroskaIndex, pos), { .n = matroska_index_pos } }, { 0 } }; static EbmlSyntax matroska_index[] = { - { MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext,index), {.n=matroska_index_entry} }, + { MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext, index), { .n = matroska_index_entry } }, { 0 } }; static EbmlSyntax matroska_simpletag[] = { - { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag,name) }, - { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag,string) }, - { MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag,lang), {.s="und"} }, - { MATROSKA_ID_TAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTag,def) }, - { MATROSKA_ID_TAGDEFAULT_BUG, EBML_UINT, 0, offsetof(MatroskaTag,def) }, - { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTag,sub), {.n=matroska_simpletag} }, + { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag, name) }, + { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag, string) }, + { MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag, lang), { .s = "und" } }, + { MATROSKA_ID_TAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTag, def) }, + { MATROSKA_ID_TAGDEFAULT_BUG, EBML_UINT, 0, offsetof(MatroskaTag, def) }, + { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTag, sub), { .n = matroska_simpletag } }, { 0 } }; static EbmlSyntax matroska_tagtargets[] = { - { MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget,type) }, - { MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget,typevalue), {.u=50} }, - { MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget,trackuid) }, - { MATROSKA_ID_TAGTARGETS_CHAPTERUID,EBML_UINT, 0, offsetof(MatroskaTagTarget,chapteruid) }, - { MATROSKA_ID_TAGTARGETS_ATTACHUID, EBML_UINT, 0, offsetof(MatroskaTagTarget,attachuid) }, + { MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget, type) }, + { MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget, typevalue), { .u = 50 } }, + { MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, trackuid) }, + { MATROSKA_ID_TAGTARGETS_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, chapteruid) }, + { MATROSKA_ID_TAGTARGETS_ATTACHUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, attachuid) }, { 0 } }; static EbmlSyntax matroska_tag[] = { - { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags,tag), {.n=matroska_simpletag} }, - { MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags,target), {.n=matroska_tagtargets} }, + { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags, tag), { .n = matroska_simpletag } }, + { MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags, target), { .n = matroska_tagtargets } }, { 0 } }; static EbmlSyntax matroska_tags[] = { - { MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext,tags), {.n=matroska_tag} }, + { MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext, tags), { .n = matroska_tag } }, { 0 } }; static EbmlSyntax matroska_seekhead_entry[] = { - { MATROSKA_ID_SEEKID, EBML_UINT, 0, offsetof(MatroskaSeekhead,id) }, - { MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, offsetof(MatroskaSeekhead,pos), {.u=-1} }, + { MATROSKA_ID_SEEKID, EBML_UINT, 0, offsetof(MatroskaSeekhead, id) }, + { MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, offsetof(MatroskaSeekhead, pos), { .u = -1 } }, { 0 } }; static EbmlSyntax matroska_seekhead[] = { - { MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext,seekhead), {.n=matroska_seekhead_entry} }, + { MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext, seekhead), { .n = matroska_seekhead_entry } }, { 0 } }; static EbmlSyntax matroska_segment[] = { - { MATROSKA_ID_INFO, EBML_NEST, 0, 0, {.n=matroska_info } }, - { MATROSKA_ID_TRACKS, EBML_NEST, 0, 0, {.n=matroska_tracks } }, - { MATROSKA_ID_ATTACHMENTS, EBML_NEST, 0, 0, {.n=matroska_attachments} }, - { MATROSKA_ID_CHAPTERS, EBML_NEST, 0, 0, {.n=matroska_chapters } }, - { MATROSKA_ID_CUES, EBML_NEST, 0, 0, {.n=matroska_index } }, - { MATROSKA_ID_TAGS, EBML_NEST, 0, 0, {.n=matroska_tags } }, - { MATROSKA_ID_SEEKHEAD, EBML_NEST, 0, 0, {.n=matroska_seekhead } }, - { MATROSKA_ID_CLUSTER, EBML_STOP }, + { MATROSKA_ID_INFO, EBML_NEST, 0, 0, { .n = matroska_info } }, + { MATROSKA_ID_TRACKS, EBML_NEST, 0, 0, { .n = matroska_tracks } }, + { MATROSKA_ID_ATTACHMENTS, EBML_NEST, 0, 0, { .n = matroska_attachments } }, + { MATROSKA_ID_CHAPTERS, EBML_NEST, 0, 0, { .n = matroska_chapters } }, + { MATROSKA_ID_CUES, EBML_NEST, 0, 0, { .n = matroska_index } }, + { MATROSKA_ID_TAGS, EBML_NEST, 0, 0, { .n = matroska_tags } }, + { MATROSKA_ID_SEEKHEAD, EBML_NEST, 0, 0, { .n = matroska_seekhead } }, + { MATROSKA_ID_CLUSTER, EBML_STOP }, { 0 } }; static EbmlSyntax matroska_segments[] = { - { MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, {.n=matroska_segment } }, + { MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, { .n = matroska_segment } }, { 0 } }; @@ -568,69 +574,69 @@ static EbmlSyntax matroska_blockmore[] = { }; static EbmlSyntax matroska_blockadditions[] = { - { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n=matroska_blockmore} }, + { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = matroska_blockmore} }, { 0 } }; static EbmlSyntax matroska_blockgroup[] = { - { MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, - { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, {.n=matroska_blockadditions} }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, - { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration) }, - { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock,discard_padding) }, - { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock,reference) }, + { MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, + { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, { .n = matroska_blockadditions} }, + { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, + { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) }, + { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock, discard_padding) }, + { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference) }, { MATROSKA_ID_CODECSTATE, EBML_NONE }, - { 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} }, + { 1, EBML_UINT, 0, offsetof(MatroskaBlock, non_simple), { .u = 1 } }, { 0 } }; static EbmlSyntax matroska_cluster[] = { - { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, - { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, - { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, + { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, + { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, + { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, + { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, + { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_clusters[] = { - { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, {.n=matroska_cluster} }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, + { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster } }, + { MATROSKA_ID_INFO, EBML_NONE }, + { MATROSKA_ID_CUES, EBML_NONE }, + { MATROSKA_ID_TAGS, EBML_NONE }, + { MATROSKA_ID_SEEKHEAD, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_cluster_incremental_parsing[] = { - { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, - { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, - { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, - { MATROSKA_ID_CLUSTER, EBML_STOP }, + { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, + { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, + { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, + { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, + { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, + { MATROSKA_ID_INFO, EBML_NONE }, + { MATROSKA_ID_CUES, EBML_NONE }, + { MATROSKA_ID_TAGS, EBML_NONE }, + { MATROSKA_ID_SEEKHEAD, EBML_NONE }, + { MATROSKA_ID_CLUSTER, EBML_STOP }, { 0 } }; static EbmlSyntax matroska_cluster_incremental[] = { - { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_STOP }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_STOP }, - { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, - { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, + { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, + { MATROSKA_ID_BLOCKGROUP, EBML_STOP }, + { MATROSKA_ID_SIMPLEBLOCK, EBML_STOP }, + { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, + { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, { 0 } }; static EbmlSyntax matroska_clusters_incremental[] = { - { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, {.n=matroska_cluster_incremental} }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, + { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster_incremental } }, + { MATROSKA_ID_INFO, EBML_NONE }, + { MATROSKA_ID_CUES, EBML_NONE }, + { MATROSKA_ID_TAGS, EBML_NONE }, + { MATROSKA_ID_SEEKHEAD, EBML_NONE }, { 0 } }; @@ -655,11 +661,12 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS || id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) { - matroska->current_id = id; - return 0; + matroska->current_id = id; + return 0; } id = (id << 8) | avio_r8(pb); } + eof: matroska->done = 1; return AVERROR_EOF; @@ -795,13 +802,13 @@ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num) */ static int ebml_read_float(AVIOContext *pb, int size, double *num) { - if (size == 0) { + if (size == 0) *num = 0; - } else if (size == 4) { + else if (size == 4) *num = av_int2float(avio_rb32(pb)); - } else if (size == 8){ + else if (size == 8) *num = av_int2double(avio_rb64(pb)); - } else + else return AVERROR_INVALIDDATA; return 0; @@ -867,8 +874,8 @@ static int ebml_read_master(MatroskaDemuxContext *matroska, uint64_t length) return AVERROR(ENOSYS); } - level = &matroska->levels[matroska->num_levels++]; - level->start = avio_tell(pb); + level = &matroska->levels[matroska->num_levels++]; + level->start = avio_tell(pb); level->length = length; return 0; @@ -900,7 +907,7 @@ static int matroska_ebmlnum_sint(MatroskaDemuxContext *matroska, return res; /* make signed (weird way) */ - *num = unum - ((1LL << (7*res - 1)) - 1); + *num = unum - ((1LL << (7 * res - 1)) - 1); return res; } @@ -912,15 +919,15 @@ static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, uint32_t id, void *data) { int i; - for (i=0; syntax[i].id; i++) + for (i = 0; syntax[i].id; i++) if (id == syntax[i].id) break; if (!syntax[i].id && id == MATROSKA_ID_CLUSTER && - matroska->num_levels > 0 && - matroska->levels[matroska->num_levels-1].length == 0xffffffffffffff) + matroska->num_levels > 0 && + matroska->levels[matroska->num_levels - 1].length == 0xffffffffffffff) return 0; // we reached the end of an unknown size cluster if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) { - av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%X\n", id); + av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%"PRIX32"\n", id); if (matroska->ctx->error_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; } @@ -935,7 +942,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, int res = ebml_read_num(matroska, matroska->ctx->pb, 4, &id); if (res < 0) return res; - matroska->current_id = id | 1 << 7*res; + matroska->current_id = id | 1 << 7 * res; } return ebml_parse_id(matroska, syntax, matroska->current_id, data); } @@ -945,19 +952,19 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, { int i, res = 0; - for (i=0; syntax[i].id; i++) + for (i = 0; syntax[i].id; i++) switch (syntax[i].type) { case EBML_UINT: - *(uint64_t *)((char *)data+syntax[i].data_offset) = syntax[i].def.u; + *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; break; case EBML_FLOAT: - *(double *)((char *)data+syntax[i].data_offset) = syntax[i].def.f; + *(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f; break; case EBML_STR: case EBML_UTF8: // the default may be NULL if (syntax[i].def.s) { - uint8_t **dst = (uint8_t**)((uint8_t*)data + syntax[i].data_offset); + uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset); *dst = av_strdup(syntax[i].def.s); if (!*dst) return AVERROR(ENOMEM); @@ -990,14 +997,14 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, int res; void *newelem; - data = (char *)data + syntax->data_offset; + data = (char *) data + syntax->data_offset; if (syntax->list_elem_size) { EbmlList *list = data; - newelem = av_realloc_array(list->elem, list->nb_elem+1, syntax->list_elem_size); + newelem = av_realloc_array(list->elem, list->nb_elem + 1, syntax->list_elem_size); if (!newelem) return AVERROR(ENOMEM); list->elem = newelem; - data = (char*)list->elem + list->nb_elem*syntax->list_elem_size; + data = (char *) list->elem + list->nb_elem * syntax->list_elem_size; memset(data, 0, syntax->list_elem_size); list->nb_elem++; } @@ -1015,23 +1022,36 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, } switch (syntax->type) { - case EBML_UINT: res = ebml_read_uint (pb, length, data); break; - case EBML_SINT: res = ebml_read_sint (pb, length, data); break; - case EBML_FLOAT: res = ebml_read_float (pb, length, data); break; + case EBML_UINT: + res = ebml_read_uint(pb, length, data); + break; + case EBML_SINT: + res = ebml_read_sint(pb, length, data); + break; + case EBML_FLOAT: + res = ebml_read_float(pb, length, data); + break; case EBML_STR: - case EBML_UTF8: res = ebml_read_ascii (pb, length, data); break; - case EBML_BIN: res = ebml_read_binary(pb, length, data); break; - case EBML_NEST: if ((res=ebml_read_master(matroska, length)) < 0) - return res; - if (id == MATROSKA_ID_SEGMENT) - matroska->segment_start = avio_tell(matroska->ctx->pb); - return ebml_parse_nest(matroska, syntax->def.n, data); - case EBML_PASS: return ebml_parse_id(matroska, syntax->def.n, id, data); - case EBML_STOP: return 1; + case EBML_UTF8: + res = ebml_read_ascii(pb, length, data); + break; + case EBML_BIN: + res = ebml_read_binary(pb, length, data); + break; + case EBML_NEST: + if ((res = ebml_read_master(matroska, length)) < 0) + return res; + if (id == MATROSKA_ID_SEGMENT) + matroska->segment_start = avio_tell(matroska->ctx->pb); + return ebml_parse_nest(matroska, syntax->def.n, data); + case EBML_PASS: + return ebml_parse_id(matroska, syntax->def.n, id, data); + case EBML_STOP: + return 1; default: - if(ffio_limit(pb, length) != length) + if (ffio_limit(pb, length) != length) return AVERROR(EIO); - return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0; + return avio_skip(pb, length) < 0 ? AVERROR(EIO) : 0; } if (res == AVERROR_INVALIDDATA) av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n"); @@ -1043,27 +1063,32 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, static void ebml_free(EbmlSyntax *syntax, void *data) { int i, j; - for (i=0; syntax[i].id; i++) { - void *data_off = (char *)data + syntax[i].data_offset; + for (i = 0; syntax[i].id; i++) { + void *data_off = (char *) data + syntax[i].data_offset; switch (syntax[i].type) { case EBML_STR: - case EBML_UTF8: av_freep(data_off); break; - case EBML_BIN: av_freep(&((EbmlBin *)data_off)->data); break; + case EBML_UTF8: + av_freep(data_off); + break; + case EBML_BIN: + av_freep(&((EbmlBin *) data_off)->data); + break; case EBML_NEST: if (syntax[i].list_elem_size) { EbmlList *list = data_off; char *ptr = list->elem; - for (j=0; j<list->nb_elem; j++, ptr+=syntax[i].list_elem_size) + for (j = 0; j < list->nb_elem; + j++, ptr += syntax[i].list_elem_size) ebml_free(syntax[i].def.n, ptr); av_free(list->elem); } else ebml_free(syntax[i].def.n, data_off); - default: break; + default: + break; } } } - /* * Autodetecting... */ @@ -1083,14 +1108,14 @@ static int matroska_probe(AVProbeData *p) len_mask >>= 1; } if (size > 8) - return 0; + return 0; total &= (len_mask - 1); while (n < size) total = (total << 8) | p->buf[4 + n++]; /* Does the probe data contain the whole header? */ if (p->buf_size < 4 + size + total) - return 0; + return 0; /* The header should contain a known document type. For now, * we don't parse the whole header but simply check for the @@ -1100,8 +1125,8 @@ static int matroska_probe(AVProbeData *p) int probelen = strlen(matroska_doctypes[i]); if (total < probelen) continue; - for (n = 4+size; n <= 4+size+total-probelen; n++) - if (!memcmp(p->buf+n, matroska_doctypes[i], probelen)) + for (n = 4 + size; n <= 4 + size + total - probelen; n++) + if (!memcmp(p->buf + n, matroska_doctypes[i], probelen)) return AVPROBE_SCORE_MAX; } @@ -1115,7 +1140,7 @@ static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, MatroskaTrack *tracks = matroska->tracks.elem; int i; - for (i=0; i < matroska->tracks.nb_elem; i++) + for (i = 0; i < matroska->tracks.nb_elem; i++) if (tracks[i].num == num) return &tracks[i]; @@ -1123,13 +1148,13 @@ static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, return NULL; } -static int matroska_decode_buffer(uint8_t** buf, int* buf_size, +static int matroska_decode_buffer(uint8_t **buf, int *buf_size, MatroskaTrack *track) { MatroskaTrackEncoding *encodings = track->encodings.elem; - uint8_t* data = *buf; + uint8_t *data = *buf; int isize = *buf_size; - uint8_t* pkt_data = NULL; + uint8_t *pkt_data = NULL; uint8_t av_unused *newpktdata; int pkt_size = isize; int result = 0; @@ -1139,7 +1164,8 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, return AVERROR_INVALIDDATA; switch (encodings[0].compression.algo) { - case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP: { + case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP: + { int header_size = encodings[0].compression.settings.size; uint8_t *header = encodings[0].compression.settings.data; @@ -1163,15 +1189,15 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, #if CONFIG_LZO case MATROSKA_TRACK_ENCODING_COMP_LZO: do { - olen = pkt_size *= 3; + olen = pkt_size *= 3; newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING); if (!newpktdata) { result = AVERROR(ENOMEM); goto failed; } pkt_data = newpktdata; - result = av_lzo1x_decode(pkt_data, &olen, data, &isize); - } while (result==AV_LZO_OUTPUT_FULL && pkt_size<10000000); + result = av_lzo1x_decode(pkt_data, &olen, data, &isize); + } while (result == AV_LZO_OUTPUT_FULL && pkt_size < 10000000); if (result) { result = AVERROR_INVALIDDATA; goto failed; @@ -1180,27 +1206,28 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, break; #endif #if CONFIG_ZLIB - case MATROSKA_TRACK_ENCODING_COMP_ZLIB: { - z_stream zstream = {0}; + case MATROSKA_TRACK_ENCODING_COMP_ZLIB: + { + z_stream zstream = { 0 }; if (inflateInit(&zstream) != Z_OK) return -1; - zstream.next_in = data; + zstream.next_in = data; zstream.avail_in = isize; do { - pkt_size *= 3; + pkt_size *= 3; newpktdata = av_realloc(pkt_data, pkt_size); if (!newpktdata) { inflateEnd(&zstream); goto failed; } - pkt_data = newpktdata; + pkt_data = newpktdata; zstream.avail_out = pkt_size - zstream.total_out; - zstream.next_out = pkt_data + zstream.total_out; + zstream.next_out = pkt_data + zstream.total_out; if (pkt_data) { result = inflate(&zstream, Z_NO_FLUSH); } else result = Z_MEM_ERROR; - } while (result==Z_OK && pkt_size<10000000); + } while (result == Z_OK && pkt_size < 10000000); pkt_size = zstream.total_out; inflateEnd(&zstream); if (result != Z_STREAM_END) { @@ -1214,27 +1241,28 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, } #endif #if CONFIG_BZLIB - case MATROSKA_TRACK_ENCODING_COMP_BZLIB: { - bz_stream bzstream = {0}; + case MATROSKA_TRACK_ENCODING_COMP_BZLIB: + { + bz_stream bzstream = { 0 }; if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK) return -1; - bzstream.next_in = data; + bzstream.next_in = data; bzstream.avail_in = isize; do { - pkt_size *= 3; + pkt_size *= 3; newpktdata = av_realloc(pkt_data, pkt_size); if (!newpktdata) { BZ2_bzDecompressEnd(&bzstream); goto failed; } - pkt_data = newpktdata; + pkt_data = newpktdata; bzstream.avail_out = pkt_size - bzstream.total_out_lo32; - bzstream.next_out = pkt_data + bzstream.total_out_lo32; + bzstream.next_out = pkt_data + bzstream.total_out_lo32; if (pkt_data) { result = BZ2_bzDecompress(&bzstream); } else result = BZ_MEM_ERROR; - } while (result==BZ_OK && pkt_size<10000000); + } while (result == BZ_OK && pkt_size < 10000000); pkt_size = bzstream.total_out_lo32; BZ2_bzDecompressEnd(&bzstream); if (result != BZ_STREAM_END) { @@ -1251,10 +1279,11 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, return AVERROR_INVALIDDATA; } - *buf = pkt_data; + *buf = pkt_data; *buf_size = pkt_size; return 0; - failed: + +failed: av_free(pkt_data); return result; } @@ -1264,28 +1293,38 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, AVPacket *pkt, uint64_t display_duration) { AVBufferRef *line; - char *layer, *ptr = pkt->data, *end = ptr+pkt->size; - for (; *ptr!=',' && ptr<end-1; ptr++); + char *layer, *ptr = pkt->data, *end = ptr + pkt->size; + + for (; *ptr != ',' && ptr < end - 1; ptr++) + ; if (*ptr == ',') ptr++; layer = ptr; - for (; *ptr!=',' && ptr<end-1; ptr++); + for (; *ptr != ',' && ptr < end - 1; ptr++) + ; if (*ptr == ',') { int64_t end_pts = pkt->pts + display_duration; int sc = matroska->time_scale * pkt->pts / 10000000; int ec = matroska->time_scale * end_pts / 10000000; int sh, sm, ss, eh, em, es, len; - sh = sc/360000; sc -= 360000*sh; - sm = sc/ 6000; sc -= 6000*sm; - ss = sc/ 100; sc -= 100*ss; - eh = ec/360000; ec -= 360000*eh; - em = ec/ 6000; ec -= 6000*em; - es = ec/ 100; ec -= 100*es; + sh = sc / 360000; + sc -= 360000 * sh; + sm = sc / 6000; + sc -= 6000 * sm; + ss = sc / 100; + sc -= 100 * ss; + eh = ec / 360000; + ec -= 360000 * eh; + em = ec / 6000; + ec -= 6000 * em; + es = ec / 100; + ec -= 100 * es; *ptr++ = '\0'; - len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE; + len = 50 + end - ptr + FF_INPUT_BUFFER_PADDING_SIZE; if (!(line = av_buffer_alloc(len))) return; - snprintf(line->data, len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", + snprintf(line->data, len, + "Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", layer, sh, sm, ss, sc, eh, em, es, ec, ptr); av_buffer_unref(&pkt->buf); pkt->buf = line; @@ -1315,20 +1354,22 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, char key[1024]; int i; - for (i=0; i < list->nb_elem; i++) { - const char *lang = tags[i].lang && strcmp(tags[i].lang, "und") ? - tags[i].lang : NULL; + for (i = 0; i < list->nb_elem; i++) { + const char *lang = tags[i].lang && + strcmp(tags[i].lang, "und") ? tags[i].lang : NULL; if (!tags[i].name) { av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n"); continue; } - if (prefix) snprintf(key, sizeof(key), "%s/%s", prefix, tags[i].name); - else av_strlcpy(key, tags[i].name, sizeof(key)); + if (prefix) + snprintf(key, sizeof(key), "%s/%s", prefix, tags[i].name); + else + av_strlcpy(key, tags[i].name, sizeof(key)); if (tags[i].def || !lang) { - av_dict_set(metadata, key, tags[i].string, 0); - if (tags[i].sub.nb_elem) - matroska_convert_tag(s, &tags[i].sub, metadata, key); + av_dict_set(metadata, key, tags[i].string, 0); + if (tags[i].sub.nb_elem) + matroska_convert_tag(s, &tags[i].sub, metadata, key); } if (lang) { av_strlcat(key, "-", sizeof(key)); @@ -1347,24 +1388,24 @@ static void matroska_convert_tags(AVFormatContext *s) MatroskaTags *tags = matroska->tags.elem; int i, j; - for (i=0; i < matroska->tags.nb_elem; i++) { + for (i = 0; i < matroska->tags.nb_elem; i++) { if (tags[i].target.attachuid) { - MatroskaAttachement *attachment = matroska->attachments.elem; - for (j=0; j<matroska->attachments.nb_elem; j++) - if (attachment[j].uid == tags[i].target.attachuid - && attachment[j].stream) + MatroskaAttachment *attachment = matroska->attachments.elem; + for (j = 0; j < matroska->attachments.nb_elem; j++) + if (attachment[j].uid == tags[i].target.attachuid && + attachment[j].stream) matroska_convert_tag(s, &tags[i].tag, &attachment[j].stream->metadata, NULL); } else if (tags[i].target.chapteruid) { MatroskaChapter *chapter = matroska->chapters.elem; - for (j=0; j<matroska->chapters.nb_elem; j++) - if (chapter[j].uid == tags[i].target.chapteruid - && chapter[j].chapter) + for (j = 0; j < matroska->chapters.nb_elem; j++) + if (chapter[j].uid == tags[i].target.chapteruid && + chapter[j].chapter) matroska_convert_tag(s, &tags[i].tag, &chapter[j].chapter->metadata, NULL); } else if (tags[i].target.trackuid) { MatroskaTrack *track = matroska->tracks.elem; - for (j=0; j<matroska->tracks.nb_elem; j++) + for (j = 0; j < matroska->tracks.nb_elem; j++) if (track[j].uid == tags[i].target.trackuid && track[j].stream) matroska_convert_tag(s, &tags[i].tag, &track[j].stream->metadata, NULL); @@ -1375,20 +1416,21 @@ static void matroska_convert_tags(AVFormatContext *s) } } -static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, int idx) +static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, + int idx) { EbmlList *seekhead_list = &matroska->seekhead; + uint32_t level_up = matroska->level_up; + uint32_t saved_id = matroska->current_id; MatroskaSeekhead *seekhead = seekhead_list->elem; - uint32_t level_up = matroska->level_up; int64_t before_pos = avio_tell(matroska->ctx->pb); - uint32_t saved_id = matroska->current_id; MatroskaLevel level; int64_t offset; int ret = 0; - if (idx >= seekhead_list->nb_elem - || seekhead[idx].id == MATROSKA_ID_SEEKHEAD - || seekhead[idx].id == MATROSKA_ID_CLUSTER) + if (idx >= seekhead_list->nb_elem || + seekhead[idx].id == MATROSKA_ID_SEEKHEAD || + seekhead[idx].id == MATROSKA_ID_CLUSTER) return 0; /* seek */ @@ -1402,25 +1444,25 @@ static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, int idx "cannot parse further.\n", EBML_MAX_DEPTH); ret = AVERROR_INVALIDDATA; } else { - level.start = 0; - level.length = (uint64_t)-1; + level.start = 0; + level.length = (uint64_t) -1; matroska->levels[matroska->num_levels] = level; matroska->num_levels++; - matroska->current_id = 0; + matroska->current_id = 0; ret = ebml_parse(matroska, matroska_segment, matroska); /* remove dummy level */ while (matroska->num_levels) { uint64_t length = matroska->levels[--matroska->num_levels].length; - if (length == (uint64_t)-1) + if (length == (uint64_t) -1) break; } } } /* seek back */ avio_seek(matroska->ctx->pb, before_pos, SEEK_SET); - matroska->level_up = level_up; + matroska->level_up = level_up; matroska->current_id = saved_id; return ret; @@ -1456,28 +1498,30 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) } } -static void matroska_add_index_entries(MatroskaDemuxContext *matroska) { +static void matroska_add_index_entries(MatroskaDemuxContext *matroska) +{ EbmlList *index_list; MatroskaIndex *index; int index_scale = 1; int i, j; index_list = &matroska->index; - index = index_list->elem; - if (index_list->nb_elem - && index[0].time > 1E14/matroska->time_scale) { + index = index_list->elem; + if (index_list->nb_elem && + index[0].time > 1E14 / matroska->time_scale) { av_log(matroska->ctx, AV_LOG_WARNING, "Working around broken index.\n"); index_scale = matroska->time_scale; } for (i = 0; i < index_list->nb_elem; i++) { - EbmlList *pos_list = &index[i].pos; + EbmlList *pos_list = &index[i].pos; MatroskaIndexPos *pos = pos_list->elem; for (j = 0; j < pos_list->nb_elem; j++) { - MatroskaTrack *track = matroska_find_track_by_num(matroska, pos[j].track); + MatroskaTrack *track = matroska_find_track_by_num(matroska, + pos[j].track); if (track && track->stream) av_add_index_entry(track->stream, pos[j].pos + matroska->segment_start, - index[i].time/index_scale, 0, 0, + index[i].time / index_scale, 0, 0, AVINDEX_KEYFRAME); } } @@ -1500,10 +1544,10 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska) { static int matroska_aac_profile(char *codec_id) { - static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" }; + static const char *const aac_profiles[] = { "MAIN", "LC", "SSR" }; int profile; - for (profile=0; profile<FF_ARRAY_ELEMS(aac_profiles); profile++) + for (profile = 0; profile < FF_ARRAY_ELEMS(aac_profiles); profile++) if (strstr(codec_id, aac_profiles[profile])) break; return profile + 1; @@ -1513,7 +1557,7 @@ static int matroska_aac_sri(int samplerate) { int sri; - for (sri=0; sri<FF_ARRAY_ELEMS(avpriv_mpeg4audio_sample_rates); sri++) + for (sri = 0; sri < FF_ARRAY_ELEMS(avpriv_mpeg4audio_sample_rates); sri++) if (avpriv_mpeg4audio_sample_rates[sri] == samplerate) break; return sri; @@ -1533,9 +1577,9 @@ static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t dat static int matroska_read_header(AVFormatContext *s) { MatroskaDemuxContext *matroska = s->priv_data; - EbmlList *attachements_list = &matroska->attachments; - MatroskaAttachement *attachements; - EbmlList *chapters_list = &matroska->chapters; + EbmlList *attachments_list = &matroska->attachments; + EbmlList *chapters_list = &matroska->chapters; + MatroskaAttachment *attachments; MatroskaChapter *chapters; MatroskaTrack *tracks; uint64_t max_start = 0; @@ -1547,9 +1591,12 @@ static int matroska_read_header(AVFormatContext *s) matroska->ctx = s; /* First read the EBML header. */ - if (ebml_parse(matroska, ebml_syntax, &ebml) - || ebml.version > EBML_VERSION || ebml.max_size > sizeof(uint64_t) - || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 3 || !ebml.doctype) { + if (ebml_parse(matroska, ebml_syntax, &ebml) || + ebml.version > EBML_VERSION || + ebml.max_size > sizeof(uint64_t) || + ebml.id_length > sizeof(uint32_t) || + ebml.doctype_version > 3 || + !ebml.doctype) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML header using unsupported features\n" "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", @@ -1590,15 +1637,16 @@ static int matroska_read_header(AVFormatContext *s) if (!matroska->time_scale) matroska->time_scale = 1000000; if (matroska->duration) - matroska->ctx->duration = matroska->duration * matroska->time_scale - * 1000 / AV_TIME_BASE; + matroska->ctx->duration = matroska->duration * matroska->time_scale * + 1000 / AV_TIME_BASE; av_dict_set(&s->metadata, "title", matroska->title, 0); + av_dict_set(&s->metadata, "encoder", matroska->muxingapp, 0); if (matroska->date_utc.size == 8) matroska_metadata_creation_time(&s->metadata, AV_RB64(matroska->date_utc.data)); tracks = matroska->tracks.elem; - for (i=0; i < matroska->tracks.nb_elem; i++) { + for (i = 0; i < matroska->tracks.nb_elem; i++) { MatroskaTrack *track = &tracks[i]; enum AVCodecID codec_id = AV_CODEC_ID_NONE; EbmlList *encodings_list = &track->encodings; @@ -1609,6 +1657,7 @@ static int matroska_read_header(AVFormatContext *s) uint32_t fourcc = 0; AVIOContext b; char* key_id_base64 = NULL; + int bit_depth = -1; /* Apply some sanity checks. */ if (track->type != MATROSKA_TRACK_TYPE_VIDEO && @@ -1625,7 +1674,7 @@ static int matroska_read_header(AVFormatContext *s) if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { if (!track->default_duration && track->video.frame_rate > 0) - track->default_duration = 1000000000/track->video.frame_rate; + track->default_duration = 1000000000 / track->video.frame_rate; if (track->video.display_width == -1) track->video.display_width = track->video.pixel_width; if (track->video.display_height == -1) @@ -1659,19 +1708,19 @@ static int matroska_read_header(AVFormatContext *s) } } else if ( #if CONFIG_ZLIB - encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && + encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && #endif #if CONFIG_BZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB && #endif #if CONFIG_LZO - encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO && + encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO && #endif encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP) { encodings[0].scope = 0; av_log(matroska->ctx, AV_LOG_ERROR, "Unsupported encoding type"); - } else if (track->codec_priv.size && encodings[0].scope&2) { + } else if (track->codec_priv.size && encodings[0].scope & 2) { uint8_t *codec_priv = track->codec_priv.data; int ret = matroska_decode_buffer(&track->codec_priv.data, &track->codec_priv.size, @@ -1688,10 +1737,10 @@ static int matroska_read_header(AVFormatContext *s) } } - 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, - strlen(ff_mkv_codec_tags[j].str))){ - codec_id= ff_mkv_codec_tags[j].id; + 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, + strlen(ff_mkv_codec_tags[j].str))) { + codec_id = ff_mkv_codec_tags[j].id; break; } } @@ -1708,79 +1757,114 @@ static int matroska_read_header(AVFormatContext *s) av_freep(&key_id_base64); } - if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") - && track->codec_priv.size >= 40 - && track->codec_priv.data != NULL) { - track->ms_compat = 1; - fourcc = AV_RL32(track->codec_priv.data + 16); - codec_id = ff_codec_get_id(ff_codec_bmp_tags, fourcc); - extradata_offset = 40; - } else if (!strcmp(track->codec_id, "A_MS/ACM") - && track->codec_priv.size >= 14 - && track->codec_priv.data != NULL) { + if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") && + track->codec_priv.size >= 40 && + track->codec_priv.data != NULL) { + track->ms_compat = 1; + bit_depth = AV_RL16(track->codec_priv.data + 14); + fourcc = AV_RL32(track->codec_priv.data + 16); + codec_id = ff_codec_get_id(ff_codec_bmp_tags, + fourcc); + if (!codec_id) + codec_id = ff_codec_get_id(ff_codec_movvideo_tags, + fourcc); + extradata_offset = 40; + } else if (!strcmp(track->codec_id, "A_MS/ACM") && + track->codec_priv.size >= 14 && + track->codec_priv.data != NULL) { int ret; - ffio_init_context(&b, track->codec_priv.data, track->codec_priv.size, + ffio_init_context(&b, track->codec_priv.data, + track->codec_priv.size, 0, NULL, NULL, NULL, NULL); ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size); if (ret < 0) return ret; - codec_id = st->codec->codec_id; + codec_id = st->codec->codec_id; extradata_offset = FFMIN(track->codec_priv.size, 18); - } else if (!strcmp(track->codec_id, "V_QUICKTIME") + } else if (!strcmp(track->codec_id, "A_QUICKTIME") && (track->codec_priv.size >= 86) && (track->codec_priv.data != NULL)) { - fourcc = AV_RL32(track->codec_priv.data); + fourcc = AV_RL32(track->codec_priv.data + 4); + codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); + if (ff_codec_get_id(ff_codec_movaudio_tags, AV_RL32(track->codec_priv.data))) { + fourcc = AV_RL32(track->codec_priv.data); + codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); + } + } else if (!strcmp(track->codec_id, "V_QUICKTIME") && + (track->codec_priv.size >= 21) && + (track->codec_priv.data != NULL)) { + fourcc = AV_RL32(track->codec_priv.data + 4); codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc); + if (ff_codec_get_id(ff_codec_movvideo_tags, AV_RL32(track->codec_priv.data))) { + fourcc = AV_RL32(track->codec_priv.data); + codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc); + } + if (codec_id == AV_CODEC_ID_NONE && AV_RL32(track->codec_priv.data+4) == AV_RL32("SMI ")) + codec_id = AV_CODEC_ID_SVQ3; } else if (codec_id == AV_CODEC_ID_PCM_S16BE) { switch (track->audio.bitdepth) { - case 8: codec_id = AV_CODEC_ID_PCM_U8; break; - case 24: codec_id = AV_CODEC_ID_PCM_S24BE; break; - case 32: codec_id = AV_CODEC_ID_PCM_S32BE; break; + case 8: + codec_id = AV_CODEC_ID_PCM_U8; + break; + case 24: + codec_id = AV_CODEC_ID_PCM_S24BE; + break; + case 32: + codec_id = AV_CODEC_ID_PCM_S32BE; + break; } } else if (codec_id == AV_CODEC_ID_PCM_S16LE) { switch (track->audio.bitdepth) { - case 8: codec_id = AV_CODEC_ID_PCM_U8; break; - case 24: codec_id = AV_CODEC_ID_PCM_S24LE; break; - case 32: codec_id = AV_CODEC_ID_PCM_S32LE; break; + case 8: + codec_id = AV_CODEC_ID_PCM_U8; + break; + case 24: + codec_id = AV_CODEC_ID_PCM_S24LE; + break; + case 32: + codec_id = AV_CODEC_ID_PCM_S32LE; + break; } - } else if (codec_id==AV_CODEC_ID_PCM_F32LE && track->audio.bitdepth==64) { + } else if (codec_id == AV_CODEC_ID_PCM_F32LE && + track->audio.bitdepth == 64) { codec_id = AV_CODEC_ID_PCM_F64LE; } else if (codec_id == AV_CODEC_ID_AAC && !track->codec_priv.size) { int profile = matroska_aac_profile(track->codec_id); - int sri = matroska_aac_sri(track->audio.samplerate); - extradata = av_mallocz(5 + FF_INPUT_BUFFER_PADDING_SIZE); + int sri = matroska_aac_sri(track->audio.samplerate); + extradata = av_mallocz(5 + FF_INPUT_BUFFER_PADDING_SIZE); if (extradata == NULL) return AVERROR(ENOMEM); - extradata[0] = (profile << 3) | ((sri&0x0E) >> 1); - extradata[1] = ((sri&0x01) << 7) | (track->audio.channels<<3); + extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1); + extradata[1] = ((sri & 0x01) << 7) | (track->audio.channels << 3); if (strstr(track->codec_id, "SBR")) { - sri = matroska_aac_sri(track->audio.out_samplerate); - extradata[2] = 0x56; - extradata[3] = 0xE5; - extradata[4] = 0x80 | (sri<<3); + sri = matroska_aac_sri(track->audio.out_samplerate); + extradata[2] = 0x56; + extradata[3] = 0xE5; + extradata[4] = 0x80 | (sri << 3); extradata_size = 5; } else extradata_size = 2; } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) { /* Only ALAC's magic cookie is stored in Matroska's track headers. - Create the "atom size", "tag", and "tag version" fields the - decoder expects manually. */ + * Create the "atom size", "tag", and "tag version" fields the + * decoder expects manually. */ extradata_size = 12 + track->codec_priv.size; - extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + extradata = av_mallocz(extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); if (extradata == NULL) return AVERROR(ENOMEM); AV_WB32(extradata, extradata_size); memcpy(&extradata[4], "alac", 4); AV_WB32(&extradata[8], 0); memcpy(&extradata[12], track->codec_priv.data, - track->codec_priv.size); + track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { extradata_size = 30; - extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (extradata == NULL) return AVERROR(ENOMEM); ffio_init_context(&b, extradata, extradata_size, 1, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL); avio_write(&b, "TTA1", 4); avio_wl16(&b, 1); avio_wl16(&b, track->audio.channels); @@ -1788,21 +1872,28 @@ static int matroska_read_header(AVFormatContext *s) if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX) return AVERROR_INVALIDDATA; avio_wl32(&b, track->audio.out_samplerate); - avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale), track->audio.out_samplerate, AV_TIME_BASE * 1000)); - } else if (codec_id == AV_CODEC_ID_RV10 || codec_id == AV_CODEC_ID_RV20 || - codec_id == AV_CODEC_ID_RV30 || codec_id == AV_CODEC_ID_RV40) { + avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale), + track->audio.out_samplerate, + AV_TIME_BASE * 1000)); + } else if (codec_id == AV_CODEC_ID_RV10 || + codec_id == AV_CODEC_ID_RV20 || + codec_id == AV_CODEC_ID_RV30 || + codec_id == AV_CODEC_ID_RV40) { extradata_offset = 26; } else if (codec_id == AV_CODEC_ID_RA_144) { track->audio.out_samplerate = 8000; - track->audio.channels = 1; - } else if ((codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK || - codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR) - && track->codec_priv.data) { + track->audio.channels = 1; + } else if ((codec_id == AV_CODEC_ID_RA_288 || + codec_id == AV_CODEC_ID_COOK || + codec_id == AV_CODEC_ID_ATRAC3 || + codec_id == AV_CODEC_ID_SIPR) + && track->codec_priv.data) { #if CONFIG_RA_288_DECODER || CONFIG_COOK_DECODER || CONFIG_ATRAC3_DECODER || CONFIG_SIPR_DECODER int flavor; - ffio_init_context(&b, track->codec_priv.data,track->codec_priv.size, - 0, NULL, NULL, NULL, NULL); + ffio_init_context(&b, track->codec_priv.data, + track->codec_priv.size, + 0, NULL, NULL, NULL, NULL); avio_skip(&b, 22); flavor = avio_rb16(&b); track->audio.coded_framesize = avio_rb32(&b); @@ -1810,11 +1901,14 @@ static int matroska_read_header(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 || - track->audio.sub_packet_h <= 0 || track->audio.frame_size <= 0 || + if (flavor < 0 || + track->audio.coded_framesize <= 0 || + track->audio.sub_packet_h <= 0 || + track->audio.frame_size <= 0 || track->audio.sub_packet_size <= 0) return AVERROR_INVALIDDATA; - track->audio.buf = av_malloc_array(track->audio.sub_packet_h, track->audio.frame_size); + 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) { @@ -1824,16 +1918,18 @@ static int matroska_read_header(AVFormatContext *s) if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) { static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 }; track->audio.sub_packet_size = ff_sipr_subpk_size[flavor]; - st->codec->bit_rate = sipr_bit_rate[flavor]; + st->codec->bit_rate = sipr_bit_rate[flavor]; } st->codec->block_align = track->audio.sub_packet_size; - extradata_offset = 78; + extradata_offset = 78; } #else /* Returning without closing would cause leaks with some files */ matroska_read_close(s); return AVERROR_INVALIDDATA; #endif + } else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) { + fourcc = AV_RL32(track->codec_priv.data); } track->codec_priv.size -= extradata_offset; @@ -1843,10 +1939,16 @@ static int matroska_read_header(AVFormatContext *s) if (track->time_scale < 0.01) track->time_scale = 1.0; - avpriv_set_pts_info(st, 64, matroska->time_scale*track->time_scale, 1000*1000*1000); /* 64 bit pts in ns */ + avpriv_set_pts_info(st, 64, matroska->time_scale * track->time_scale, + 1000 * 1000 * 1000); /* 64 bit pts in ns */ + + /* convert the delay from ns to the track timebase */ + track->codec_delay = av_rescale_q(track->codec_delay, + (AVRational){ 1, 1000000000 }, + st->time_base); st->codec->codec_id = codec_id; - st->start_time = 0; + if (strcmp(track->language, "und")) av_dict_set(&st->metadata, "language", track->language, 0); av_dict_set(&st->metadata, "title", track->name, 0); @@ -1857,10 +1959,10 @@ static int matroska_read_header(AVFormatContext *s) st->disposition |= AV_DISPOSITION_FORCED; if (!st->codec->extradata) { - if(extradata){ - st->codec->extradata = extradata; + if (extradata) { + st->codec->extradata = extradata; st->codec->extradata_size = extradata_size; - } else if(track->codec_priv.data && track->codec_priv.size > 0){ + } else if (track->codec_priv.data && track->codec_priv.size > 0) { if (ff_alloc_extradata(st->codec, track->codec_priv.size)) return AVERROR(ENOMEM); memcpy(st->codec->extradata, @@ -1874,12 +1976,14 @@ static int matroska_read_header(AVFormatContext *s) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_tag = fourcc; - st->codec->width = track->video.pixel_width; - st->codec->height = track->video.pixel_height; + if (bit_depth >= 0) + st->codec->bits_per_coded_sample = bit_depth; + st->codec->width = track->video.pixel_width; + st->codec->height = track->video.pixel_height; av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, st->codec->height * track->video.display_width, - st->codec-> width * track->video.display_height, + st->codec->width * track->video.display_height, 255); if (st->codec->codec_id != AV_CODEC_ID_HEVC) st->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -1916,15 +2020,16 @@ static int matroska_read_header(AVFormatContext *s) } } } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = track->audio.out_samplerate; - st->codec->channels = track->audio.channels; - st->codec->bits_per_coded_sample = track->audio.bitdepth; + st->codec->channels = track->audio.channels; + if (!st->codec->bits_per_coded_sample) + st->codec->bits_per_coded_sample = track->audio.bitdepth; if (st->codec->codec_id != AV_CODEC_ID_AAC) - st->need_parsing = AVSTREAM_PARSE_HEADERS; + st->need_parsing = AVSTREAM_PARSE_HEADERS; if (track->codec_delay > 0) { st->codec->delay = av_rescale_q(track->codec_delay, - (AVRational){1, 1000000000}, + st->time_base, (AVRational){1, st->codec->sample_rate}); } if (track->seek_preroll > 0) { @@ -1955,44 +2060,46 @@ static int matroska_read_header(AVFormatContext *s) } } - attachements = attachements_list->elem; - for (j=0; j<attachements_list->nb_elem; j++) { - if (!(attachements[j].filename && attachements[j].mime && - attachements[j].bin.data && attachements[j].bin.size > 0)) { + attachments = attachments_list->elem; + for (j = 0; j < attachments_list->nb_elem; j++) { + if (!(attachments[j].filename && attachments[j].mime && + attachments[j].bin.data && attachments[j].bin.size > 0)) { av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n"); } else { AVStream *st = avformat_new_stream(s, NULL); if (st == NULL) break; - av_dict_set(&st->metadata, "filename",attachements[j].filename, 0); - av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0); - st->codec->codec_id = AV_CODEC_ID_NONE; + av_dict_set(&st->metadata, "filename", attachments[j].filename, 0); + av_dict_set(&st->metadata, "mimetype", attachments[j].mime, 0); + st->codec->codec_id = AV_CODEC_ID_NONE; st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; - if (ff_alloc_extradata(st->codec, attachements[j].bin.size)) + if (ff_alloc_extradata(st->codec, attachments[j].bin.size)) break; - memcpy(st->codec->extradata, attachements[j].bin.data, attachements[j].bin.size); + memcpy(st->codec->extradata, attachments[j].bin.data, + attachments[j].bin.size); - for (i=0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) { - if (!strncmp(ff_mkv_mime_tags[i].str, attachements[j].mime, + for (i = 0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) { + if (!strncmp(ff_mkv_mime_tags[i].str, attachments[j].mime, strlen(ff_mkv_mime_tags[i].str))) { st->codec->codec_id = ff_mkv_mime_tags[i].id; break; } } - attachements[j].stream = st; + attachments[j].stream = st; } } chapters = chapters_list->elem; - for (i=0; i<chapters_list->nb_elem; i++) - if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid - && (max_start==0 || chapters[i].start > max_start)) { + for (i = 0; i < chapters_list->nb_elem; i++) + if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid && + (max_start == 0 || chapters[i].start > max_start)) { chapters[i].chapter = - avpriv_new_chapter(s, chapters[i].uid, (AVRational){1, 1000000000}, - chapters[i].start, chapters[i].end, - chapters[i].title); + avpriv_new_chapter(s, chapters[i].uid, + (AVRational) { 1, 1000000000 }, + chapters[i].start, chapters[i].end, + chapters[i].title); av_dict_set(&chapters[i].chapter->metadata, - "title", chapters[i].title, 0); + "title", chapters[i].title, 0); max_start = chapters[i].start; } @@ -2018,7 +2125,8 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, memmove(&matroska->packets[0], &matroska->packets[1], (matroska->num_packets - 1) * sizeof(AVPacket *)); newpackets = av_realloc(matroska->packets, - (matroska->num_packets - 1) * sizeof(AVPacket *)); + (matroska->num_packets - 1) * + sizeof(AVPacket *)); if (newpackets) matroska->packets = newpackets; } else { @@ -2050,7 +2158,7 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska) } static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, - int* buf_size, int type, + int *buf_size, int type, uint32_t **lace_buf, int *laces) { int res = 0, n, size = *buf_size; @@ -2058,7 +2166,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, uint32_t *lace_size; if (!type) { - *laces = 1; + *laces = 1; *lace_buf = av_mallocz(sizeof(int)); if (!*lace_buf) return AVERROR(ENOMEM); @@ -2068,15 +2176,16 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, } av_assert0(size > 0); - *laces = *data + 1; - data += 1; - size -= 1; + *laces = *data + 1; + data += 1; + size -= 1; lace_size = av_mallocz(*laces * sizeof(int)); if (!lace_size) return AVERROR(ENOMEM); switch (type) { - case 0x1: /* Xiph lacing */ { + case 0x1: /* Xiph lacing */ + { uint8_t temp; uint32_t total = 0; for (n = 0; res == 0 && n < *laces - 1; n++) { @@ -2085,11 +2194,11 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, res = AVERROR_INVALIDDATA; break; } - temp = *data; - total += temp; + temp = *data; + total += temp; lace_size[n] += temp; - data += 1; - size -= 1; + data += 1; + size -= 1; if (temp != 0xff) break; } @@ -2112,7 +2221,8 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, lace_size[n] = size / *laces; break; - case 0x3: /* EBML lacing */ { + case 0x3: /* EBML lacing */ + { uint64_t num; uint64_t total; n = matroska_ebmlnum_uint(matroska, data, size, &num); @@ -2135,10 +2245,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, res = r<0 ? r : AVERROR_INVALIDDATA; break; } - data += r; - size -= r; + data += r; + size -= r; lace_size[n] = lace_size[n - 1] + snum; - total += lace_size[n]; + total += lace_size[n]; } if (size <= total) { res = AVERROR_INVALIDDATA; @@ -2157,18 +2267,16 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, } static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, - MatroskaTrack *track, - AVStream *st, - uint8_t *data, int size, - uint64_t timecode, + MatroskaTrack *track, AVStream *st, + uint8_t *data, int size, uint64_t timecode, int64_t pos) { int a = st->codec->block_align; int sps = track->audio.sub_packet_size; int cfs = track->audio.coded_framesize; - int h = track->audio.sub_packet_h; - int y = track->audio.sub_packet_cnt; - int w = track->audio.frame_size; + int h = track->audio.sub_packet_h; + int y = track->audio.sub_packet_cnt; + int w = track->audio.frame_size; int x; if (!track->audio.pkt_cnt) { @@ -2180,24 +2288,26 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, "Corrupt int4 RM-style audio packet size\n"); return AVERROR_INVALIDDATA; } - for (x=0; x<h/2; x++) - memcpy(track->audio.buf+x*2*w+y*cfs, - data+x*cfs, cfs); + for (x = 0; x < h / 2; x++) + memcpy(track->audio.buf + x * 2 * w + y * cfs, + data + x * cfs, cfs); } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) { if (size < w) { av_log(matroska->ctx, AV_LOG_ERROR, "Corrupt sipr RM-style audio packet size\n"); return AVERROR_INVALIDDATA; } - memcpy(track->audio.buf + y*w, data, w); + memcpy(track->audio.buf + y * w, data, w); } else { - if (size < sps * w / sps || h<=0) { + if (size < sps * w / sps || h<=0 || w%sps) { av_log(matroska->ctx, AV_LOG_ERROR, "Corrupt generic RM-style audio packet size\n"); return AVERROR_INVALIDDATA; } - for (x=0; x<w/sps; x++) - memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); + for (x = 0; x < w / sps; x++) + memcpy(track->audio.buf + + sps * (h * x + ((h + 1) / 2) * (y & 1) + (y >> 1)), + data + x * sps, sps); } if (++track->audio.sub_packet_cnt >= h) { @@ -2209,23 +2319,24 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, #endif } track->audio.sub_packet_cnt = 0; - track->audio.pkt_cnt = h*w / a; + track->audio.pkt_cnt = h * w / a; } } while (track->audio.pkt_cnt) { AVPacket *pkt = NULL; - if (!(pkt = av_mallocz(sizeof(AVPacket))) || av_new_packet(pkt, a) < 0){ + if (!(pkt = av_mallocz(sizeof(AVPacket))) || av_new_packet(pkt, a) < 0) { av_free(pkt); return AVERROR(ENOMEM); } - memcpy(pkt->data, track->audio.buf - + a * (h*w / a - track->audio.pkt_cnt--), a); - pkt->pts = track->audio.buf_timecode; + memcpy(pkt->data, + track->audio.buf + a * (h * w / a - track->audio.pkt_cnt--), + a); + pkt->pts = track->audio.buf_timecode; track->audio.buf_timecode = AV_NOPTS_VALUE; - pkt->pos = pos; - pkt->stream_index = st->index; - dynarray_add(&matroska->packets,&matroska->num_packets,pkt); + pkt->pos = pos; + pkt->stream_index = st->index; + dynarray_add(&matroska->packets, &matroska->num_packets, pkt); } return 0; @@ -2268,8 +2379,8 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, goto fail; } blocksize = AV_RL32(src); - src += 4; - srclen -= 4; + src += 4; + srclen -= 4; } else blocksize = srclen; @@ -2286,16 +2397,16 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, dst = tmp; dstlen += blocksize + 32; - AV_WL32(dst + offset, MKTAG('w', 'v', 'p', 'k')); // tag - AV_WL32(dst + offset + 4, blocksize + 24); // blocksize - 8 - AV_WL16(dst + offset + 8, ver); // version - AV_WL16(dst + offset + 10, 0); // track/index_no - AV_WL32(dst + offset + 12, 0); // total samples - AV_WL32(dst + offset + 16, 0); // block index - AV_WL32(dst + offset + 20, samples); // number of samples - AV_WL32(dst + offset + 24, flags); // flags - AV_WL32(dst + offset + 28, crc); // crc - memcpy (dst + offset + 32, src, blocksize); // block data + AV_WL32(dst + offset, MKTAG('w', 'v', 'p', 'k')); // tag + AV_WL32(dst + offset + 4, blocksize + 24); // blocksize - 8 + AV_WL16(dst + offset + 8, ver); // version + AV_WL16(dst + offset + 10, 0); // track/index_no + AV_WL32(dst + offset + 12, 0); // total samples + AV_WL32(dst + offset + 16, 0); // block index + AV_WL32(dst + offset + 20, samples); // number of samples + AV_WL32(dst + offset + 24, flags); // flags + AV_WL32(dst + offset + 28, crc); // crc + memcpy(dst + offset + 32, src, blocksize); // block data src += blocksize; srclen -= blocksize; @@ -2427,8 +2538,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, } static int matroska_parse_frame(MatroskaDemuxContext *matroska, - MatroskaTrack *track, - AVStream *st, + MatroskaTrack *track, AVStream *st, uint8_t *data, int pkt_size, uint64_t timecode, uint64_t lace_duration, int64_t pos, int is_keyframe, @@ -2450,7 +2560,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, uint8_t *wv_data; res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size); if (res < 0) { - av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a wavpack block.\n"); + av_log(matroska->ctx, AV_LOG_ERROR, + "Error parsing a wavpack block.\n"); goto fail; } if (pkt_data != data) @@ -2458,7 +2569,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, pkt_data = wv_data; } - if (st->codec->codec_id == AV_CODEC_ID_PRORES) + if (st->codec->codec_id == AV_CODEC_ID_PRORES && + AV_RB32(&data[4]) != MKBETAG('i', 'c', 'p', 'f')) offset = 8; pkt = av_mallocz(sizeof(AVPacket)); @@ -2469,7 +2581,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, goto fail; } - if (st->codec->codec_id == AV_CODEC_ID_PRORES) { + if (st->codec->codec_id == AV_CODEC_ID_PRORES && offset == 8) { uint8_t *buf = pkt->data; bytestream_put_be32(&buf, pkt_size); bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f')); @@ -2480,14 +2592,14 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, if (pkt_data != data) av_freep(&pkt_data); - pkt->flags = is_keyframe; + pkt->flags = is_keyframe; pkt->stream_index = st->index; if (additional_size > 0) { uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, additional_size + 8); - if(side_data == NULL) { + if (side_data == NULL) { av_free_packet(pkt); av_free(pkt); return AVERROR(ENOMEM); @@ -2500,7 +2612,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); - if(side_data == NULL) { + if (side_data == NULL) { av_free_packet(pkt); av_free(pkt); return AVERROR(ENOMEM); @@ -2544,14 +2656,14 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, if (st->codec->codec_id == AV_CODEC_ID_SSA) matroska_fix_ass_packet(matroska, pkt, lace_duration); - if (matroska->prev_pkt && - timecode != AV_NOPTS_VALUE && - matroska->prev_pkt->pts == timecode && - matroska->prev_pkt->stream_index == st->index && + if (matroska->prev_pkt && + timecode != AV_NOPTS_VALUE && + matroska->prev_pkt->pts == timecode && + matroska->prev_pkt->stream_index == st->index && st->codec->codec_id == AV_CODEC_ID_SSA) matroska_merge_packets(matroska->prev_pkt, pkt); else { - dynarray_add(&matroska->packets,&matroska->num_packets,pkt); + dynarray_add(&matroska->packets, &matroska->num_packets, pkt); matroska->prev_pkt = pkt; } #else @@ -2560,6 +2672,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, #endif return 0; + fail: if (pkt_data != data) av_freep(&pkt_data); @@ -2602,23 +2715,25 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, av_assert1(block_duration != AV_NOPTS_VALUE); block_time = sign_extend(AV_RB16(data), 16); - data += 2; - flags = *data++; - size -= 3; + data += 2; + flags = *data++; + size -= 3; if (is_keyframe == -1) is_keyframe = flags & 0x80 ? AV_PKT_FLAG_KEY : 0; - if (cluster_time != (uint64_t)-1 - && (block_time >= 0 || cluster_time >= -block_time)) { - timecode = cluster_time + block_time; - if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE - && timecode < track->end_timecode) + if (cluster_time != (uint64_t) -1 && + (block_time >= 0 || cluster_time >= -block_time)) { + timecode = cluster_time + block_time - track->codec_delay; + if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && + timecode < track->end_timecode) is_keyframe = 0; /* overlapping subtitles are not key frame */ if (is_keyframe) - av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME); + av_add_index_entry(st, cluster_pos, timecode, 0, 0, + AVINDEX_KEYFRAME); } - if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { + if (matroska->skip_to_keyframe && + track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { if (timecode < matroska->skip_to_timecode) return res; if (is_keyframe) @@ -2638,7 +2753,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (track->audio.samplerate == 8000) { // If this is needed for more codecs, then add them here if (st->codec->codec_id == AV_CODEC_ID_AC3) { - if(track->audio.samplerate != st->codec->sample_rate || !st->codec->frame_size) + if (track->audio.samplerate != st->codec->sample_rate || !st->codec->frame_size) trust_default_duration = 0; } } @@ -2659,11 +2774,10 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, } if ((st->codec->codec_id == AV_CODEC_ID_RA_288 || - st->codec->codec_id == AV_CODEC_ID_COOK || - st->codec->codec_id == AV_CODEC_ID_SIPR || + st->codec->codec_id == AV_CODEC_ID_COOK || + st->codec->codec_id == AV_CODEC_ID_SIPR || st->codec->codec_id == AV_CODEC_ID_ATRAC3) && - st->codec->block_align && track->audio.sub_packet_size) { - + st->codec->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], @@ -2681,13 +2795,12 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, pos); if (res) goto end; - } else { res = matroska_parse_frame(matroska, track, st, data, lace_size[n], - timecode, lace_duration, - pos, !n? is_keyframe : 0, - additional, additional_id, additional_size, - discard_padding); + timecode, lace_duration, pos, + !n ? is_keyframe : 0, + additional, additional_id, additional_size, + discard_padding); if (res) goto end; } @@ -2718,8 +2831,8 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) ebml_free(matroska_cluster, &matroska->current_cluster); memset(&matroska->current_cluster, 0, sizeof(MatroskaCluster)); matroska->current_cluster_num_blocks = 0; - matroska->current_cluster_pos = avio_tell(matroska->ctx->pb); - matroska->prev_pkt = NULL; + matroska->current_cluster_pos = avio_tell(matroska->ctx->pb); + matroska->prev_pkt = NULL; /* sizeof the ID which was already read */ if (matroska->current_id) matroska->current_cluster_pos -= 4; @@ -2735,21 +2848,20 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) if (!res && matroska->current_cluster_num_blocks < - matroska->current_cluster.blocks.nb_elem) { + matroska->current_cluster.blocks.nb_elem) { blocks_list = &matroska->current_cluster.blocks; - blocks = blocks_list->elem; + blocks = blocks_list->elem; matroska->current_cluster_num_blocks = blocks_list->nb_elem; - i = blocks_list->nb_elem - 1; + i = blocks_list->nb_elem - 1; if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; uint8_t* additional = blocks[i].additional.size > 0 ? blocks[i].additional.data : NULL; if (!blocks[i].non_simple) blocks[i].duration = 0; - res = matroska_parse_block(matroska, - blocks[i].bin.data, blocks[i].bin.size, - blocks[i].bin.pos, + res = matroska_parse_block(matroska, blocks[i].bin.data, + blocks[i].bin.size, blocks[i].bin.pos, matroska->current_cluster.timecode, blocks[i].duration, is_keyframe, additional, blocks[i].additional_id, @@ -2769,23 +2881,24 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) MatroskaBlock *blocks; int i, res; int64_t pos; + if (!matroska->contains_ssa) return matroska_parse_cluster_incremental(matroska); pos = avio_tell(matroska->ctx->pb); matroska->prev_pkt = NULL; if (matroska->current_id) pos -= 4; /* sizeof the ID which was already read */ - res = ebml_parse(matroska, matroska_clusters, &cluster); + res = ebml_parse(matroska, matroska_clusters, &cluster); blocks_list = &cluster.blocks; - blocks = blocks_list->elem; - for (i=0; i<blocks_list->nb_elem; i++) + blocks = blocks_list->elem; + for (i = 0; i < blocks_list->nb_elem; i++) if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; - res=matroska_parse_block(matroska, - blocks[i].bin.data, blocks[i].bin.size, - blocks[i].bin.pos, cluster.timecode, - blocks[i].duration, is_keyframe, NULL, 0, 0, - pos, blocks[i].discard_padding); + res = matroska_parse_block(matroska, blocks[i].bin.data, + blocks[i].bin.size, blocks[i].bin.pos, + cluster.timecode, blocks[i].duration, + is_keyframe, NULL, 0, 0, pos, + blocks[i].discard_padding); } ebml_free(matroska_cluster, &cluster); return res; @@ -2825,7 +2938,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { - avio_seek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET); + avio_seek(s->pb, st->index_entries[st->nb_index_entries - 1].pos, + SEEK_SET); matroska->current_id = 0; while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { matroska_clear_queue(matroska); @@ -2839,24 +2953,26 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, goto err; index_min = index; - for (i=0; i < matroska->tracks.nb_elem; i++) { - tracks[i].audio.pkt_cnt = 0; + for (i = 0; i < matroska->tracks.nb_elem; i++) { + tracks[i].audio.pkt_cnt = 0; tracks[i].audio.sub_packet_cnt = 0; - tracks[i].audio.buf_timecode = AV_NOPTS_VALUE; - tracks[i].end_timecode = 0; - if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE - && tracks[i].stream->discard != AVDISCARD_ALL) { - index_sub = av_index_search_timestamp(tracks[i].stream, st->index_entries[index].timestamp, AVSEEK_FLAG_BACKWARD); - while(index_sub >= 0 - && index_min >= 0 - && tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos - && st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale) + tracks[i].audio.buf_timecode = AV_NOPTS_VALUE; + tracks[i].end_timecode = 0; + if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE && + tracks[i].stream->discard != AVDISCARD_ALL) { + index_sub = av_index_search_timestamp( + tracks[i].stream, st->index_entries[index].timestamp, + AVSEEK_FLAG_BACKWARD); + while (index_sub >= 0 && + index_min > 0 && + tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos && + st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000 / matroska->time_scale) index_min--; } } avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET); - matroska->current_id = 0; + matroska->current_id = 0; if (flags & AVSEEK_FLAG_ANY) { st->skip_to_keyframe = 0; matroska->skip_to_timecode = timestamp; @@ -2865,8 +2981,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, matroska->skip_to_timecode = st->index_entries[index].timestamp; } matroska->skip_to_keyframe = 1; - matroska->done = 0; - matroska->num_levels = 0; + matroska->done = 0; + matroska->num_levels = 0; ff_update_cur_dts(s, st, st->index_entries[index].timestamp); return 0; err: @@ -2889,7 +3005,7 @@ static int matroska_read_close(AVFormatContext *s) matroska_clear_queue(matroska); - for (n=0; n < matroska->tracks.nb_elem; n++) + for (n = 0; n < matroska->tracks.nb_elem; n++) if (tracks[n].type == MATROSKA_TRACK_TYPE_AUDIO) av_free(tracks[n].audio.buf); ebml_free(matroska_cluster, &matroska->current_cluster); diff --git a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c index e461c5e60ed..17eb318aadb 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c @@ -22,6 +22,7 @@ #include <stdint.h> #include "avc.h" +#include "hevc.h" #include "avformat.h" #include "avio_internal.h" #include "avlanguage.h" @@ -84,6 +85,7 @@ typedef struct { typedef struct { int write_dts; int has_cue; + int64_t ts_offset; } mkv_track; #define MODE_MATROSKAv2 0x01 @@ -532,6 +534,8 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo ret = put_wv_codecpriv(dyn_cp, codec); else if (codec->codec_id == AV_CODEC_ID_H264) ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); + else if (codec->codec_id == AV_CODEC_ID_HEVC) + ret = ff_isom_write_hvcc(dyn_cp, codec->extradata, codec->extradata_size, 0); else if (codec->codec_id == AV_CODEC_ID_ALAC) { if (codec->extradata_size < 36) { av_log(s, AV_LOG_ERROR, @@ -541,6 +545,9 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo } else avio_write(dyn_cp, codec->extradata + 12, codec->extradata_size - 12); + } else if (codec->codec_id == AV_CODEC_ID_PRORES && + ff_codec_get_id(ff_codec_movvideo_tags, codec->codec_tag) == AV_CODEC_ID_PRORES) { + avio_wl32(dyn_cp, codec->codec_tag); } else if (codec->extradata_size && codec->codec_id != AV_CODEC_ID_TTA) avio_write(dyn_cp, codec->extradata, codec->extradata_size); @@ -548,9 +555,23 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo if (qt_id) { if (!codec->codec_tag) codec->codec_tag = ff_codec_get_tag(ff_codec_movvideo_tags, codec->codec_id); - if (codec->extradata_size) + if (codec->extradata_size) { + if ( ff_codec_get_id(ff_codec_movvideo_tags, codec->codec_tag) == codec->codec_id + && ff_codec_get_id(ff_codec_movvideo_tags, AV_RL32(codec->extradata+4)) != codec->codec_id + ) { + int i; + avio_wb32(dyn_cp, 0x5a + codec->extradata_size); + avio_wl32(dyn_cp, codec->codec_tag); + for(i=0; i<0x5a-8; i++) + avio_w8(dyn_cp, 0); + } avio_write(dyn_cp, codec->extradata, codec->extradata_size); + } } else { + if (!ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id)) + av_log(s, AV_LOG_WARNING, "codec %s is not supported by this format\n", + avcodec_get_name(codec->codec_id)); + if (!codec->codec_tag) codec->codec_tag = ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id); if (!codec->codec_tag) { @@ -559,7 +580,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo ret = AVERROR(EINVAL); } - ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0); + ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0, 0); } } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -573,7 +594,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo if (!codec->codec_tag) codec->codec_tag = tag; - ff_put_wav_header(dyn_cp, codec); + ff_put_wav_header(dyn_cp, codec, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); } codecpriv_size = avio_close_dyn_buf(dyn_cp, &codecpriv); @@ -616,7 +637,7 @@ static int mkv_write_tracks(AVFormatContext *s) continue; } - if (!bit_depth) + if (!bit_depth && codec->codec_id != AV_CODEC_ID_ADPCM_G726) bit_depth = av_get_bytes_per_sample(codec->sample_fmt) << 3; if (!bit_depth) bit_depth = codec->bits_per_coded_sample; @@ -674,13 +695,17 @@ static int mkv_write_tracks(AVFormatContext *s) } } + if (codec->codec_type == AVMEDIA_TYPE_AUDIO && codec->delay && codec->codec_id == AV_CODEC_ID_OPUS) { +// mkv->tracks[i].ts_offset = av_rescale_q(codec->delay, +// (AVRational){ 1, codec->sample_rate }, +// st->time_base); + + put_ebml_uint(pb, MATROSKA_ID_CODECDELAY, + av_rescale_q(codec->delay, (AVRational){ 1, codec->sample_rate }, + (AVRational){ 1, 1000000000 })); + } if (codec->codec_id == AV_CODEC_ID_OPUS) { - uint64_t codec_delay =av_rescale_q(codec->delay, - (AVRational){1, codec->sample_rate}, - (AVRational){1, 1000000000}); - put_ebml_uint(pb, MATROSKA_ID_CODECDELAY, codec_delay); put_ebml_uint(pb, MATROSKA_ID_SEEKPREROLL, OPUS_SEEK_PREROLL); - } if (mkv->mode == MODE_WEBM && !(codec->codec_id == AV_CODEC_ID_VP8 || @@ -928,7 +953,9 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme end_ebml_master(s->pb, targets); while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) - if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode")) + if (av_strcasecmp(t->key, "title") && + av_strcasecmp(t->key, "stereo_mode") && + av_strcasecmp(t->key, "encoding_tool")) mkv_write_simpletag(s->pb, t); end_ebml_master(s->pb, tag); @@ -1069,7 +1096,7 @@ static int mkv_write_header(AVFormatContext *s) AVIOContext *pb = s->pb; ebml_master ebml_header, segment_info; AVDictionaryEntry *tag; - int ret, i; + int ret, i, version = 2; if (!strcmp(s->oformat->name, "webm")) mkv->mode = MODE_WEBM; else mkv->mode = MODE_MATROSKAv2; @@ -1077,7 +1104,12 @@ static int mkv_write_header(AVFormatContext *s) if (s->avoid_negative_ts < 0) s->avoid_negative_ts = 1; - for (i = 0; i < s->nb_streams; i++) + if (mkv->mode != MODE_WEBM || + av_dict_get(s->metadata, "stereo_mode", NULL, 0) || + av_dict_get(s->metadata, "alpha_mode", NULL, 0)) + version = 4; + + for (i = 0; i < s->nb_streams; i++) { if (s->streams[i]->codec->codec_id == AV_CODEC_ID_ATRAC3 || s->streams[i]->codec->codec_id == AV_CODEC_ID_COOK || s->streams[i]->codec->codec_id == AV_CODEC_ID_RA_288 || @@ -1089,8 +1121,13 @@ static int mkv_write_header(AVFormatContext *s) avcodec_get_name(s->streams[i]->codec->codec_id)); return AVERROR_PATCHWELCOME; } + if (s->streams[i]->codec->codec_id == AV_CODEC_ID_OPUS || + av_dict_get(s->streams[i]->metadata, "stereo_mode", NULL, 0) || + av_dict_get(s->streams[i]->metadata, "alpha_mode", NULL, 0)) + version = 4; + } - mkv->tracks = av_mallocz(s->nb_streams * sizeof(*mkv->tracks)); + mkv->tracks = av_mallocz_array(s->nb_streams, sizeof(*mkv->tracks)); if (!mkv->tracks) return AVERROR(ENOMEM); @@ -1100,7 +1137,7 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); put_ebml_string (pb, EBML_ID_DOCTYPE , s->oformat->name); - put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 4); + put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , version); put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); end_ebml_master(pb, ebml_header); @@ -1123,7 +1160,7 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); - if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { + if (!(s->flags & AVFMT_FLAG_BITEXACT)) { uint32_t segment_uid[4]; AVLFG lfg; @@ -1133,7 +1170,10 @@ static int mkv_write_header(AVFormatContext *s) segment_uid[i] = av_lfg_get(&lfg); put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT); - put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); + if ((tag = av_dict_get(s->metadata, "encoding_tool", NULL, 0))) + put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, tag->value); + else + put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16); } else { const char *ident = "Lavf"; @@ -1349,6 +1389,10 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, if (codec->codec_id == AV_CODEC_ID_H264 && codec->extradata_size > 0 && (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) ff_avc_parse_nal_units_buf(pkt->data, &data, &size); + else if (codec->codec_id == AV_CODEC_ID_HEVC && codec->extradata_size > 6 && + (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) + /* extradata is Annex B, assume the bitstream is too and convert it */ + ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL); else if (codec->codec_id == AV_CODEC_ID_WAVPACK) { int ret = mkv_strip_wavpack(pkt->data, &data, &size); if (ret < 0) { @@ -1520,6 +1564,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n"); return AVERROR(EINVAL); } + ts += mkv->tracks[pkt->stream_index].ts_offset; if (!s->pb->seekable) { if (!mkv->dyn_bc) { @@ -1585,6 +1630,7 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) cluster_time = pkt->dts - mkv->cluster_pts; else cluster_time = pkt->pts - mkv->cluster_pts; + cluster_time += mkv->tracks[pkt->stream_index].ts_offset; // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or // after 4k and on a keyframe @@ -1630,9 +1676,9 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM); } else ret = av_dup_packet(&mkv->cur_audio_pkt); - if (mkv->cur_audio_pkt.side_data_elems > 0) { - ret = av_copy_packet_side_data(&mkv->cur_audio_pkt, &mkv->cur_audio_pkt); - } + if (mkv->cur_audio_pkt.side_data_elems > 0) { + ret = av_copy_packet_side_data(&mkv->cur_audio_pkt, &mkv->cur_audio_pkt); + } } else ret = mkv_write_packet_internal(s, pkt); return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/metadata.c b/chromium/third_party/ffmpeg/libavformat/metadata.c index fc3a9d7d556..b9b6de79725 100644 --- a/chromium/third_party/ffmpeg/libavformat/metadata.c +++ b/chromium/third_party/ffmpeg/libavformat/metadata.c @@ -33,7 +33,7 @@ void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv, AVDictionary *dst = NULL; const char *key; - if (d_conv == s_conv) + if (d_conv == s_conv || !pm) return; while ((mtag = av_dict_get(*pm, "", mtag, AV_DICT_IGNORE_SUFFIX))) { diff --git a/chromium/third_party/ffmpeg/libavformat/microdvddec.c b/chromium/third_party/ffmpeg/libavformat/microdvddec.c index 7b49e439765..49d2b681921 100644 --- a/chromium/third_party/ffmpeg/libavformat/microdvddec.c +++ b/chromium/third_party/ffmpeg/libavformat/microdvddec.c @@ -24,12 +24,15 @@ #include "internal.h" #include "subtitles.h" #include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" #define MAX_LINESIZE 2048 typedef struct { + const AVClass *class; FFDemuxSubtitlesQueue q; + AVRational frame_rate; } MicroDVDContext; @@ -71,22 +74,30 @@ static int get_duration(const char *buf) return -1; } +static const char *bom = "\xEF\xBB\xBF"; + 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; - char line[MAX_LINESIZE]; + char line_buf[MAX_LINESIZE]; + int has_real_fps = 0; if (!st) return AVERROR(ENOMEM); while (!url_feof(s->pb)) { - char *p = line; + char *p; AVPacket *sub; int64_t pos = avio_tell(s->pb); - int len = ff_get_line(s->pb, line, sizeof(line)); + int len = ff_get_line(s->pb, line_buf, sizeof(line_buf)); + char *line = line_buf; + + if (!strncmp(line, bom, 3)) + line += 3; + p = line; if (!len) break; @@ -98,8 +109,10 @@ static int microdvd_read_header(AVFormatContext *s) if ((sscanf(line, "{%d}{}%6lf", &frame, &fps) == 2 || sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2) - && frame <= 1 && fps > 3 && fps < 100) + && frame <= 1 && fps > 3 && fps < 100) { pts_info = av_d2q(fps, 100000); + has_real_fps = 1; + } if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) { st->codec->extradata = av_strdup(line + 11); if (!st->codec->extradata) @@ -128,6 +141,13 @@ static int microdvd_read_header(AVFormatContext *s) sub->duration = get_duration(line); } ff_subtitles_queue_finalize(µdvd->q); + if (has_real_fps) { + /* export the FPS info only if set in the file */ + microdvd->frame_rate = pts_info; + } else if (microdvd->frame_rate.num) { + /* fallback on user specified frame rate */ + pts_info = microdvd->frame_rate; + } avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_MICRODVD; @@ -155,6 +175,21 @@ static int microdvd_read_close(AVFormatContext *s) return 0; } + +#define OFFSET(x) offsetof(MicroDVDContext, x) +#define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM +static const AVOption microdvd_options[] = { + { "subfps", "set the movie frame rate fallback", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, SD }, + { NULL } +}; + +static const AVClass microdvd_class = { + .class_name = "microdvddec", + .item_name = av_default_item_name, + .option = microdvd_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVInputFormat ff_microdvd_demuxer = { .name = "microdvd", .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"), @@ -164,4 +199,5 @@ AVInputFormat ff_microdvd_demuxer = { .read_packet = microdvd_read_packet, .read_seek2 = microdvd_read_seek, .read_close = microdvd_read_close, + .priv_class = µdvd_class, }; diff --git a/chromium/third_party/ffmpeg/libavformat/mlvdec.c b/chromium/third_party/ffmpeg/libavformat/mlvdec.c new file mode 100644 index 00000000000..a980ed6218c --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/mlvdec.c @@ -0,0 +1,471 @@ +/* + * Magic Lantern Video (MLV) demuxer + * Copyright (c) 2014 Peter Ross + * + * 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 + */ + +/** + * @file + * Magic Lantern Video (MLV) demuxer + */ + +#include "libavutil/eval.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/rational.h" +#include "avformat.h" +#include "internal.h" +#include "riff.h" + +#define MLV_VERSION "v2.0" + +#define MLV_VIDEO_CLASS_RAW 1 +#define MLV_VIDEO_CLASS_YUV 2 +#define MLV_VIDEO_CLASS_JPEG 3 +#define MLV_VIDEO_CLASS_H264 4 + +#define MLV_AUDIO_CLASS_WAV 1 + +#define MLV_CLASS_FLAG_DELTA 0x40 +#define MLV_CLASS_FLAG_LZMA 0x80 + +typedef struct { + AVIOContext *pb[101]; + int class[2]; + int stream_index; + uint64_t pts; +} MlvContext; + +static int probe(AVProbeData *p) +{ + if (AV_RL32(p->buf) == MKTAG('M','L','V','I') && + AV_RL32(p->buf + 4) >= 52 && + !memcmp(p->buf + 8, MLV_VERSION, 5)) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int check_file_header(AVIOContext *pb, uint64_t guid) +{ + unsigned int size; + uint8_t version[8]; + + avio_skip(pb, 4); + size = avio_rl32(pb); + if (size < 52) + return AVERROR_INVALIDDATA; + avio_read(pb, version, 8); + if (memcmp(version, MLV_VERSION, 5) || avio_rl64(pb) != guid) + return AVERROR_INVALIDDATA; + avio_skip(pb, size - 24); + return 0; +} + +static void read_string(AVFormatContext *avctx, AVIOContext *pb, const char *tag, int size) +{ + char * value = av_malloc(size + 1); + if (!value) { + avio_skip(pb, size); + return; + } + + avio_read(pb, value, size); + if (!value[0]) { + av_free(value); + return; + } + + value[size] = 0; + av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL); +} + +static void read_uint8(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt) +{ + char value[4]; + snprintf(value, sizeof(value), "%i", avio_r8(pb)); + av_dict_set(&avctx->metadata, tag, value, 0); +} + +static void read_uint16(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt) +{ + char value[8]; + snprintf(value, sizeof(value), "%i", avio_rl16(pb)); + av_dict_set(&avctx->metadata, tag, value, 0); +} + +static void read_uint32(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt) +{ + char value[16]; + snprintf(value, sizeof(value), fmt, avio_rl32(pb)); + av_dict_set(&avctx->metadata, tag, value, 0); +} + +static void read_uint64(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt) +{ + char value[32]; + snprintf(value, sizeof(value), fmt, avio_rl64(pb)); + av_dict_set(&avctx->metadata, tag, value, 0); +} + +static int scan_file(AVFormatContext *avctx, AVStream *vst, AVStream *ast, int file) +{ + MlvContext *mlv = avctx->priv_data; + AVIOContext *pb = mlv->pb[file]; + int ret; + while (!url_feof(pb)) { + int type; + unsigned int size; + type = avio_rl32(pb); + size = avio_rl32(pb); + avio_skip(pb, 8); //timestamp + if (size < 16) + break; + size -= 16; + if (vst && type == MKTAG('R','A','W','I') && size >= 164) { + vst->codec->width = avio_rl16(pb); + vst->codec->height = avio_rl16(pb); + if (avio_rl32(pb) != 1) + avpriv_request_sample(avctx, "raw api version"); + avio_skip(pb, 20); // pointer, width, height, pitch, frame_size + vst->codec->bits_per_coded_sample = avio_rl32(pb); + avio_skip(pb, 8 + 16 + 24); // black_level, white_level, xywh, active_area, exposure_bias + if (avio_rl32(pb) != 0x2010100) /* RGGB */ + avpriv_request_sample(avctx, "cfa_pattern"); + avio_skip(pb, 80); // calibration_illuminant1, color_matrix1, dynamic_range + vst->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB16LE; + vst->codec->codec_tag = MKTAG('B', 'I', 'T', 16); + size -= 164; + } else if (ast && type == MKTAG('W', 'A', 'V', 'I') && size >= 16) { + ret = ff_get_wav_header(pb, ast->codec, 16); + if (ret < 0) + return ret; + size -= 16; + } else if (type == MKTAG('I','N','F','O')) { + if (size > 0) + read_string(avctx, pb, "info", size); + continue; + } else if (type == MKTAG('I','D','N','T') && size >= 36) { + read_string(avctx, pb, "cameraName", 32); + read_uint32(avctx, pb, "cameraModel", "0x%"PRIx32); + size -= 36; + if (size >= 32) { + read_string(avctx, pb, "cameraSerial", 32); + size -= 32; + } + } else if (type == MKTAG('L','E','N','S') && size >= 48) { + read_uint16(avctx, pb, "focalLength", "%i"); + read_uint16(avctx, pb, "focalDist", "%i"); + read_uint16(avctx, pb, "aperture", "%i"); + read_uint8(avctx, pb, "stabilizerMode", "%i"); + read_uint8(avctx, pb, "autofocusMode", "%i"); + read_uint32(avctx, pb, "flags", "0x%"PRIx32); + read_uint32(avctx, pb, "lensID", "%"PRIi32); + read_string(avctx, pb, "lensName", 32); + size -= 48; + if (size >= 32) { + read_string(avctx, pb, "lensSerial", 32); + size -= 32; + } + } else if (vst && type == MKTAG('V', 'I', 'D', 'F') && size >= 4) { + uint64_t pts = avio_rl32(pb); + ff_add_index_entry(&vst->index_entries, &vst->nb_index_entries, &vst->index_entries_allocated_size, + avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME); + size -= 4; + } else if (ast && type == MKTAG('A', 'U', 'D', 'F') && size >= 4) { + uint64_t pts = avio_rl32(pb); + ff_add_index_entry(&ast->index_entries, &ast->nb_index_entries, &ast->index_entries_allocated_size, + avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME); + size -= 4; + } else if (vst && type == MKTAG('W','B','A','L') && size >= 28) { + read_uint32(avctx, pb, "wb_mode", "%"PRIi32); + read_uint32(avctx, pb, "kelvin", "%"PRIi32); + read_uint32(avctx, pb, "wbgain_r", "%"PRIi32); + read_uint32(avctx, pb, "wbgain_g", "%"PRIi32); + read_uint32(avctx, pb, "wbgain_b", "%"PRIi32); + read_uint32(avctx, pb, "wbs_gm", "%"PRIi32); + read_uint32(avctx, pb, "wbs_ba", "%"PRIi32); + size -= 28; + } else if (type == MKTAG('R','T','C','I') && size >= 20) { + char str[32]; + struct tm time = { 0 }; + time.tm_sec = avio_rl16(pb); + time.tm_min = avio_rl16(pb); + time.tm_hour = avio_rl16(pb); + time.tm_mday = avio_rl16(pb); + time.tm_mon = avio_rl16(pb); + time.tm_year = avio_rl16(pb); + time.tm_wday = avio_rl16(pb); + time.tm_yday = avio_rl16(pb); + time.tm_isdst = avio_rl16(pb); + avio_skip(pb, 2); + strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time); + av_dict_set(&avctx->metadata, "time", str, 0); + size -= 20; + } else if (type == MKTAG('E','X','P','O') && size >= 16) { + av_dict_set(&avctx->metadata, "isoMode", avio_rl32(pb) ? "auto" : "manual", 0); + read_uint32(avctx, pb, "isoValue", "%"PRIi32); + read_uint32(avctx, pb, "isoAnalog", "%"PRIi32); + read_uint32(avctx, pb, "digitalGain", "%"PRIi32); + size -= 16; + if (size >= 8) { + read_uint64(avctx, pb, "shutterValue", "%"PRIi64); + size -= 8; + } + } else if (type == MKTAG('S','T','Y','L') && size >= 36) { + read_uint32(avctx, pb, "picStyleId", "%"PRIi32); + read_uint32(avctx, pb, "contrast", "%"PRIi32); + read_uint32(avctx, pb, "sharpness", "%"PRIi32); + read_uint32(avctx, pb, "saturation", "%"PRIi32); + read_uint32(avctx, pb, "colortone", "%"PRIi32); + read_string(avctx, pb, "picStyleName", 16); + size -= 36; + } else if (type == MKTAG('M','A','R','K')) { + } else if (type == MKTAG('N','U','L','L')) { + } else if (type == MKTAG('M','L','V','I')) { /* occurs when MLV and Mnn files are concatenated */ + } else { + av_log(avctx, AV_LOG_INFO, "unsupported tag %c%c%c%c, size %u\n", type&0xFF, (type>>8)&0xFF, (type>>16)&0xFF, (type>>24)&0xFF, size); + } + avio_skip(pb, size); + } + return 0; +} + +static int read_header(AVFormatContext *avctx) +{ + MlvContext *mlv = avctx->priv_data; + AVIOContext *pb = avctx->pb; + AVStream *vst = NULL, *ast = NULL; + int size, ret; + uint64_t guid; + char guidstr[32]; + + avio_skip(pb, 4); + size = avio_rl32(pb); + if (size < 52) + return AVERROR_INVALIDDATA; + + avio_skip(pb, 8); + + guid = avio_rl64(pb); + snprintf(guidstr, sizeof(guidstr), "0x%"PRIx64, guid); + av_dict_set(&avctx->metadata, "guid", guidstr, 0); + + avio_skip(pb, 8); //fileNum, fileCount, fileFlags + + mlv->class[0] = avio_rl16(pb); + if (mlv->class[0]) { + vst = avformat_new_stream(avctx, NULL); + if (!vst) + return AVERROR(ENOMEM); + vst->id = 0; + if ((mlv->class[0] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA))) + avpriv_request_sample(avctx, "compression"); + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + switch (mlv->class[0] & ~(MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA)) { + case MLV_VIDEO_CLASS_RAW: + vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + break; + case MLV_VIDEO_CLASS_YUV: + vst->codec->pix_fmt = AV_PIX_FMT_YUV420P; + vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + vst->codec->codec_tag = 0; + break; + case MLV_VIDEO_CLASS_JPEG: + vst->codec->codec_id = AV_CODEC_ID_MJPEG; + vst->codec->codec_tag = 0; + break; + case MLV_VIDEO_CLASS_H264: + vst->codec->codec_id = AV_CODEC_ID_H264; + vst->codec->codec_tag = 0; + break; + default: + avpriv_request_sample(avctx, "unknown video class"); + } + } + + mlv->class[1] = avio_rl16(pb); + if (mlv->class[1]) { + ast = avformat_new_stream(avctx, NULL); + if (!ast) + return AVERROR(ENOMEM); + ast->id = 1; + if ((mlv->class[1] & MLV_CLASS_FLAG_LZMA)) + avpriv_request_sample(avctx, "compression"); + if ((mlv->class[1] & ~MLV_CLASS_FLAG_LZMA) != MLV_AUDIO_CLASS_WAV) + avpriv_request_sample(avctx, "unknown audio class"); + + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate); + } + + if (vst) + vst->nb_frames = avio_rl32(pb); + else + avio_skip(pb, 4); + + if (ast) + ast->nb_frames = avio_rl32(pb); + else + avio_skip(pb, 4); + + if (vst) { + AVRational framerate; + framerate.num = avio_rl32(pb); + framerate.den = avio_rl32(pb); + avpriv_set_pts_info(vst, 64, framerate.den, framerate.num); + } else + avio_skip(pb, 8); + + avio_skip(pb, size - 52); + + /* scan primary file */ + mlv->pb[100] = avctx->pb; + ret = scan_file(avctx, vst, ast, 100); + if (ret < 0) + return ret; + + /* scan secondary files */ + if (strlen(avctx->filename) > 2) { + int i; + char *filename = av_strdup(avctx->filename); + if (!filename) + return AVERROR(ENOMEM); + for (i = 0; i < 100; i++) { + snprintf(filename + strlen(filename) - 2, 3, "%02d", i); + if (avio_open2(&mlv->pb[i], filename, AVIO_FLAG_READ, &avctx->interrupt_callback, NULL) < 0) + break; + if (check_file_header(mlv->pb[i], guid) < 0) { + av_log(avctx, AV_LOG_WARNING, "ignoring %s; bad format or guid mismatch\n", filename); + avio_close(mlv->pb[i]); + mlv->pb[i] = NULL; + continue; + } + av_log(avctx, AV_LOG_INFO, "scanning %s\n", filename); + ret = scan_file(avctx, vst, ast, i); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "ignoring %s; %s\n", filename, av_err2str(ret)); + avio_close(mlv->pb[i]); + mlv->pb[i] = NULL; + continue; + } + } + av_free(filename); + } + + if (vst) + vst->duration = vst->nb_index_entries; + if (ast) + ast->duration = ast->nb_index_entries; + + if (vst && ast) + avio_seek(pb, FFMIN(vst->index_entries[0].pos, ast->index_entries[0].pos), SEEK_SET); + else if (vst) + avio_seek(pb, vst->index_entries[0].pos, SEEK_SET); + else if (ast) + avio_seek(pb, ast->index_entries[0].pos, SEEK_SET); + + return 0; +} + +static int read_packet(AVFormatContext *avctx, AVPacket *pkt) +{ + MlvContext *mlv = avctx->priv_data; + AVIOContext *pb; + AVStream *st = avctx->streams[mlv->stream_index]; + int index, ret; + unsigned int size, space; + + if (mlv->pts >= st->duration) + return AVERROR_EOF; + + index = av_index_search_timestamp(st, mlv->pts, AVSEEK_FLAG_ANY); + if (index < 0) { + av_log(avctx, AV_LOG_ERROR, "could not find index entry for frame %"PRId64"\n", mlv->pts); + return AVERROR(EIO); + } + + pb = mlv->pb[st->index_entries[index].size]; + avio_seek(pb, st->index_entries[index].pos, SEEK_SET); + + avio_skip(pb, 4); // blockType + size = avio_rl32(pb); + if (size < 16) + return AVERROR_INVALIDDATA; + avio_skip(pb, 12); //timestamp, frameNumber + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + avio_skip(pb, 8); // cropPosX, cropPosY, panPosX, panPosY + space = avio_rl32(pb); + avio_skip(pb, space); + + if ((mlv->class[st->id] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA))) { + ret = AVERROR_PATCHWELCOME; + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + ret = av_get_packet(pb, pkt, (st->codec->width * st->codec->height * st->codec->bits_per_coded_sample + 7) >> 3); + } else { // AVMEDIA_TYPE_AUDIO + if (space > UINT_MAX - 24 || size < (24 + space)) + return AVERROR_INVALIDDATA; + ret = av_get_packet(pb, pkt, size - (24 + space)); + } + + if (ret < 0) + return ret; + + pkt->stream_index = mlv->stream_index; + pkt->pts = mlv->pts; + + mlv->stream_index++; + if (mlv->stream_index == avctx->nb_streams) { + mlv->stream_index = 0; + mlv->pts++; + } + return 0; +} + +static int read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags) +{ + MlvContext *mlv = avctx->priv_data; + + if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) + return AVERROR(ENOSYS); + + if (!avctx->pb->seekable) + return AVERROR(EIO); + + mlv->pts = timestamp; + return 0; +} + +static int read_close(AVFormatContext *s) +{ + MlvContext *mlv = s->priv_data; + int i; + for (i = 0; i < 100; i++) + if (mlv->pb[i]) + avio_close(mlv->pb[i]); + return 0; +} + +AVInputFormat ff_mlv_demuxer = { + .name = "mlv", + .long_name = NULL_IF_CONFIG_SMALL("Magic Lantern Video (MLV)"), + .priv_data_size = sizeof(MlvContext), + .read_probe = probe, + .read_header = read_header, + .read_packet = read_packet, + .read_close = read_close, + .read_seek = read_seek, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/mms.c b/chromium/third_party/ffmpeg/libavformat/mms.c index 46fbede90c4..7e60b3bec60 100644 --- a/chromium/third_party/ffmpeg/libavformat/mms.c +++ b/chromium/third_party/ffmpeg/libavformat/mms.c @@ -1,7 +1,7 @@ /* * MMS protocol common definitions. * Copyright (c) 2006,2007 Ryan Martell - * Copyright (c) 2007 Björn Axelsson + * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com> * * This file is part of FFmpeg. diff --git a/chromium/third_party/ffmpeg/libavformat/mmsh.c b/chromium/third_party/ffmpeg/libavformat/mmsh.c index 482ece40316..dac5d9f6539 100644 --- a/chromium/third_party/ffmpeg/libavformat/mmsh.c +++ b/chromium/third_party/ffmpeg/libavformat/mmsh.c @@ -119,7 +119,7 @@ static int read_data_packet(MMSHContext *mmsh, const int len) int res; if (len > sizeof(mms->in_buffer)) { av_log(NULL, AV_LOG_ERROR, - "Data packet length %d exceeds the in_buffer size %zu\n", + "Data packet length %d exceeds the in_buffer size %"SIZE_SPECIFIER"\n", len, sizeof(mms->in_buffer)); return AVERROR(EIO); } @@ -194,7 +194,7 @@ static int get_http_header_data(MMSHContext *mmsh) if (len) { if (len > sizeof(mms->in_buffer)) { av_log(NULL, AV_LOG_ERROR, - "Other packet len = %d exceed the in_buffer size %zu\n", + "Other packet len = %d exceed the in_buffer size %"SIZE_SPECIFIER"\n", len, sizeof(mms->in_buffer)); return AVERROR(EIO); } diff --git a/chromium/third_party/ffmpeg/libavformat/mmst.c b/chromium/third_party/ffmpeg/libavformat/mmst.c index 382895566ee..c851187dafb 100644 --- a/chromium/third_party/ffmpeg/libavformat/mmst.c +++ b/chromium/third_party/ffmpeg/libavformat/mmst.c @@ -1,7 +1,7 @@ /* * MMS protocol over TCP * Copyright (c) 2006,2007 Ryan Martell - * Copyright (c) 2007 Björn Axelsson + * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com> * * This file is part of FFmpeg. @@ -284,7 +284,7 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst) if (length_remaining < 0 || length_remaining > sizeof(mms->in_buffer) - 12) { av_log(NULL, AV_LOG_ERROR, - "Incoming packet length %d exceeds bufsize %zu\n", + "Incoming packet length %d exceeds bufsize %"SIZE_SPECIFIER"\n", length_remaining, sizeof(mms->in_buffer) - 12); return AVERROR_INVALIDDATA; } @@ -320,7 +320,7 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst) if (length_remaining < 0 || length_remaining > sizeof(mms->in_buffer) - 8) { av_log(NULL, AV_LOG_ERROR, - "Data length %d is invalid or too large (max=%zu)\n", + "Data length %d is invalid or too large (max=%"SIZE_SPECIFIER")\n", length_remaining, sizeof(mms->in_buffer)); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/mov.c b/chromium/third_party/ffmpeg/libavformat/mov.c index 0157a7dc8a9..b0500d9756c 100644 --- a/chromium/third_party/ffmpeg/libavformat/mov.c +++ b/chromium/third_party/ffmpeg/libavformat/mov.c @@ -23,6 +23,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> #include <limits.h> #include <stdint.h> @@ -46,6 +47,7 @@ #include "libavcodec/get_bits.h" #include "id3v1.h" #include "mov_chan.h" +#include "replaygain.h" #if CONFIG_ZLIB #include <zlib.h> @@ -129,74 +131,6 @@ static int mov_metadata_gnre(MOVContext *c, AVIOContext *pb, return 0; } -static int mov_read_custom_metadata(MOVContext *c, AVIOContext *pb, MOVAtom atom) -{ - char key[1024]={0}, data[1024]={0}; - int i; - AVStream *st; - MOVStreamContext *sc; - - if (c->fc->nb_streams < 1) - return 0; - st = c->fc->streams[c->fc->nb_streams-1]; - sc = st->priv_data; - - if (atom.size <= 8) return 0; - - for (i = 0; i < 3; i++) { // Parse up to three sub-atoms looking for name and data. - int data_size = avio_rb32(pb); - int tag = avio_rl32(pb); - int str_size = 0, skip_size = 0; - char *target = NULL; - - switch (tag) { - case MKTAG('n','a','m','e'): - avio_rb32(pb); // version/flags - str_size = skip_size = data_size - 12; - atom.size -= 12; - target = key; - break; - case MKTAG('d','a','t','a'): - avio_rb32(pb); // version/flags - avio_rb32(pb); // reserved (zero) - str_size = skip_size = data_size - 16; - atom.size -= 16; - target = data; - break; - default: - skip_size = data_size - 8; - str_size = 0; - break; - } - - if (target) { - str_size = FFMIN3(sizeof(data)-1, str_size, atom.size); - avio_read(pb, target, str_size); - target[str_size] = 0; - } - atom.size -= skip_size; - - // If we didn't read the full data chunk for the sub-atom, skip to the end of it. - if (skip_size > str_size) avio_skip(pb, skip_size - str_size); - } - - if (*key && *data) { - if (strcmp(key, "iTunSMPB") == 0) { - int priming, remainder, samples; - if(sscanf(data, "%*X %X %X %X", &priming, &remainder, &samples) == 3){ - if(priming>0 && priming<16384) - sc->start_pad = priming; - return 1; - } - } - if (strcmp(key, "cdec") == 0) { -// av_dict_set(&st->metadata, key, data, 0); - return 1; - } - } - return 0; -} - static const uint32_t mac_to_unicode[128] = { 0x00C4,0x00C5,0x00C7,0x00C9,0x00D1,0x00D6,0x00DC,0x00E1, 0x00E0,0x00E2,0x00E4,0x00E3,0x00E5,0x00E7,0x00E9,0x00E8, @@ -298,15 +232,14 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) uint32_t data_type = 0, str_size; int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL; - if (c->itunes_metadata && atom.type == MKTAG('-','-','-','-')) - return mov_read_custom_metadata(c, pb, atom); - switch (atom.type) { case MKTAG(0xa9,'n','a','m'): key = "title"; break; case MKTAG(0xa9,'a','u','t'): case MKTAG(0xa9,'A','R','T'): key = "artist"; break; case MKTAG( 'a','A','R','T'): key = "album_artist"; break; case MKTAG(0xa9,'w','r','t'): key = "composer"; break; + case MKTAG( 'c','p','i','l'): key = "compilation"; + parse = mov_metadata_int8_no_padding; break; case MKTAG( 'c','p','r','t'): case MKTAG(0xa9,'c','p','y'): key = "copyright"; break; case MKTAG(0xa9,'g','r','p'): key = "grouping"; break; @@ -362,8 +295,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) int ret = mov_read_covr(c, pb, data_type, str_size); if (ret < 0) { av_log(c->fc, AV_LOG_ERROR, "Error parsing cover art.\n"); - return ret; } + return ret; } } else return 0; } else if (atom.size > 4 && key && !c->itunes_metadata) { @@ -394,7 +327,9 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff))) { // MAC Encoded mov_read_mac_string(c, pb, str_size, str, sizeof(str)); } else { - avio_read(pb, str, str_size); + int ret = avio_read(pb, str, str_size); + if (ret != str_size) + return ret < 0 ? ret : AVERROR_INVALIDDATA; str[str_size] = 0; } av_dict_set(&c->fc->metadata, key, str, 0); @@ -537,7 +472,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) dref->dir = av_malloc(len+1); if (!dref->dir) return AVERROR(ENOMEM); - avio_read(pb, dref->dir, len); + if (avio_read(pb, dref->dir, len) != len) + return AVERROR_INVALIDDATA; dref->dir[len] = 0; for (j = 0; j < len; j++) if (dref->dir[j] == ':') @@ -764,7 +700,7 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type); av_dict_set(&c->fc->metadata, "major_brand", type, 0); minor_ver = avio_rb32(pb); /* minor version */ - snprintf(minor_ver_str, sizeof(minor_ver_str), "%d", minor_ver); + snprintf(minor_ver_str, sizeof(minor_ver_str), "%"PRIu32"", minor_ver); av_dict_set(&c->fc->metadata, "minor_version", minor_ver_str, 0); comp_brand_size = atom.size - 8; @@ -1002,7 +938,14 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom, st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE; AV_WB32( buf , atom.size + 8); AV_WL32( buf + 4, atom.type); - avio_read(pb, buf + 8, atom.size); + err = avio_read(pb, buf + 8, atom.size); + if (err < 0) { + return err; + } else if (err < atom.size) { + av_log(c->fc, AV_LOG_WARNING, "truncated extradata\n"); + st->codec->extradata_size -= atom.size - err; + } + memset(buf + 8 + err, 0, FF_INPUT_BUFFER_PADDING_SIZE); return 0; } @@ -1080,9 +1023,8 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codec->codec_id == AV_CODEC_ID_SPEEX) { // pass all frma atom to codec, needed at least for QDMC and QDM2 av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, atom.size)) + if (ff_get_extradata(st->codec, pb, atom.size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, atom.size); } else if (atom.size > 8) { /* to read frma, esds atoms */ int ret; if ((ret = mov_read_default(c, pb, atom)) < 0) @@ -1117,9 +1059,9 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_default(c, pb, atom); } av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, atom.size)) + if (ff_get_extradata(st->codec, pb, atom.size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, atom.size); + return 0; } @@ -1127,6 +1069,7 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; uint8_t profile_level; + int ret; if (c->fc->nb_streams < 1) return 0; @@ -1139,11 +1082,11 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((profile_level & 0xf0) != 0xc0) return 0; - av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, atom.size - 7)) - return AVERROR(ENOMEM); avio_seek(pb, 6, SEEK_CUR); - avio_read(pb, st->codec->extradata, st->codec->extradata_size); + av_free(st->codec->extradata); + if ((ret = ff_get_extradata(st->codec, pb, atom.size - 7)) < 0) + return ret; + return 0; } @@ -1165,11 +1108,10 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((uint64_t)atom.size > (1<<30)) return AVERROR_INVALIDDATA; + avio_skip(pb, 40); av_free(st->codec->extradata); - if (ff_alloc_extradata(st->codec, atom.size - 40)) + if (ff_get_extradata(st->codec, pb, atom.size - 40) < 0) return AVERROR(ENOMEM); - avio_skip(pb, 40); - avio_read(pb, st->codec->extradata, atom.size - 40); return 0; } @@ -1266,6 +1208,7 @@ static int mov_codec_id(AVStream *st, uint32_t format) static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, AVStream *st, MOVStreamContext *sc) { + uint8_t codec_name[32]; unsigned int color_depth, len, j; int color_greyscale; int color_table_id; @@ -1287,18 +1230,22 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, len = avio_r8(pb); /* codec name, pascal string */ if (len > 31) len = 31; - mov_read_mac_string(c, pb, len, st->codec->codec_name, 32); + mov_read_mac_string(c, pb, len, codec_name, sizeof(codec_name)); if (len < 31) avio_skip(pb, 31 - len); + + if (codec_name[0]) + av_dict_set(&st->metadata, "encoder", codec_name, 0); + /* codec_tag YV12 triggers an UV swap in rawdec.c */ - if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) { + if (!memcmp(codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) { st->codec->codec_tag = MKTAG('I', '4', '2', '0'); st->codec->width &= ~1; st->codec->height &= ~1; } /* Flash Media Server uses tag H263 with Sorenson Spark */ if (st->codec->codec_tag == MKTAG('H','2','6','3') && - !memcmp(st->codec->codec_name, "Sorenson H263", 13)) + !memcmp(codec_name, "Sorenson H263", 13)) st->codec->codec_id = AV_CODEC_ID_FLV1; st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */ @@ -1308,6 +1255,9 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, /* figure out the palette situation */ color_depth = st->codec->bits_per_coded_sample & 0x1F; color_greyscale = st->codec->bits_per_coded_sample & 0x20; + /* Do not create a greyscale palette for cinepak */ + if (color_greyscale && st->codec->codec_id == AV_CODEC_ID_CINEPAK) + return; /* if the depth is 2, 4, or 8 bpp, file is palettized */ if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) { @@ -1323,9 +1273,6 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, color_index = 255; color_dec = 256 / (color_count - 1); for (j = 0; j < color_count; j++) { - if (st->codec->codec_id == AV_CODEC_ID_CINEPAK){ - r = g = b = color_count - 1 - color_index; - } else r = g = b = color_index; sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); color_index -= color_dec; @@ -1477,14 +1424,64 @@ static void mov_parse_stsd_subtitle(MOVContext *c, AVIOContext *pb, st->codec->height = sc->height; } +static uint32_t yuv_to_rgba(uint32_t ycbcr) +{ + uint8_t r, g, b; + int y, cb, cr; + + y = (ycbcr >> 16) & 0xFF; + cr = (ycbcr >> 8) & 0xFF; + cb = ycbcr & 0xFF; + + b = av_clip_uint8(1.164 * (y - 16) + 2.018 * (cb - 128)); + g = av_clip_uint8(1.164 * (y - 16) - 0.813 * (cr - 128) - 0.391 * (cb - 128)); + r = av_clip_uint8(1.164 * (y - 16) + 1.596 * (cr - 128)); + + return (r << 16) | (g << 8) | b; +} + +static int mov_rewrite_dvd_sub_extradata(AVStream *st) +{ + char buf[256] = {0}; + uint8_t *src = st->codec->extradata; + int i; + + if (st->codec->extradata_size != 64) + return 0; + + if (st->codec->width > 0 && st->codec->height > 0) + snprintf(buf, sizeof(buf), "size: %dx%d\n", + st->codec->width, st->codec->height); + av_strlcat(buf, "palette: ", sizeof(buf)); + + for (i = 0; i < 16; i++) { + uint32_t yuv = AV_RB32(src + i * 4); + uint32_t rgba = yuv_to_rgba(yuv); + + av_strlcatf(buf, sizeof(buf), "%06"PRIx32"%s", rgba, i != 15 ? ", " : ""); + } + + if (av_strlcat(buf, "\n", sizeof(buf)) >= sizeof(buf)) + return 0; + + av_freep(&st->codec->extradata); + st->codec->extradata_size = 0; + st->codec->extradata = av_mallocz(strlen(buf) + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata_size = strlen(buf); + memcpy(st->codec->extradata, buf, st->codec->extradata_size); + + return 0; +} + static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb, AVStream *st, MOVStreamContext *sc, int size) { if (st->codec->codec_tag == MKTAG('t','m','c','d')) { - if (ff_alloc_extradata(st->codec, size)) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, size); if (size > 16) { MOVStreamContext *tmcd_ctx = st->priv_data; int val; @@ -1529,6 +1526,10 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, // force sample rate for qcelp when not stored in mov if (st->codec->codec_tag != MKTAG('Q','c','l','p')) st->codec->sample_rate = 8000; + // FIXME: Why is the following needed for some files? + sc->samples_per_frame = 160; + if (!sc->bytes_per_frame) + sc->bytes_per_frame = 35; break; case AV_CODEC_ID_AMR_NB: st->codec->channels = 1; @@ -1561,11 +1562,7 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, } break; case AV_CODEC_ID_AC3: - st->need_parsing = AVSTREAM_PARSE_FULL; - break; case AV_CODEC_ID_MPEG1VIDEO: - st->need_parsing = AVSTREAM_PARSE_FULL; - break; case AV_CODEC_ID_VC1: st->need_parsing = AVSTREAM_PARSE_FULL; break; @@ -1906,6 +1903,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (entries >= UINT_MAX / sizeof(*sc->stts_data)) return -1; + av_free(sc->stts_data); sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data)); if (!sc->stts_data) return AVERROR(ENOMEM); @@ -1919,7 +1917,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) /* sample_duration < 0 is invalid based on the spec */ if (sample_duration < 0) { - av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d\n", sample_duration); + av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta %d in STTS, at %d st:%d\n", + sample_duration, i, c->fc->nb_streams-1); sample_duration = 1; } if (sample_count < 0) { @@ -1932,12 +1931,21 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dlog(c->fc, "sample_count=%d, sample_duration=%d\n", sample_count, sample_duration); + if ( i+1 == entries + && i + && sample_count == 1 + && total_sample_count > 100 + && sample_duration/10 > duration / total_sample_count) + sample_duration = duration / total_sample_count; duration+=(int64_t)sample_duration*sample_count; total_sample_count+=sample_count; } sc->stts_count = i; + sc->duration_for_fps += duration; + sc->nb_frames_for_fps += total_sample_count; + if (pb->eof_reached) return AVERROR_EOF; @@ -2145,6 +2153,11 @@ static void mov_build_index(MOVContext *mov, AVStream *st) rap_group_index++; } } + if (sc->keyframe_absent + && !sc->stps_count + && !rap_group_present + && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + keyframe = 1; if (keyframe) distance = 0; sample_size = sc->stsz_sample_size > 0 ? sc->stsz_sample_size : sc->sample_sizes[current_sample]; @@ -2379,10 +2392,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) ((double)st->codec->width * sc->height), INT_MAX); } - if (st->duration > 0) - av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, - sc->time_scale*st->nb_frames, st->duration, INT_MAX); - #if FF_API_R_FRAME_RATE if (sc->stts_count == 1 || (sc->stts_count == 2 && sc->stts_data[1].count == 1)) av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, @@ -2434,6 +2443,103 @@ static int mov_read_ilst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ret; } +static int mov_read_custom_2plus(MOVContext *c, AVIOContext *pb, int size) +{ + int64_t end = avio_tell(pb) + size; + uint8_t *key = NULL, *val = NULL; + int i; + AVStream *st; + MOVStreamContext *sc; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + for (i = 0; i < 2; i++) { + uint8_t **p; + uint32_t len, tag; + + if (end - avio_tell(pb) <= 12) + break; + + len = avio_rb32(pb); + tag = avio_rl32(pb); + avio_skip(pb, 4); // flags + + if (len < 12 || len - 12 > end - avio_tell(pb)) + break; + len -= 12; + + if (tag == MKTAG('n', 'a', 'm', 'e')) + p = &key; + else if (tag == MKTAG('d', 'a', 't', 'a') && len > 4) { + avio_skip(pb, 4); + len -= 4; + p = &val; + } else + break; + + *p = av_malloc(len + 1); + if (!*p) + break; + avio_read(pb, *p, len); + (*p)[len] = 0; + } + + if (key && val) { + if (strcmp(key, "iTunSMPB") == 0) { + int priming, remainder, samples; + if(sscanf(val, "%*X %X %X %X", &priming, &remainder, &samples) == 3){ + if(priming>0 && priming<16384) + sc->start_pad = priming; + } + } else if (strcmp(key, "cdec") == 0) { + } else { + av_dict_set(&c->fc->metadata, key, val, + AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + key = val = NULL; + } + } + + avio_seek(pb, end, SEEK_SET); + av_freep(&key); + av_freep(&val); + return 0; +} + +static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int64_t end = avio_tell(pb) + atom.size; + uint32_t tag, len; + + if (atom.size < 8) + goto fail; + + len = avio_rb32(pb); + tag = avio_rl32(pb); + + if (len > atom.size) + goto fail; + + if (tag == MKTAG('m', 'e', 'a', 'n') && len > 12) { + uint8_t domain[128]; + int domain_len; + + avio_skip(pb, 4); // flags + len -= 12; + + domain_len = avio_get_str(pb, len, domain, sizeof(domain)); + avio_skip(pb, len - domain_len); + return mov_read_custom_2plus(c, pb, end - avio_tell(pb)); + } + +fail: + av_log(c->fc, AV_LOG_VERBOSE, + "Unhandled or malformed custom metadata of size %"PRId64"\n", atom.size); + return 0; +} + static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom) { while (atom.size > 8) { @@ -2701,6 +2807,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) dts += sample_duration; offset += sample_size; sc->data_size += sample_size; + sc->duration_for_fps += sample_duration; + sc->nb_frames_for_fps ++; } if (pb->eof_reached) @@ -2975,6 +3083,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('h','v','c','C'), mov_read_glbl }, { MKTAG('u','u','i','d'), mov_read_uuid }, { MKTAG('C','i','n', 0x8e), mov_read_targa_y216 }, +{ MKTAG('-','-','-','-'), mov_read_custom }, { 0, NULL } }; @@ -3272,15 +3381,20 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->drefs[j].dir); } av_freep(&sc->drefs); + + sc->drefs_count = 0; + if (!sc->pb_is_copied) avio_close(sc->pb); + sc->pb = NULL; av_freep(&sc->chunk_offsets); - av_freep(&sc->keyframes); - av_freep(&sc->sample_sizes); - av_freep(&sc->stps_data); av_freep(&sc->stsc_data); + av_freep(&sc->sample_sizes); + av_freep(&sc->keyframes); av_freep(&sc->stts_data); + av_freep(&sc->stps_data); + av_freep(&sc->rap_group); } if (mov->dv_demux) { @@ -3336,8 +3450,9 @@ static int mov_read_header(AVFormatContext *s) { MOVContext *mov = s->priv_data; AVIOContext *pb = s->pb; - int i, j, err; + int j, err; MOVAtom atom = { AV_RL32("root") }; + int i; mov->fc = s; /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ @@ -3395,6 +3510,19 @@ static int mov_read_header(AVFormatContext *s) if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->codec_id == AV_CODEC_ID_AAC) { st->skip_samples = sc->start_pad; } + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) + av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, + sc->time_scale*(int64_t)sc->nb_frames_for_fps, sc->duration_for_fps, INT_MAX); + if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + if (st->codec->width <= 0 && st->codec->height <= 0) { + st->codec->width = sc->width; + st->codec->height = sc->height; + } + if (st->codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE) { + if ((err = mov_rewrite_dvd_sub_extradata(st)) < 0) + return err; + } + } } if (mov->trex_data) { @@ -3414,6 +3542,19 @@ static int mov_read_header(AVFormatContext *s) ff_rfps_calculate(s); + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + + if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) + continue; + + err = ff_replaygain_export(st, s->metadata); + if (err < 0) { + mov_read_close(s); + return err; + } + } + return 0; } @@ -3617,6 +3758,7 @@ AVInputFormat ff_mov_demuxer = { .name = "mov,mp4,m4a,3gp,3g2,mj2", .long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"), .priv_data_size = sizeof(MOVContext), + .extensions = "mov,mp4,m4a,3gp,3g2,mj2", .read_probe = mov_probe, .read_header = mov_read_header, .read_packet = mov_read_packet, diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.c b/chromium/third_party/ffmpeg/libavformat/movenc.c index 7315417ca2a..adcbcf2c0f8 100644 --- a/chromium/third_party/ffmpeg/libavformat/movenc.c +++ b/chromium/third_party/ffmpeg/libavformat/movenc.c @@ -22,6 +22,7 @@ */ #include <stdint.h> +#include <inttypes.h> #include "movenc.h" #include "avformat.h" @@ -33,12 +34,15 @@ #include "libavcodec/get_bits.h" #include "libavcodec/put_bits.h" #include "libavcodec/vc1.h" +#include "libavcodec/raw.h" #include "internal.h" #include "libavutil/avstring.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/pixdesc.h" +#include "hevc.h" #include "rtpenc.h" #include "mov_chan.h" @@ -66,6 +70,7 @@ static const AVOption options[] = { { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, + { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, }; @@ -348,7 +353,9 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio) // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved) - if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) + if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE) + avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream) + else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_w8(pb, 0x15); // flags (= Audiostream) else avio_w8(pb, 0x11); // flags (= Visualstream) @@ -390,20 +397,24 @@ static int mov_pcm_be_gt16(enum AVCodecID codec_id) static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track) { + int ret; int64_t pos = avio_tell(pb); avio_wb32(pb, 0); avio_wl32(pb, track->tag); // store it byteswapped track->enc->codec_tag = av_bswap16(track->tag >> 16); - ff_put_wav_header(pb, track->enc); + if ((ret = ff_put_wav_header(pb, track->enc, 0)) < 0) + return ret; return update_size(pb, pos); } static int mov_write_wfex_tag(AVIOContext *pb, MOVTrack *track) { + int ret; int64_t pos = avio_tell(pb); avio_wb32(pb, 0); ffio_wfourcc(pb, "wfex"); - ff_put_wav_header(pb, track->enc); + if ((ret = ff_put_wav_header(pb, track->enc, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0) + return ret; return update_size(pb, pos); } @@ -614,7 +625,12 @@ static int get_cluster_duration(MOVTrack *track, int cluster_idx) else next_dts = track->cluster[cluster_idx + 1].dts; - return next_dts - track->cluster[cluster_idx].dts; + next_dts -= track->cluster[cluster_idx].dts; + + av_assert0(next_dts >= 0); + av_assert0(next_dts <= INT_MAX); + + return next_dts; } static int get_samples_per_packet(MOVTrack *track) @@ -767,6 +783,16 @@ static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + + avio_wb32(pb, 0); + ffio_wfourcc(pb, "hvcC"); + ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0); + return update_size(pb, pos); +} + /* also used by all avid codecs (dv, imx, meridien) and their variants */ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) { @@ -823,12 +849,14 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track) return 0; if (track->enc->codec_id == AV_CODEC_ID_H264) tag = MKTAG('a','v','c','1'); + else if (track->enc->codec_id == AV_CODEC_ID_HEVC) tag = MKTAG('h','e','v','1'); else if (track->enc->codec_id == AV_CODEC_ID_AC3) tag = MKTAG('a','c','-','3'); else if (track->enc->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); else if (track->enc->codec_id == AV_CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g'); else if (track->enc->codec_id == AV_CODEC_ID_VC1) tag = MKTAG('v','c','-','1'); else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); + else if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE) tag = MKTAG('m','p','4','s'); return tag; } @@ -901,11 +929,14 @@ static AVRational find_fps(AVFormatContext *s, AVStream *st) static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track) { - int tag = MKTAG('m', '2', 'v', '1'); //fallback tag + int tag = track->enc->codec_tag; int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE; AVStream *st = track->st; int rate = av_q2d(find_fps(s, st)); + if (!tag) + tag = MKTAG('m', '2', 'v', '1'); //fallback tag + if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) { if (track->enc->width == 1280 && track->enc->height == 720) { if (!interlaced) { @@ -984,6 +1015,7 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track) { int tag = track->enc->codec_tag; int i; + enum AVPixelFormat pix_fmt; for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) { if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) { @@ -994,6 +1026,13 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track) } } + pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_mov, + track->enc->bits_per_coded_sample); + if (tag == MKTAG('r','a','w',' ') && + track->enc->pix_fmt != pix_fmt && + track->enc->pix_fmt != AV_PIX_FMT_NONE) + av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n", + av_get_pix_fmt_name(track->enc->pix_fmt)); return tag; } @@ -1122,7 +1161,9 @@ static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track) avio_wb16(pb, 0); /* Reserved */ avio_wb16(pb, 1); /* Data-reference index */ - if (track->enc->extradata_size) + if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE) + mov_write_esds_tag(pb, track); + else if (track->enc->extradata_size) avio_write(pb, track->enc->extradata, track->enc->extradata_size); return update_size(pb, pos); @@ -1221,6 +1262,8 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, 0); } else if (track->enc->codec_id == AV_CODEC_ID_DNXHD) mov_write_avid_tag(pb, track); + else if (track->enc->codec_id == AV_CODEC_ID_HEVC) + mov_write_hvcc_tag(pb, track); else if (track->enc->codec_id == AV_CODEC_ID_H264) { mov_write_avcc_tag(pb, track); if (track->mode == MODE_IPOD) @@ -1539,6 +1582,12 @@ static int mov_write_vmhd_tag(AVIOContext *pb) return 0x14; } +static int is_clcp_track(MOVTrack *track) +{ + return track->tag == MKTAG('c','7','0','8') || + track->tag == MKTAG('c','6','0','8'); +} + static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) { const char *hdlr, *descr = NULL, *hdlr_type = NULL; @@ -1557,12 +1606,17 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) hdlr_type = "soun"; descr = "SoundHandler"; } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { - if (track->tag == MKTAG('c','6','0','8')) { + if (is_clcp_track(track)) { hdlr_type = "clcp"; descr = "ClosedCaptionHandler"; } else { - if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl"; - else hdlr_type = "text"; + if (track->tag == MKTAG('t','x','3','g')) { + hdlr_type = "sbtl"; + } else if (track->tag == MKTAG('m','p','4','s')) { + hdlr_type = "subp"; + } else { + hdlr_type = "text"; + } descr = "SubtitleHandler"; } } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) { @@ -1623,7 +1677,7 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track) else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) mov_write_smhd_tag(pb); else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { - if (track->tag == MKTAG('t','e','x','t') || track->tag == MKTAG('c','6','0','8')) { + if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) { mov_write_gmhd_tag(pb, track); } else { mov_write_nmhd_tag(pb); @@ -1929,10 +1983,16 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box if (track->tag == MKTAG('r','t','p',' ')) mov_write_udta_sdp(pb, track); - if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && track->mode == MODE_MOV) { - double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); - if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) + if (track->mode == MODE_MOV) { + if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { + double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); + if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) { + mov_write_tapt_tag(pb, track); + } + } + if (is_clcp_track(track) && st->sample_aspect_ratio.num) { mov_write_tapt_tag(pb, track); + } } return update_size(pb, pos); } @@ -2203,7 +2263,9 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1); mov_write_string_metadata(s, pb, "\251alb", "album" , 1); mov_write_string_metadata(s, pb, "\251day", "date" , 1); - mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1); + if (!mov->exact && + !mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) + mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1); mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1); mov_write_string_metadata(s, pb, "\251gen", "genre" , 1); mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1); @@ -2219,6 +2281,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_int8_metadata (s, pb, "stik", "media_type",1); mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1); mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1); + mov_write_int8_metadata (s, pb, "cpil", "compilation", 1); mov_write_trkn_tag(pb, mov, s, 0); // track number mov_write_trkn_tag(pb, mov, s, 1); // disc number mov_write_tmpo_tag(pb, s); @@ -2321,14 +2384,9 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { AVIOContext *pb_buf; - int i, ret, size; + int ret, size; uint8_t *buf; - for (i = 0; i < s->nb_streams; i++) - if (mov->tracks[i].enc->flags & CODEC_FLAG_BITEXACT) { - return 0; - } - ret = avio_open_dyn_buf(&pb_buf); if (ret < 0) return ret; @@ -2388,6 +2446,7 @@ static void mov_write_psp_udta_tag(AVIOContext *pb, static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) { + MOVMuxContext *mov = s->priv_data; AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); int64_t pos, pos2; @@ -2412,7 +2471,8 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) avio_wb16(pb, 0x0); /* ? */ avio_wb16(pb, 0x021C); /* data */ - mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04); + if (!mov->exact) + mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04); mov_write_psp_udta_tag(pb, title->value, "eng", 0x01); mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03); @@ -2482,7 +2542,10 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, int src_trk = mov->tracks[i].src_track; mov->tracks[src_trk].tref_tag = mov->tracks[i].tag; mov->tracks[src_trk].tref_id = mov->tracks[i].track_id; - mov->tracks[i].track_duration = mov->tracks[src_trk].track_duration; + //src_trk may have a different timescale than the tmcd track + mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration, + mov->tracks[i].timescale, + mov->tracks[src_trk].timescale); } } @@ -2541,7 +2604,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov) avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n"); avio_printf(pb, "<head>\n"); - avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n", + if (!mov->exact) + avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n", LIBAVFORMAT_IDENT); avio_printf(pb, "</head>\n"); avio_printf(pb, "<body>\n"); @@ -2937,7 +3001,9 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "ftyp"); - if (mov->mode == MODE_3GP) { + if (mov->major_brand && strlen(mov->major_brand) >= 4) + ffio_wfourcc(pb, mov->major_brand); + else if (mov->mode == MODE_3GP) { ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4"); minor = has_h264 ? 0x100 : 0x200; } else if (mov->mode & MODE_3G2) { @@ -3255,6 +3321,17 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) int size = pkt->size; uint8_t *reformatted_data = NULL; + if (trk->entry) { + int64_t duration = pkt->dts - trk->cluster[trk->entry - 1].dts; + if (duration < 0 || duration > INT_MAX) { + av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" / timestamp: %"PRId64" is out of range for mov/mp4 format\n", + duration, pkt->dts + ); + + pkt->dts = trk->cluster[trk->entry - 1].dts + 1; + pkt->pts = AV_NOPTS_VALUE; + } + } if (mov->flags & FF_MOV_FLAG_FRAGMENT) { int ret; if (mov->fragments > 0) { @@ -3321,6 +3398,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } else { size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); } + } else if (enc->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 && + (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) { + /* extradata is Annex B, assume the bitstream is too and convert it */ + if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) { + ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data, &size, 0, NULL); + avio_write(pb, reformatted_data, size); + } else { + size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL); + } } else { avio_write(pb, pkt->data, size); } @@ -3558,7 +3644,7 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum) track->enc->extradata = buf; track->enc->extradata_size = size; } else { - av_free(&buf); + av_freep(&buf); } } #endif @@ -3700,12 +3786,77 @@ static void mov_free(AVFormatContext *s) av_freep(&mov->tracks); } +static uint32_t rgb_to_yuv(uint32_t rgb) +{ + uint8_t r, g, b; + int y, cb, cr; + + r = (rgb >> 16) & 0xFF; + g = (rgb >> 8) & 0xFF; + b = (rgb ) & 0xFF; + + y = av_clip_uint8( 16. + 0.257 * r + 0.504 * g + 0.098 * b); + cb = av_clip_uint8(128. - 0.148 * r - 0.291 * g + 0.439 * b); + cr = av_clip_uint8(128. + 0.439 * r - 0.368 * g - 0.071 * b); + + return (y << 16) | (cr << 8) | cb; +} + +static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track, + AVStream *st) +{ + int i, width = 720, height = 480; + int have_palette = 0, have_size = 0; + uint32_t palette[16]; + char *cur = st->codec->extradata; + + while (cur && *cur) { + if (strncmp("palette:", cur, 8) == 0) { + int i, count; + count = sscanf(cur + 8, + "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", " + "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", " + "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", " + "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"", + &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3], + &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7], + &palette[ 8], &palette[ 9], &palette[10], &palette[11], + &palette[12], &palette[13], &palette[14], &palette[15]); + + for (i = 0; i < count; i++) { + palette[i] = rgb_to_yuv(palette[i]); + } + have_palette = 1; + } else if (!strncmp("size:", cur, 5)) { + sscanf(cur + 5, "%dx%d", &width, &height); + have_size = 1; + } + if (have_palette && have_size) + break; + cur += strcspn(cur, "\n\r"); + cur += strspn(cur, "\n\r"); + } + if (have_palette) { + track->vos_data = av_malloc(16*4); + if (!track->vos_data) + return AVERROR(ENOMEM); + for (i = 0; i < 16; i++) { + AV_WB32(track->vos_data + i * 4, palette[i]); + } + track->vos_len = 16 * 4; + } + st->codec->width = width; + st->codec->height = track->height = height; + + return 0; +} + static int mov_write_header(AVFormatContext *s) { AVIOContext *pb = s->pb; MOVMuxContext *mov = s->priv_data; AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata, "timecode", NULL, 0); - int i, hint_track = 0, tmcd_track = 0; + int i, ret, hint_track = 0, tmcd_track = 0; /* Default mode == MP4 */ mov->mode = MODE_MP4; @@ -3720,6 +3871,10 @@ static int mov_write_header(AVFormatContext *s) else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V; } + for (i = 0; i < s->nb_streams; i++) + if (s->flags & AVFMT_FLAG_BITEXACT) + mov->exact = 1; + /* Set the FRAGMENT flag if any of the fragmentation methods are * enabled. */ if (mov->max_fragment_duration || mov->max_fragment_size || @@ -3745,7 +3900,7 @@ static int mov_write_header(AVFormatContext *s) } if (!supports_edts(mov) && s->avoid_negative_ts < 0) { - s->avoid_negative_ts = 1; + s->avoid_negative_ts = 2; } /* Non-seekable output is ok if using fragmentation. If ism_lookahead @@ -3837,8 +3992,10 @@ static int mov_write_header(AVFormatContext *s) track->mode = mov->mode; track->tag = mov_find_codec_tag(s, track); if (!track->tag) { - av_log(s, AV_LOG_ERROR, "track %d: could not find tag, " - "codec not currently supported in container\n", i); + av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, " + "codec not currently supported in container\n", + avcodec_get_name(st->codec->codec_id), i); + ret = AVERROR(EINVAL); goto error; } /* If hinting of this track is enabled by a later hint track, @@ -3851,6 +4008,7 @@ static int mov_write_header(AVFormatContext *s) track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) { if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) { av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n"); + ret = AVERROR(EINVAL); goto error; } track->height = track->tag >> 24 == 'n' ? 486 : 576; @@ -3877,6 +4035,7 @@ static int mov_write_header(AVFormatContext *s) st->codec->codec_id == AV_CODEC_ID_ILBC){ if (!st->codec->block_align) { av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i); + ret = AVERROR(EINVAL); goto error; } track->sample_size = st->codec->block_align; @@ -3893,6 +4052,7 @@ static int mov_write_header(AVFormatContext *s) track->enc->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) { av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n", i, track->enc->sample_rate); + ret = AVERROR(EINVAL); goto error; } } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { @@ -3913,21 +4073,18 @@ static int mov_write_header(AVFormatContext *s) /* copy extradata if it exists */ if (st->codec->extradata_size) { - track->vos_len = st->codec->extradata_size; - track->vos_data = av_malloc(track->vos_len); - memcpy(track->vos_data, st->codec->extradata, track->vos_len); + if (st->codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE) + mov_create_dvd_sub_decoder_specific_info(track, st); + else { + track->vos_len = st->codec->extradata_size; + track->vos_data = av_malloc(track->vos_len); + memcpy(track->vos_data, st->codec->extradata, track->vos_len); + } } } enable_tracks(s); - if (mov->mode == MODE_ISM) { - /* If no fragmentation options have been set, set a default. */ - if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | - FF_MOV_FLAG_FRAG_CUSTOM)) && - !mov->max_fragment_duration && !mov->max_fragment_size) - mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; - } if (mov->reserved_moov_size){ mov->reserved_moov_pos= avio_tell(pb); @@ -3935,7 +4092,13 @@ static int mov_write_header(AVFormatContext *s) avio_skip(pb, mov->reserved_moov_size); } - if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + if (mov->flags & FF_MOV_FLAG_FRAGMENT) { + /* If no fragmentation options have been set, set a default. */ + if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | + FF_MOV_FLAG_FRAG_CUSTOM)) && + !mov->max_fragment_duration && !mov->max_fragment_size) + mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; + } else { if (mov->flags & FF_MOV_FLAG_FASTSTART) mov->reserved_moov_pos = avio_tell(pb); mov_write_mdat_tag(pb, mov); @@ -3947,7 +4110,7 @@ static int mov_write_header(AVFormatContext *s) mov->time += 0x7C25B080; // 1970 based -> 1904 based if (mov->chapter_track) - if (mov_create_chapter_track(s, mov->chapter_track) < 0) + if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0) goto error; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { @@ -3956,7 +4119,7 @@ static int mov_write_header(AVFormatContext *s) AVStream *st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if (ff_mov_init_hinting(s, hint_track, i) < 0) + if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0) goto error; hint_track++; } @@ -3974,7 +4137,7 @@ static int mov_write_header(AVFormatContext *s) t = av_dict_get(st->metadata, "timecode", NULL, 0); if (!t) continue; - if (mov_create_timecode_track(s, tmcd_track, i, t->value) < 0) + if ((ret = mov_create_timecode_track(s, tmcd_track, i, t->value)) < 0) goto error; tmcd_track++; } @@ -3994,7 +4157,7 @@ static int mov_write_header(AVFormatContext *s) return 0; error: mov_free(s); - return -1; + return ret; } static int get_moov_size(AVFormatContext *s) diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.h b/chromium/third_party/ffmpeg/libavformat/movenc.h index 09f3ea772c8..fce2d3c9329 100644 --- a/chromium/third_party/ffmpeg/libavformat/movenc.h +++ b/chromium/third_party/ffmpeg/libavformat/movenc.h @@ -156,6 +156,7 @@ typedef struct MOVMuxContext { int flags; int rtp_flags; + int exact; int iods_skip; int iods_video_profile; @@ -173,6 +174,8 @@ typedef struct MOVMuxContext { int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise int64_t reserved_moov_pos; + + char *major_brand; } MOVMuxContext; #define FF_MOV_FLAG_RTP_HINT 1 diff --git a/chromium/third_party/ffmpeg/libavformat/mp3dec.c b/chromium/third_party/ffmpeg/libavformat/mp3dec.c index 5d484e9090d..00142c5163c 100644 --- a/chromium/third_party/ffmpeg/libavformat/mp3dec.c +++ b/chromium/third_party/ffmpeg/libavformat/mp3dec.c @@ -22,12 +22,16 @@ #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/crc.h" #include "libavutil/dict.h" #include "libavutil/mathematics.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" #include "id3v2.h" #include "id3v1.h" +#include "replaygain.h" + #include "libavcodec/mpegaudiodecheader.h" #define XING_FLAG_FRAMES 0x01 @@ -39,11 +43,12 @@ typedef struct { AVClass *class; int64_t filesize; - int64_t header_filesize; int xing_toc; int start_pad; int end_pad; int usetoc; + unsigned frames; /* Total number of frames in file */ + unsigned header_filesize; /* Total number of bytes in the stream */ int is_cbr; } MP3DecContext; @@ -85,10 +90,10 @@ static int mp3_read_probe(AVProbeData *p) // issues with MPEG-files! if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1; else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; - else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION / 2; + else if(max_frames>=4 && max_frames >= p->buf_size/10000) return AVPROBE_SCORE_EXTENSION / 2; else if(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size) return p->buf_size < PROBE_BUF_MAX ? AVPROBE_SCORE_EXTENSION / 4 : AVPROBE_SCORE_EXTENSION - 2; - else if(max_frames>=1) return 1; + else if(max_frames>=1 && max_frames >= p->buf_size/10000) return 1; else return 0; //mpegps_mp3_unrecognized_format.mpg has max_frames=3 } @@ -117,19 +122,149 @@ static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration mp3->xing_toc = 1; } +static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, + MPADecodeHeader *c, uint32_t spf) +{ +#define LAST_BITS(k, n) ((k) & ((1 << (n)) - 1)) +#define MIDDLE_BITS(k, m, n) LAST_BITS((k) >> (m), ((n) - (m))) + + uint16_t crc; + uint32_t v; + + char version[10]; + + uint32_t peak = 0; + int32_t r_gain = INT32_MIN, a_gain = INT32_MIN; + + MP3DecContext *mp3 = s->priv_data; + static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; + + /* Check for Xing / Info tag */ + avio_skip(s->pb, xing_offtbl[c->lsf == 1][c->nb_channels == 1]); + v = avio_rb32(s->pb); + mp3->is_cbr = v == MKBETAG('I', 'n', 'f', 'o'); + if (v != MKBETAG('X', 'i', 'n', 'g') && !mp3->is_cbr) + return; + + v = avio_rb32(s->pb); + if (v & XING_FLAG_FRAMES) + mp3->frames = avio_rb32(s->pb); + if (v & XING_FLAG_SIZE) + mp3->header_filesize = avio_rb32(s->pb); + if (v & XING_FLAG_TOC) + read_xing_toc(s, mp3->header_filesize, av_rescale_q(mp3->frames, + (AVRational){spf, c->sample_rate}, + st->time_base)); + /* VBR quality */ + if(v & 8) + avio_skip(s->pb, 4); + + /* Encoder short version string */ + memset(version, 0, sizeof(version)); + avio_read(s->pb, version, 9); + + /* Info Tag revision + VBR method */ + avio_r8(s->pb); + + /* Lowpass filter value */ + avio_r8(s->pb); + + /* ReplayGain peak */ + v = avio_rb32(s->pb); + peak = av_rescale(v, 100000, 1 << 23); + + /* Radio ReplayGain */ + v = avio_rb16(s->pb); + + if (MIDDLE_BITS(v, 13, 15) == 1) { + r_gain = MIDDLE_BITS(v, 0, 8) * 10000; + + if (v & (1 << 9)) + r_gain *= -1; + } + + /* Audiophile ReplayGain */ + v = avio_rb16(s->pb); + + if (MIDDLE_BITS(v, 13, 15) == 2) { + a_gain = MIDDLE_BITS(v, 0, 8) * 10000; + + if (v & (1 << 9)) + a_gain *= -1; + } + + /* Encoding flags + ATH Type */ + avio_r8(s->pb); + + /* if ABR {specified bitrate} else {minimal bitrate} */ + avio_r8(s->pb); + + /* Encoder delays */ + v= avio_rb24(s->pb); + if(AV_RB32(version) == MKBETAG('L', 'A', 'M', 'E') + || AV_RB32(version) == MKBETAG('L', 'a', 'v', 'f')) { + + mp3->start_pad = v>>12; + mp3-> end_pad = v&4095; + st->skip_samples = mp3->start_pad + 528 + 1; + av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad); + } + + /* Misc */ + avio_r8(s->pb); + + /* MP3 gain */ + avio_r8(s->pb); + + /* Preset and surround info */ + avio_rb16(s->pb); + + /* Music length */ + avio_rb32(s->pb); + + /* Music CRC */ + avio_rb16(s->pb); + + /* Info Tag CRC */ + crc = ffio_get_checksum(s->pb); + v = avio_rb16(s->pb); + + if (v == crc) { + ff_replaygain_export_raw(st, r_gain, peak, a_gain, 0); + av_dict_set(&st->metadata, "encoder", version, 0); + } +} + +static void mp3_parse_vbri_tag(AVFormatContext *s, AVStream *st, int64_t base) +{ + uint32_t v; + MP3DecContext *mp3 = s->priv_data; + + /* Check for VBRI tag (always 32 bytes after end of mpegaudio header) */ + avio_seek(s->pb, base + 4 + 32, SEEK_SET); + v = avio_rb32(s->pb); + if (v == MKBETAG('V', 'B', 'R', 'I')) { + /* Check tag version */ + if (avio_rb16(s->pb) == 1) { + /* skip delay and quality */ + avio_skip(s->pb, 4); + mp3->header_filesize = avio_rb32(s->pb); + mp3->frames = avio_rb32(s->pb); + } + } +} + /** * Try to find Xing/Info/VBRI tags and compute duration from info therein */ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) { - MP3DecContext *mp3 = s->priv_data; uint32_t v, spf; - unsigned frames = 0; /* Total number of frames in file */ - unsigned size = 0; /* Total number of bytes in the stream */ - static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; MPADecodeHeader c; int vbrtag_size = 0; - int is_cbr; + MP3DecContext *mp3 = s->priv_data; + + ffio_init_checksum(s->pb, ff_crcA001_update, 0); v = avio_rb32(s->pb); if(ff_mpa_check_header(v) < 0) @@ -142,60 +277,23 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) spf = c.lsf ? 576 : 1152; /* Samples per frame, layer 3 */ - /* Check for Xing / Info tag */ - avio_skip(s->pb, xing_offtbl[c.lsf == 1][c.nb_channels == 1]); - v = avio_rb32(s->pb); - is_cbr = v == MKBETAG('I', 'n', 'f', 'o'); - if (v == MKBETAG('X', 'i', 'n', 'g') || is_cbr) { - v = avio_rb32(s->pb); - if(v & XING_FLAG_FRAMES) - frames = avio_rb32(s->pb); - if(v & XING_FLAG_SIZE) - size = avio_rb32(s->pb); - if (v & XING_FLAG_TOC) - read_xing_toc(s, size, av_rescale_q(frames, (AVRational){spf, c.sample_rate}, - st->time_base)); - if(v & 8) - avio_skip(s->pb, 4); - - v = avio_rb32(s->pb); - if(v == MKBETAG('L', 'A', 'M', 'E') || v == MKBETAG('L', 'a', 'v', 'f')) { - avio_skip(s->pb, 21-4); - v= avio_rb24(s->pb); - mp3->start_pad = v>>12; - mp3-> end_pad = v&4095; - st->skip_samples = mp3->start_pad + 528 + 1; - av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad); - } - } + mp3->frames = 0; + mp3->header_filesize = 0; - /* Check for VBRI tag (always 32 bytes after end of mpegaudio header) */ - avio_seek(s->pb, base + 4 + 32, SEEK_SET); - v = avio_rb32(s->pb); - if(v == MKBETAG('V', 'B', 'R', 'I')) { - /* Check tag version */ - if(avio_rb16(s->pb) == 1) { - /* skip delay and quality */ - avio_skip(s->pb, 4); - size = avio_rb32(s->pb); - frames = avio_rb32(s->pb); - } - } + mp3_parse_info_tag(s, st, &c, spf); + mp3_parse_vbri_tag(s, st, base); - if(!frames && !size) + if (!mp3->frames && !mp3->header_filesize) return -1; /* Skip the vbr tag frame */ avio_seek(s->pb, base + vbrtag_size, SEEK_SET); - if(frames) - st->duration = av_rescale_q(frames, (AVRational){spf, c.sample_rate}, + if (mp3->frames) + st->duration = av_rescale_q(mp3->frames, (AVRational){spf, c.sample_rate}, st->time_base); - if (size && frames && !is_cbr) - st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf); - - mp3->is_cbr = is_cbr; - mp3->header_filesize = size; + if (mp3->header_filesize && mp3->frames && !mp3->is_cbr) + st->codec->bit_rate = av_rescale(mp3->header_filesize, 8 * c.sample_rate, mp3->frames * (int64_t)spf); return 0; } @@ -205,6 +303,7 @@ static int mp3_read_header(AVFormatContext *s) MP3DecContext *mp3 = s->priv_data; AVStream *st; int64_t off; + int ret; st = avformat_new_stream(s, NULL); if (!st) @@ -230,6 +329,10 @@ static int mp3_read_header(AVFormatContext *s) if (mp3_parse_vbr_tags(s, st, off) < 0) avio_seek(s->pb, off, SEEK_SET); + ret = ff_replaygain_export(st, s->metadata); + if (ret < 0) + return ret; + /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -314,6 +417,8 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, return -1; } + if (dir < 0) + avio_seek(s->pb, FFMAX(ie->pos - 4096, 0), SEEK_SET); ret = avio_seek(s->pb, ie->pos, SEEK_SET); if (ret < 0) return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/mp3enc.c b/chromium/third_party/ffmpeg/libavformat/mp3enc.c index a5f672b2577..9c9bd5e8626 100644 --- a/chromium/third_party/ffmpeg/libavformat/mp3enc.c +++ b/chromium/third_party/ffmpeg/libavformat/mp3enc.c @@ -85,6 +85,7 @@ typedef struct MP3Context { ID3v2EncContext id3; int id3v2_version; int write_id3v1; + int write_xing; /* xing header */ int64_t xing_offset; @@ -115,17 +116,18 @@ static int mp3_write_xing(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec; - int bitrate_idx; - int best_bitrate_idx = -1; - int best_bitrate_error= INT_MAX; - int xing_offset; - int32_t header, mask; - MPADecodeHeader c; - int srate_idx, ver = 0, i, channels; - int needed; - const char *vendor = (codec->flags & CODEC_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT; - - if (!s->pb->seekable) + int32_t header; + MPADecodeHeader mpah; + int srate_idx, i, channels; + int bitrate_idx; + int best_bitrate_idx = -1; + int best_bitrate_error = INT_MAX; + int xing_offset; + int ver = 0; + int bytes_needed; + const char *vendor = (codec->flags & CODEC_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT; + + if (!s->pb->seekable || !mp3->write_xing) return 0; for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) { @@ -155,28 +157,29 @@ static int mp3_write_xing(AVFormatContext *s) /* dummy MPEG audio header */ header = 0xffU << 24; // sync header |= (0x7 << 5 | ver << 3 | 0x1 << 1 | 0x1) << 16; // sync/audio-version/layer 3/no crc*/ - header |= (srate_idx << 2) << 8; + header |= (srate_idx << 2) << 8; header |= channels << 6; - for (bitrate_idx=1; bitrate_idx<15; bitrate_idx++) { - int error; - avpriv_mpegaudio_decode_header(&c, header | (bitrate_idx << (4+8))); - error= FFABS(c.bit_rate - codec->bit_rate); - if(error < best_bitrate_error){ - best_bitrate_error= error; - best_bitrate_idx = bitrate_idx; + for (bitrate_idx = 1; bitrate_idx < 15; bitrate_idx++) { + int bit_rate = 1000 * avpriv_mpa_bitrate_tab[ver != 3][3 - 1][bitrate_idx]; + int error = FFABS(bit_rate - codec->bit_rate); + + if (error < best_bitrate_error) { + best_bitrate_error = error; + best_bitrate_idx = bitrate_idx; } } av_assert0(best_bitrate_idx >= 0); - for (bitrate_idx= best_bitrate_idx;; bitrate_idx++) { + for (bitrate_idx = best_bitrate_idx; ; bitrate_idx++) { + int32_t mask = bitrate_idx << (4 + 8); if (15 == bitrate_idx) return -1; - mask = bitrate_idx << (4+8); header |= mask; - avpriv_mpegaudio_decode_header(&c, header); - xing_offset=xing_offtbl[c.lsf == 1][c.nb_channels == 1]; - needed = 4 // header + + avpriv_mpegaudio_decode_header(&mpah, header); + xing_offset=xing_offtbl[mpah.lsf == 1][mpah.nb_channels == 1]; + bytes_needed = 4 // header + xing_offset + 4 // xing tag + 4 // frames/size/toc flags @@ -186,8 +189,9 @@ static int mp3_write_xing(AVFormatContext *s) + 24 ; - if (needed <= c.frame_size) + if (bytes_needed <= mpah.frame_size) break; + header &= ~mask; } @@ -198,7 +202,7 @@ static int mp3_write_xing(AVFormatContext *s) ffio_wfourcc(s->pb, "Xing"); avio_wb32(s->pb, 0x01 | 0x02 | 0x04); // frames / size / TOC - mp3->size = c.frame_size; + mp3->size = mpah.frame_size; mp3->want=1; mp3->seen=0; mp3->pos=0; @@ -216,7 +220,7 @@ static int mp3_write_xing(AVFormatContext *s) avio_w8(s->pb, 0); avio_wb24(s->pb, FFMAX(codec->delay - 528 - 1, 0)<<12); - ffio_fill(s->pb, 0, c.frame_size - needed); + ffio_fill(s->pb, 0, mpah.frame_size - bytes_needed); return 0; } @@ -256,7 +260,7 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) MP3Context *mp3 = s->priv_data; if (pkt->data && pkt->size >= 4) { - MPADecodeHeader c; + MPADecodeHeader mpah; int av_unused base; uint32_t head = AV_RB32(pkt->data); @@ -265,16 +269,16 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) "is invalid, writing it anyway.\n", pkt->size, head); return ff_raw_write_packet(s, pkt); } - avpriv_mpegaudio_decode_header(&c, head); + avpriv_mpegaudio_decode_header(&mpah, head); if (!mp3->initial_bitrate) - mp3->initial_bitrate = c.bit_rate; - if ((c.bit_rate == 0) || (mp3->initial_bitrate != c.bit_rate)) + mp3->initial_bitrate = mpah.bit_rate; + if ((mpah.bit_rate == 0) || (mp3->initial_bitrate != mpah.bit_rate)) mp3->has_variable_bitrate = 1; #ifdef FILTER_VBR_HEADERS /* filter out XING and INFO headers. */ - base = 4 + xing_offtbl[c.lsf == 1][c.nb_channels == 1]; + base = 4 + xing_offtbl[mpah.lsf == 1][mpah.nb_channels == 1]; if (base + 4 <= pkt->size) { uint32_t v = AV_RB32(pkt->data + base); @@ -303,7 +307,7 @@ static int mp3_queue_flush(AVFormatContext *s) AVPacketList *pktl; int ret = 0, write = 1; - ff_id3v2_finish(&mp3->id3, s->pb); + ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding); mp3_write_xing(s); while ((pktl = mp3->queue)) { @@ -393,9 +397,11 @@ AVOutputFormat ff_mp2_muxer = { static const AVOption options[] = { { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.", - offsetof(MP3Context, id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 3, 4, AV_OPT_FLAG_ENCODING_PARAM}, + offsetof(MP3Context, id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 0, 4, AV_OPT_FLAG_ENCODING_PARAM}, { "write_id3v1", "Enable ID3v1 writing. ID3v1 tags are written in UTF-8 which may not be supported by most software.", offsetof(MP3Context, write_id3v1), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "write_xing", "Write the Xing header containing file duration.", + offsetof(MP3Context, write_xing), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; @@ -414,14 +420,14 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt) if (mp3->pics_to_write) { /* buffer audio packets until we get all the pictures */ AVPacketList *pktl = av_mallocz(sizeof(*pktl)); + int ret; if (!pktl) return AVERROR(ENOMEM); - pktl->pkt = *pkt; - pktl->pkt.buf = av_buffer_ref(pkt->buf); - if (!pktl->pkt.buf) { + ret = av_copy_packet(&pktl->pkt, pkt); + if (ret < 0) { av_freep(&pktl); - return AVERROR(ENOMEM); + return ret; } if (mp3->queue_end) @@ -464,6 +470,14 @@ static int mp3_write_header(struct AVFormatContext *s) MP3Context *mp3 = s->priv_data; int ret, i; + if (mp3->id3v2_version && + mp3->id3v2_version != 3 && + mp3->id3v2_version != 4) { + av_log(s, AV_LOG_ERROR, "Invalid ID3v2 version requested: %d. Only " + "3, 4 or 0 (disabled) are allowed.\n", mp3->id3v2_version); + return AVERROR(EINVAL); + } + /* check the streams -- we want exactly one audio and arbitrary number of * video (attached pictures) */ mp3->audio_stream_idx = -1; @@ -487,13 +501,22 @@ static int mp3_write_header(struct AVFormatContext *s) } mp3->pics_to_write = s->nb_streams - 1; - ff_id3v2_start(&mp3->id3, s->pb, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); - ret = ff_id3v2_write_metadata(s, &mp3->id3); - if (ret < 0) - return ret; + if (mp3->pics_to_write && !mp3->id3v2_version) { + av_log(s, AV_LOG_ERROR, "Attached pictures were requested, but the " + "ID3v2 header is disabled.\n"); + return AVERROR(EINVAL); + } + + if (mp3->id3v2_version) { + ff_id3v2_start(&mp3->id3, s->pb, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); + ret = ff_id3v2_write_metadata(s, &mp3->id3); + if (ret < 0) + return ret; + } if (!mp3->pics_to_write) { - ff_id3v2_finish(&mp3->id3, s->pb); + if (mp3->id3v2_version) + ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding); mp3_write_xing(s); } diff --git a/chromium/third_party/ffmpeg/libavformat/mpc.c b/chromium/third_party/ffmpeg/libavformat/mpc.c index 8abc4885536..c3faebe6c07 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpc.c @@ -95,9 +95,8 @@ static int mpc_read_header(AVFormatContext *s) st->codec->channel_layout = AV_CH_LAYOUT_STEREO; st->codec->bits_per_coded_sample = 16; - if (ff_alloc_extradata(st->codec, 16)) + if (ff_get_extradata(st->codec, s->pb, 16) < 0) return AVERROR(ENOMEM); - avio_read(s->pb, st->codec->extradata, 16); st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3]; avpriv_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate); /* scan for seekpoints */ diff --git a/chromium/third_party/ffmpeg/libavformat/mpc8.c b/chromium/third_party/ffmpeg/libavformat/mpc8.c index 7017c187f77..b32bc9c3546 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpc8.c +++ b/chromium/third_party/ffmpeg/libavformat/mpc8.c @@ -136,7 +136,7 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) int tag; int64_t size, pos, ppos[2]; uint8_t *buf; - int i, t, seekd; + int i, t, seekd, ret; GetBitContext gb; if (s->nb_streams == 0) { @@ -156,7 +156,14 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) } if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE))) return; - avio_read(s->pb, buf, size); + ret = avio_read(s->pb, buf, size); + if (ret != size) { + av_log(s, AV_LOG_ERROR, "seek table truncated\n"); + av_free(buf); + return; + } + memset(buf+size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + init_get_bits(&gb, buf, size * 8); size = gb_get_v(&gb); if(size > UINT_MAX/4 || size > c->samples/1152){ @@ -241,9 +248,8 @@ static int mpc8_read_header(AVFormatContext *s) st->codec->codec_id = AV_CODEC_ID_MUSEPACK8; st->codec->bits_per_coded_sample = 16; - if (ff_alloc_extradata(st->codec, 2)) + if (ff_get_extradata(st->codec, pb, 2) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, st->codec->extradata_size); st->codec->channels = (st->codec->extradata[1] >> 4) + 1; st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5]; diff --git a/chromium/third_party/ffmpeg/libavformat/mpeg.c b/chromium/third_party/ffmpeg/libavformat/mpeg.c index 1777283939c..d70a5ab9beb 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/mpeg.c @@ -37,74 +37,85 @@ #define MAX_SYNC_SIZE 100000 -static int check_pes(const uint8_t *p, const uint8_t *end){ +static int check_pes(const uint8_t *p, const uint8_t *end) +{ int pes1; - int pes2= (p[3] & 0xC0) == 0x80 - && (p[4] & 0xC0) != 0x40 - &&((p[4] & 0xC0) == 0x00 || (p[4]&0xC0)>>2 == (p[6]&0xF0)); - - for(p+=3; p<end && *p == 0xFF; p++); - if((*p&0xC0) == 0x40) p+=2; - if((*p&0xF0) == 0x20){ - pes1= p[0]&p[2]&p[4]&1; - }else if((*p&0xF0) == 0x30){ - pes1= p[0]&p[2]&p[4]&p[5]&p[7]&p[9]&1; - }else + int pes2 = (p[3] & 0xC0) == 0x80 && + (p[4] & 0xC0) != 0x40 && + ((p[4] & 0xC0) == 0x00 || + (p[4] & 0xC0) >> 2 == (p[6] & 0xF0)); + + for (p += 3; p < end && *p == 0xFF; p++) ; + if ((*p & 0xC0) == 0x40) + p += 2; + + if ((*p & 0xF0) == 0x20) + pes1 = p[0] & p[2] & p[4] & 1; + else if ((*p & 0xF0) == 0x30) + pes1 = p[0] & p[2] & p[4] & p[5] & p[7] & p[9] & 1; + else pes1 = *p == 0x0F; - return pes1||pes2; + return pes1 || pes2; } -static int check_pack_header(const uint8_t *buf) { +static int check_pack_header(const uint8_t *buf) +{ return (buf[1] & 0xC0) == 0x40 || (buf[1] & 0xF0) == 0x20; } static int mpegps_probe(AVProbeData *p) { - uint32_t code= -1; - int sys=0, pspack=0, priv1=0, vid=0, audio=0, invalid=0; + uint32_t code = -1; int i; - int score=0; + int sys = 0, pspack = 0, priv1 = 0, vid = 0; + int audio = 0, invalid = 0, score = 0; - for(i=0; i<p->buf_size; i++){ - code = (code<<8) + p->buf[i]; + for (i = 0; i < p->buf_size; i++) { + code = (code << 8) + p->buf[i]; if ((code & 0xffffff00) == 0x100) { - int len= p->buf[i+1] << 8 | p->buf[i+2]; - int pes= check_pes(p->buf+i, p->buf+p->buf_size); - int pack = check_pack_header(p->buf+i); - - if(code == SYSTEM_HEADER_START_CODE) sys++; - else if(code == PACK_START_CODE && pack) pspack++; - else if((code & 0xf0) == VIDEO_ID && pes) vid++; + int len = p->buf[i + 1] << 8 | p->buf[i + 2]; + int pes = check_pes(p->buf + i, p->buf + p->buf_size); + int pack = check_pack_header(p->buf + i); + + if (code == SYSTEM_HEADER_START_CODE) + sys++; + else if (code == PACK_START_CODE && pack) + pspack++; + else if ((code & 0xf0) == VIDEO_ID && pes) + vid++; // skip pes payload to avoid start code emulation for private // and audio streams - else if((code & 0xe0) == AUDIO_ID && pes) {audio++; i+=len;} - else if(code == PRIVATE_STREAM_1 && pes) {priv1++; i+=len;} - else if(code == 0x1fd && pes) vid++; //VC1 + else if ((code & 0xe0) == AUDIO_ID && pes) {audio++; i+=len;} + else if (code == PRIVATE_STREAM_1 && pes) {priv1++; i+=len;} + else if (code == 0x1fd && pes) vid++; //VC1 - else if((code & 0xf0) == VIDEO_ID && !pes) invalid++; - else if((code & 0xe0) == AUDIO_ID && !pes) invalid++; - else if(code == PRIVATE_STREAM_1 && !pes) invalid++; + else if ((code & 0xf0) == VIDEO_ID && !pes) invalid++; + else if ((code & 0xe0) == AUDIO_ID && !pes) invalid++; + else if (code == PRIVATE_STREAM_1 && !pes) invalid++; } } - if(vid+audio > invalid+1) /* invalid VDR files nd short PES streams */ + if (vid + audio > invalid + 1) /* invalid VDR files nd short PES streams */ score = AVPROBE_SCORE_EXTENSION / 2; - if(sys>invalid && sys*9 <= pspack*10) - return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg - if(pspack > invalid && (priv1+vid+audio)*10 >= pspack*9) - return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg - if((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys && !pspack && p->buf_size>2048 && vid + audio > invalid) /* PES stream */ - return (audio > 12 || vid > 3 + 2*invalid) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; - - //02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1 - //mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6 - //Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618 + if (sys > invalid && sys * 9 <= pspack * 10) + return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2 + : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg + if (pspack > invalid && (priv1 + vid + audio) * 10 >= pspack * 9) + return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2 + : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg + if ((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys && + !pspack && p->buf_size > 2048 && vid + audio > invalid) /* PES stream */ + return (audio > 12 || vid > 3 + 2 * invalid) ? AVPROBE_SCORE_EXTENSION + 2 + : AVPROBE_SCORE_EXTENSION / 2; + + // 02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1 + // mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6 + // Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618 return score; } - typedef struct MpegDemuxContext { int32_t header_state; unsigned char psm_es_type[256]; @@ -124,7 +135,7 @@ static int mpegps_read_header(AVFormatContext *s) int64_t last_pos = avio_tell(s->pb); m->header_state = 0xff; - s->ctx_flags |= AVFMTCTX_NOHEADER; + s->ctx_flags |= AVFMTCTX_NOHEADER; avio_get_str(s->pb, 6, buffer, sizeof(buffer)); if (!memcmp("IMKH", buffer, 4)) { @@ -142,8 +153,8 @@ static int64_t get_pts(AVIOContext *pb, int c) { uint8_t buf[5]; - buf[0] = c<0 ? avio_r8(pb) : c; - avio_read(pb, buf+1, 4); + buf[0] = c < 0 ? avio_r8(pb) : c; + avio_read(pb, buf + 1, 4); return ff_parse_pes_pts(buf); } @@ -155,7 +166,7 @@ static int find_next_start_code(AVIOContext *pb, int *size_ptr, int val, n; state = *header_state; - n = *size_ptr; + n = *size_ptr; while (n > 0) { if (url_feof(pb)) break; @@ -163,15 +174,16 @@ static int find_next_start_code(AVIOContext *pb, int *size_ptr, n--; if (state == 0x000001) { state = ((state << 8) | v) & 0xffffff; - val = state; + val = state; goto found; } state = ((state << 8) | v) & 0xffffff; } val = -1; - found: + +found: *header_state = state; - *size_ptr = n; + *size_ptr = n; return val; } @@ -197,10 +209,11 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb) es_map_length = psm_length - ps_info_length - 10; /* at least one es available? */ - while (es_map_length >= 4){ + while (es_map_length >= 4) { unsigned char type = avio_r8(pb); unsigned char es_id = avio_r8(pb); uint16_t es_info_length = avio_rb16(pb); + /* remember mapping from stream id to stream type */ m->psm_es_type[es_id] = type; /* skip program_stream_info */ @@ -212,7 +225,7 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb) } /* read the next PES header. Return its position in ppos - (if not NULL), and its start code, pts and dts. + * (if not NULL), and its start code, pts and dts. */ static int mpegps_read_pes_header(AVFormatContext *s, int64_t *ppos, int *pstart_code, @@ -222,20 +235,20 @@ static int mpegps_read_pes_header(AVFormatContext *s, int len, size, startcode, c, flags, header_len; int pes_ext, ext2_len, id_ext, skip; int64_t pts, dts; - int64_t last_sync= avio_tell(s->pb); - - error_redo: - avio_seek(s->pb, last_sync, SEEK_SET); - redo: - /* next start code (should be immediately after) */ - m->header_state = 0xff; - size = MAX_SYNC_SIZE; - startcode = find_next_start_code(s->pb, &size, &m->header_state); - last_sync = avio_tell(s->pb); - if (startcode < 0){ - if(url_feof(s->pb)) + int64_t last_sync = avio_tell(s->pb); + +error_redo: + avio_seek(s->pb, last_sync, SEEK_SET); +redo: + /* next start code (should be immediately after) */ + m->header_state = 0xff; + size = MAX_SYNC_SIZE; + startcode = find_next_start_code(s->pb, &size, &m->header_state); + last_sync = avio_tell(s->pb); + if (startcode < 0) { + if (url_feof(s->pb)) return AVERROR_EOF; - //FIXME we should remember header_state + // FIXME we should remember header_state return AVERROR(EAGAIN); } @@ -346,7 +359,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, if (startcode != PRIVATE_STREAM_2) { /* stuffing */ - for(;;) { + for (;;) { if (len < 1) goto error_redo; c = avio_r8(s->pb); @@ -358,45 +371,47 @@ static int mpegps_read_pes_header(AVFormatContext *s, if ((c & 0xc0) == 0x40) { /* buffer scale & size */ avio_r8(s->pb); - c = avio_r8(s->pb); + c = avio_r8(s->pb); len -= 2; } if ((c & 0xe0) == 0x20) { - dts = pts = get_pts(s->pb, c); + dts = + pts = get_pts(s->pb, c); len -= 4; - if (c & 0x10){ - dts = get_pts(s->pb, -1); + if (c & 0x10) { + dts = get_pts(s->pb, -1); len -= 5; } } else if ((c & 0xc0) == 0x80) { /* mpeg 2 PES */ - flags = avio_r8(s->pb); + flags = avio_r8(s->pb); header_len = avio_r8(s->pb); - len -= 2; + len -= 2; if (header_len > len) goto error_redo; len -= header_len; if (flags & 0x80) { - dts = pts = get_pts(s->pb, -1); + dts = pts = get_pts(s->pb, -1); header_len -= 5; if (flags & 0x40) { - dts = get_pts(s->pb, -1); + dts = get_pts(s->pb, -1); header_len -= 5; } } - if (flags & 0x3f && header_len == 0){ + if (flags & 0x3f && header_len == 0) { flags &= 0xC0; av_log(s, AV_LOG_WARNING, "Further flags set but no bytes left\n"); } if (flags & 0x01) { /* PES extension */ pes_ext = avio_r8(s->pb); header_len--; - /* Skip PES private data, program packet sequence counter and P-STD buffer */ - skip = (pes_ext >> 4) & 0xb; + /* Skip PES private data, program packet sequence counter + * and P-STD buffer */ + skip = (pes_ext >> 4) & 0xb; skip += skip & 0x9; - if (pes_ext & 0x40 || skip > header_len){ + if (pes_ext & 0x40 || skip > header_len) { av_log(s, AV_LOG_WARNING, "pes_ext %X is invalid\n", pes_ext); - pes_ext=skip=0; + pes_ext = skip = 0; } avio_skip(s->pb, skip); header_len -= skip; @@ -412,11 +427,10 @@ static int mpegps_read_pes_header(AVFormatContext *s, } } } - if(header_len < 0) + if (header_len < 0) goto error_redo; avio_skip(s->pb, header_len); - } - else if( c!= 0xf ) + } else if (c != 0xf) goto redo; } @@ -424,22 +438,23 @@ static int mpegps_read_pes_header(AVFormatContext *s, startcode = avio_r8(s->pb); len--; } - if(len<0) + if (len < 0) goto error_redo; - if(dts != AV_NOPTS_VALUE && ppos){ + if (dts != AV_NOPTS_VALUE && ppos) { int i; - for(i=0; i<s->nb_streams; i++){ - if(startcode == s->streams[i]->id && - s->pb->seekable /* index useless on streams anyway */) { + for (i = 0; i < s->nb_streams; i++) { + if (startcode == s->streams[i]->id && + s->pb->seekable /* index useless on streams anyway */) { ff_reduce_index(s, i); - av_add_index_entry(s->streams[i], *ppos, dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */); + av_add_index_entry(s->streams[i], *ppos, dts, 0, 0, + AVINDEX_KEYFRAME /* FIXME keyframe? */); } } } *pstart_code = startcode; - *ppts = pts; - *pdts = dts; + *ppts = pts; + *pdts = dts; return len; } @@ -453,15 +468,15 @@ static int mpegps_read_packet(AVFormatContext *s, int request_probe= 0; enum AVCodecID codec_id = AV_CODEC_ID_NONE; enum AVMediaType type; - int64_t pts, dts, dummy_pos; //dummy_pos is needed for the index building to work + int64_t pts, dts, dummy_pos; // dummy_pos is needed for the index building to work - redo: +redo: len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts); if (len < 0) return len; if (startcode >= 0x80 && startcode <= 0xcf) { - if(len < 4) + if (len < 4) goto skip; /* audio: skip header */ @@ -476,44 +491,45 @@ static int mpegps_read_packet(AVFormatContext *s, } /* now find stream */ - for(i=0;i<s->nb_streams;i++) { + for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->id == startcode) goto found; } es_type = m->psm_es_type[startcode & 0xff]; - if(es_type == STREAM_TYPE_VIDEO_MPEG1){ + if (es_type == STREAM_TYPE_VIDEO_MPEG1) { codec_id = AV_CODEC_ID_MPEG2VIDEO; - type = AVMEDIA_TYPE_VIDEO; - } else if(es_type == STREAM_TYPE_VIDEO_MPEG2){ + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_VIDEO_MPEG2) { codec_id = AV_CODEC_ID_MPEG2VIDEO; - type = AVMEDIA_TYPE_VIDEO; - } else if(es_type == STREAM_TYPE_AUDIO_MPEG1 || - es_type == STREAM_TYPE_AUDIO_MPEG2){ + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_AUDIO_MPEG1 || + es_type == STREAM_TYPE_AUDIO_MPEG2) { codec_id = AV_CODEC_ID_MP3; - type = AVMEDIA_TYPE_AUDIO; - } else if(es_type == STREAM_TYPE_AUDIO_AAC){ + type = AVMEDIA_TYPE_AUDIO; + } else if (es_type == STREAM_TYPE_AUDIO_AAC) { codec_id = AV_CODEC_ID_AAC; - type = AVMEDIA_TYPE_AUDIO; - } else if(es_type == STREAM_TYPE_VIDEO_MPEG4){ + type = AVMEDIA_TYPE_AUDIO; + } else if (es_type == STREAM_TYPE_VIDEO_MPEG4) { codec_id = AV_CODEC_ID_MPEG4; - type = AVMEDIA_TYPE_VIDEO; - } else if(es_type == STREAM_TYPE_VIDEO_H264){ + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_VIDEO_H264) { codec_id = AV_CODEC_ID_H264; - type = AVMEDIA_TYPE_VIDEO; - } else if(es_type == STREAM_TYPE_AUDIO_AC3){ + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_AUDIO_AC3) { codec_id = AV_CODEC_ID_AC3; - type = AVMEDIA_TYPE_AUDIO; - } else if(m->imkh_cctv && es_type == 0x91){ + type = AVMEDIA_TYPE_AUDIO; + } else if (m->imkh_cctv && es_type == 0x91) { codec_id = AV_CODEC_ID_PCM_MULAW; - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; } else if (startcode >= 0x1e0 && startcode <= 0x1ef) { static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; unsigned char buf[8]; + avio_read(s->pb, buf, 8); avio_seek(s->pb, -8, SEEK_CUR); - if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) + if (!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) codec_id = AV_CODEC_ID_CAVS; else request_probe= 1; @@ -522,7 +538,7 @@ static int mpegps_read_packet(AVFormatContext *s, type = AVMEDIA_TYPE_DATA; codec_id = AV_CODEC_ID_DVD_NAV; } else if (startcode >= 0x1c0 && startcode <= 0x1df) { - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; if (m->sofdec > 0) { codec_id = AV_CODEC_ID_ADPCM_ADX; // Auto-detect AC-3 @@ -531,35 +547,35 @@ static int mpegps_read_packet(AVFormatContext *s, codec_id = AV_CODEC_ID_MP2; } } else if (startcode >= 0x80 && startcode <= 0x87) { - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; codec_id = AV_CODEC_ID_AC3; - } else if ( ( startcode >= 0x88 && startcode <= 0x8f) - ||( startcode >= 0x98 && startcode <= 0x9f)) { + } else if ((startcode >= 0x88 && startcode <= 0x8f) || + (startcode >= 0x98 && startcode <= 0x9f)) { /* 0x90 - 0x97 is reserved for SDDS in DVD specs */ - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; codec_id = AV_CODEC_ID_DTS; } else if (startcode >= 0xa0 && startcode <= 0xaf) { - type = AVMEDIA_TYPE_AUDIO; - if(lpcm_header_len == 6) { + type = AVMEDIA_TYPE_AUDIO; + if (lpcm_header_len == 6) { codec_id = AV_CODEC_ID_MLP; } else { codec_id = AV_CODEC_ID_PCM_DVD; } } else if (startcode >= 0xb0 && startcode <= 0xbf) { - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; codec_id = AV_CODEC_ID_TRUEHD; } else if (startcode >= 0xc0 && startcode <= 0xcf) { /* Used for both AC-3 and E-AC-3 in EVOB files */ - type = AVMEDIA_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; codec_id = AV_CODEC_ID_AC3; } else if (startcode >= 0x20 && startcode <= 0x3f) { - type = AVMEDIA_TYPE_SUBTITLE; + type = AVMEDIA_TYPE_SUBTITLE; codec_id = AV_CODEC_ID_DVD_SUBTITLE; } else if (startcode >= 0xfd55 && startcode <= 0xfd5f) { - type = AVMEDIA_TYPE_VIDEO; + type = AVMEDIA_TYPE_VIDEO; codec_id = AV_CODEC_ID_VC1; } else { - skip: +skip: /* skip packet */ avio_skip(s->pb, len); goto redo; @@ -568,18 +584,19 @@ static int mpegps_read_packet(AVFormatContext *s, st = avformat_new_stream(s, NULL); if (!st) goto skip; - st->id = startcode; + st->id = startcode; st->codec->codec_type = type; - st->codec->codec_id = codec_id; + st->codec->codec_id = codec_id; if (st->codec->codec_id == AV_CODEC_ID_PCM_MULAW) { st->codec->channels = 1; st->codec->channel_layout = AV_CH_LAYOUT_MONO; st->codec->sample_rate = 8000; } st->request_probe = request_probe; - st->need_parsing = AVSTREAM_PARSE_FULL; - found: - if(st->discard >= AVDISCARD_ALL) + st->need_parsing = AVSTREAM_PARSE_FULL; + +found: + if (st->discard >= AVDISCARD_ALL) goto skip; if (startcode >= 0xa0 && startcode <= 0xaf) { if (lpcm_header_len == 6 && st->codec->codec_id == AV_CODEC_ID_MLP) { @@ -590,9 +607,10 @@ static int mpegps_read_packet(AVFormatContext *s, } } ret = av_get_packet(s->pb, pkt, len); - pkt->pts = pts; - pkt->dts = dts; - pkt->pos = dummy_pos; + + pkt->pts = pts; + pkt->dts = dts; + pkt->pos = dummy_pos; pkt->stream_index = st->index; av_dlog(s, "%d: pts=%0.3f dts=%0.3f size=%d\n", pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0, @@ -611,7 +629,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, if (avio_seek(s->pb, pos, SEEK_SET) < 0) return AV_NOPTS_VALUE; - for(;;) { + for (;;) { len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts); if (len < 0) { av_dlog(s, "none (ret=%d)\n", len); @@ -739,7 +757,7 @@ static int vobsub_read_header(AVFormatContext *s) break; } timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay; - timestamp = av_rescale_q(timestamp, (AVRational){1,1000}, st->time_base); + timestamp = av_rescale_q(timestamp, av_make_q(1, 1000), st->time_base); sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0); if (!sub) { @@ -810,8 +828,6 @@ end: return ret; } -#define FAIL(r) do { ret = r; goto fail; } while (0) - static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) { MpegDemuxContext *vobsub = s->priv_data; @@ -860,7 +876,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) if (ret < 0) { if (pkt->size) // raise packet even if incomplete break; - FAIL(ret); + goto fail; } to_read = ret & 0xffff; new_pos = avio_tell(pb); @@ -877,7 +893,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) ret = av_grow_packet(pkt, to_read); if (ret < 0) - FAIL(ret); + goto fail; n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read); if (n < to_read) diff --git a/chromium/third_party/ffmpeg/libavformat/mpeg.h b/chromium/third_party/ffmpeg/libavformat/mpeg.h index cf10d6a4c40..55f9e0cb51b 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpeg.h +++ b/chromium/third_party/ffmpeg/libavformat/mpeg.h @@ -57,7 +57,6 @@ #define STREAM_TYPE_VIDEO_CAVS 0x42 #define STREAM_TYPE_AUDIO_AC3 0x81 -#define STREAM_TYPE_AUDIO_DTS 0x8a static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 }; diff --git a/chromium/third_party/ffmpeg/libavformat/mpegenc.c b/chromium/third_party/ffmpeg/libavformat/mpegenc.c index ccf3ec21f7a..5521f48cee4 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegenc.c @@ -387,7 +387,9 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) if (st->codec->rc_buffer_size) stream->max_buffer_size = 6*1024 + st->codec->rc_buffer_size/8; else { - av_log(ctx, AV_LOG_WARNING, "VBV buffer size not set, muxing may fail\n"); + av_log(ctx, AV_LOG_WARNING, "VBV buffer size not set, using default size of 130KB\n" + "If you want the mpeg file to be compliant to some specification\n" + "Like DVD, VCD or others, make sure you set the correct buffer size\n"); stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default } if (stream->max_buffer_size > 1024 * 8191) { @@ -1157,7 +1159,7 @@ static int mpeg_mux_end(AVFormatContext *ctx) stream = ctx->streams[i]->priv_data; assert(av_fifo_size(stream->fifo) == 0); - av_fifo_free(stream->fifo); + av_fifo_freep(&stream->fifo); } return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/mpegts.c b/chromium/third_party/ffmpeg/libavformat/mpegts.c index d67c63a4de2..0a5ac689614 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegts.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegts.c @@ -29,7 +29,6 @@ #include "libavutil/avassert.h" #include "libavcodec/bytestream.h" #include "libavcodec/get_bits.h" -#include "libavcodec/mathops.h" #include "avformat.h" #include "mpegts.h" #include "internal.h" @@ -39,37 +38,46 @@ #include "isom.h" /* maximum size in which we look for synchronisation if - synchronisation is lost */ + * synchronisation is lost */ #define MAX_RESYNC_SIZE 65536 -#define MAX_PES_PAYLOAD 200*1024 +#define MAX_PES_PAYLOAD 200 * 1024 #define MAX_MP4_DESCR_COUNT 16 +#define MOD_UNLIKELY(modulus, dividend, divisor, prev_dividend) \ + do { \ + if ((prev_dividend) == 0 || (dividend) - (prev_dividend) != (divisor)) \ + (modulus) = (dividend) % (divisor); \ + (prev_dividend) = (dividend); \ + } while (0) + enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, + MPEGTS_PCR, }; typedef struct MpegTSFilter MpegTSFilter; -typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos, int64_t cur_pcr); +typedef int PESCallback (MpegTSFilter *f, const uint8_t *buf, int len, + int is_start, int64_t pos); typedef struct MpegTSPESFilter { PESCallback *pes_cb; void *opaque; } MpegTSPESFilter; -typedef void SectionCallback(MpegTSFilter *f, const uint8_t *buf, int len); +typedef void SectionCallback (MpegTSFilter *f, const uint8_t *buf, int len); -typedef void SetServiceCallback(void *opaque, int ret); +typedef void SetServiceCallback (void *opaque, int ret); typedef struct MpegTSSectionFilter { int section_index; int section_h_size; uint8_t *section_buf; - unsigned int check_crc:1; - unsigned int end_of_section_reached:1; + unsigned int check_crc : 1; + unsigned int end_of_section_reached : 1; SectionCallback *section_cb; void *opaque; } MpegTSSectionFilter; @@ -78,6 +86,7 @@ struct MpegTSFilter { int pid; int es_id; int last_cc; /* last cc code (-1 if first packet) */ + int64_t last_pcr; enum MpegTSFilterType type; union { MpegTSPESFilter pes_filter; @@ -87,16 +96,19 @@ struct MpegTSFilter { #define MAX_PIDS_PER_PROGRAM 64 struct Program { - unsigned int id; //program id/service id + unsigned int id; // program id/service id unsigned int nb_pids; unsigned int pids[MAX_PIDS_PER_PROGRAM]; + + /** have we found pmt for this program */ + int pmt_found; }; struct MpegTSContext { const AVClass *class; /* user data */ AVFormatContext *stream; - /** raw packet size, including FEC if present */ + /** raw packet size, including FEC if present */ int raw_packet_size; int size_stat[3]; @@ -105,43 +117,47 @@ struct MpegTSContext { int64_t pos47_full; - /** if true, all pids are analyzed to find streams */ + /** if true, all pids are analyzed to find streams */ int auto_guess; - /** compute exact PCR for each transport stream packet */ + /** compute exact PCR for each transport stream packet */ int mpeg2ts_compute_pcr; /** fix dvb teletext pts */ int fix_teletext_pts; - int64_t cur_pcr; /**< used to estimate the exact PCR */ - int pcr_incr; /**< used to estimate the exact PCR */ + int64_t cur_pcr; /**< used to estimate the exact PCR */ + int pcr_incr; /**< used to estimate the exact PCR */ /* data needed to handle file based ts */ - /** stop parsing loop */ + /** stop parsing loop */ int stop_parse; - /** packet containing Audio/Video data */ + /** packet containing Audio/Video data */ AVPacket *pkt; - /** to detect seek */ + /** to detect seek */ int64_t last_pos; /******************************************/ /* private mpegts data */ /* scan context */ - /** structure to keep track of Program->pids mapping */ + /** structure to keep track of Program->pids mapping */ unsigned int nb_prg; struct Program *prg; int8_t crc_validity[NB_PID_MAX]; - /** filters for various streams specified by PMT + for the PAT and PMT */ MpegTSFilter *pids[NB_PID_MAX]; int current_pid; }; static const AVOption mpegtsraw_options[] = { - {"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT, - {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "compute_pcr", "Compute exact PCR for each transport stream packet.", + offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "ts_packetsize", "Output option carrying the raw packet size.", + offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 0, + AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, { NULL }, }; @@ -155,6 +171,8 @@ static const AVClass mpegtsraw_class = { static const AVOption mpegts_options[] = { {"fix_teletext_pts", "Try to fix pts values of dvb teletext streams.", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, + {.i64 = 0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, { NULL }, }; @@ -200,17 +218,27 @@ typedef struct PESContext { uint8_t header[MAX_PES_HEADER_SIZE]; AVBufferRef *buffer; SLConfigDescr sl; - int64_t last_pcr; } PESContext; extern AVInputFormat ff_mpegts_demuxer; +static struct Program * get_program(MpegTSContext *ts, unsigned int programid) +{ + int i; + for (i = 0; i < ts->nb_prg; i++) { + if (ts->prg[i].id == programid) { + return &ts->prg[i]; + } + } + return NULL; +} + static void clear_avprogram(MpegTSContext *ts, unsigned int programid) { AVProgram *prg = NULL; int i; - for(i=0; i<ts->stream->nb_programs; i++) - if(ts->stream->programs[i]->id == programid){ + for (i = 0; i < ts->stream->nb_programs; i++) + if (ts->stream->programs[i]->id == programid) { prg = ts->stream->programs[i]; break; } @@ -224,15 +252,17 @@ static void clear_program(MpegTSContext *ts, unsigned int programid) int i; clear_avprogram(ts, programid); - for(i=0; i<ts->nb_prg; i++) - if(ts->prg[i].id == programid) + for (i = 0; i < ts->nb_prg; i++) + if (ts->prg[i].id == programid) { ts->prg[i].nb_pids = 0; + ts->prg[i].pmt_found = 0; + } } static void clear_programs(MpegTSContext *ts) { av_freep(&ts->prg); - ts->nb_prg=0; + ts->nb_prg = 0; } static void add_pat_entry(MpegTSContext *ts, unsigned int programid) @@ -245,32 +275,36 @@ static void add_pat_entry(MpegTSContext *ts, unsigned int programid) p = &ts->prg[ts->nb_prg]; p->id = programid; p->nb_pids = 0; + p->pmt_found = 0; ts->nb_prg++; } -static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid) +static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, + unsigned int pid) { - int i; - struct Program *p = NULL; - for(i=0; i<ts->nb_prg; i++) { - if(ts->prg[i].id == programid) { - p = &ts->prg[i]; - break; - } - } - if(!p) + struct Program *p = get_program(ts, programid); + if (!p) return; - if(p->nb_pids >= MAX_PIDS_PER_PROGRAM) + if (p->nb_pids >= MAX_PIDS_PER_PROGRAM) return; p->pids[p->nb_pids++] = pid; } +static void set_pmt_found(MpegTSContext *ts, unsigned int programid) +{ + struct Program *p = get_program(ts, programid); + if (!p) + return; + + p->pmt_found = 1; +} + static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid) { int i; - for(i=0; i<s->nb_programs; i++) { - if(s->programs[i]->id == programid) { + for (i = 0; i < s->nb_programs; i++) { + if (s->programs[i]->id == programid) { s->programs[i]->pcr_pid = pid; break; } @@ -292,24 +326,22 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid) struct Program *p; /* If none of the programs have .discard=AVDISCARD_ALL then there's - * no way we have to discard this packet - */ - for (k = 0; k < ts->stream->nb_programs; k++) { + * no way we have to discard this packet */ + for (k = 0; k < ts->stream->nb_programs; k++) if (ts->stream->programs[k]->discard == AVDISCARD_ALL) break; - } if (k == ts->stream->nb_programs) return 0; - for(i=0; i<ts->nb_prg; i++) { + for (i = 0; i < ts->nb_prg; i++) { p = &ts->prg[i]; - for(j=0; j<p->nb_pids; j++) { - if(p->pids[j] != pid) + for (j = 0; j < p->nb_pids; j++) { + if (p->pids[j] != pid) continue; - //is program with id p->id set to be discarded? - for(k=0; k<ts->stream->nb_programs; k++) { - if(ts->stream->programs[k]->id == p->id) { - if(ts->stream->programs[k]->discard == AVDISCARD_ALL) + // is program with id p->id set to be discarded? + for (k = 0; k < ts->stream->nb_programs; k++) { + if (ts->stream->programs[k]->id == p->id) { + if (ts->stream->programs[k]->discard == AVDISCARD_ALL) discarded++; else used++; @@ -355,15 +387,16 @@ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, tss->section_h_size = len; } - if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) { + if (tss->section_h_size != -1 && + tss->section_index >= tss->section_h_size) { int crc_valid = 1; tss->end_of_section_reached = 1; - if (tss->check_crc){ + if (tss->check_crc) { crc_valid = !av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, tss->section_buf, tss->section_h_size); - if (crc_valid){ + if (crc_valid) { ts->crc_validity[ tss1->pid ] = 100; - }else if(ts->crc_validity[ tss1->pid ] > -10){ + }else if (ts->crc_validity[ tss1->pid ] > -10) { ts->crc_validity[ tss1->pid ]--; }else crc_valid = 2; @@ -373,13 +406,10 @@ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, } } -static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid, - SectionCallback *section_cb, void *opaque, - int check_crc) - +static MpegTSFilter *mpegts_open_filter(MpegTSContext *ts, unsigned int pid, + enum MpegTSFilterType type) { MpegTSFilter *filter; - MpegTSSectionFilter *sec; av_dlog(ts->stream, "Filter: pid=0x%x\n", pid); @@ -389,15 +419,32 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int if (!filter) return NULL; ts->pids[pid] = filter; - filter->type = MPEGTS_SECTION; - filter->pid = pid; - filter->es_id = -1; + + filter->type = type; + filter->pid = pid; + filter->es_id = -1; filter->last_cc = -1; + filter->last_pcr= -1; + + return filter; +} + +static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, + unsigned int pid, + SectionCallback *section_cb, + void *opaque, + int check_crc) +{ + MpegTSFilter *filter; + MpegTSSectionFilter *sec; + + if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) + return NULL; sec = &filter->u.section_filter; - sec->section_cb = section_cb; - sec->opaque = opaque; + sec->section_cb = section_cb; + sec->opaque = opaque; sec->section_buf = av_malloc(MAX_SECTION_SIZE); - sec->check_crc = check_crc; + sec->check_crc = check_crc; if (!sec->section_buf) { av_free(filter); return NULL; @@ -406,28 +453,26 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int } static MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid, - PESCallback *pes_cb, - void *opaque) + PESCallback *pes_cb, + void *opaque) { MpegTSFilter *filter; MpegTSPESFilter *pes; - if (pid >= NB_PID_MAX || ts->pids[pid]) + if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_PES))) return NULL; - filter = av_mallocz(sizeof(MpegTSFilter)); - if (!filter) - return NULL; - ts->pids[pid] = filter; - filter->type = MPEGTS_PES; - filter->pid = pid; - filter->es_id = -1; - filter->last_cc = -1; + pes = &filter->u.pes_filter; pes->pes_cb = pes_cb; pes->opaque = opaque; return filter; } +static MpegTSFilter *mpegts_open_pcr_filter(MpegTSContext *ts, unsigned int pid) +{ + return mpegts_open_filter(ts, pid, MPEGTS_PCR); +} + static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) { int pid; @@ -449,20 +494,22 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) ts->pids[pid] = NULL; } -static int analyze(const uint8_t *buf, int size, int packet_size, int *index){ +static int analyze(const uint8_t *buf, int size, int packet_size, int *index) +{ int stat[TS_MAX_PACKET_SIZE]; int i; - int best_score=0; + int best_score = 0; - memset(stat, 0, packet_size*sizeof(*stat)); + memset(stat, 0, packet_size * sizeof(*stat)); - for(i=0; i<size-3; i++){ - if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){ + for (i = 0; i < size - 3; i++) { + if (buf[i] == 0x47 && !(buf[i + 1] & 0x80) && buf[i + 3] != 0x47) { int x = i % packet_size; stat[x]++; - if(stat[x] > best_score){ - best_score= stat[x]; - if(index) *index= x; + if (stat[x] > best_score) { + best_score = stat[x]; + if (index) + *index = x; } } } @@ -476,18 +523,22 @@ static int get_packet_size(const uint8_t *buf, int size) int score, fec_score, dvhs_score; if (size < (TS_FEC_PACKET_SIZE * 5 + 1)) - return -1; + return AVERROR_INVALIDDATA; - score = analyze(buf, size, TS_PACKET_SIZE, NULL); - dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, NULL); - fec_score= analyze(buf, size, TS_FEC_PACKET_SIZE, NULL); + score = analyze(buf, size, TS_PACKET_SIZE, NULL); + dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, NULL); + fec_score = analyze(buf, size, TS_FEC_PACKET_SIZE, NULL); av_dlog(NULL, "score: %d, dvhs_score: %d, fec_score: %d \n", score, dvhs_score, fec_score); - if (score > fec_score && score > dvhs_score) return TS_PACKET_SIZE; - else if(dvhs_score > score && dvhs_score > fec_score) return TS_DVHS_PACKET_SIZE; - else if(score < fec_score && dvhs_score < fec_score) return TS_FEC_PACKET_SIZE; - else return -1; + if (score > fec_score && score > dvhs_score) + return TS_PACKET_SIZE; + else if (dvhs_score > score && dvhs_score > fec_score) + return TS_DVHS_PACKET_SIZE; + else if (score < fec_score && dvhs_score < fec_score) + return TS_FEC_PACKET_SIZE; + else + return AVERROR_INVALIDDATA; } typedef struct SectionHeader { @@ -505,8 +556,8 @@ static inline int get8(const uint8_t **pp, const uint8_t *p_end) p = *pp; if (p >= p_end) - return -1; - c = *p++; + return AVERROR_INVALIDDATA; + c = *p++; *pp = p; return c; } @@ -518,9 +569,9 @@ static inline int get16(const uint8_t **pp, const uint8_t *p_end) p = *pp; if ((p + 1) >= p_end) - return -1; - c = AV_RB16(p); - p += 2; + return AVERROR_INVALIDDATA; + c = AV_RB16(p); + p += 2; *pp = p; return c; } @@ -532,7 +583,7 @@ static char *getstr8(const uint8_t **pp, const uint8_t *p_end) const uint8_t *p; char *str; - p = *pp; + p = *pp; len = get8(&p, p_end); if (len < 0) return NULL; @@ -543,7 +594,7 @@ static char *getstr8(const uint8_t **pp, const uint8_t *p_end) return NULL; memcpy(str, p, len); str[len] = '\0'; - p += len; + p += len; *pp = p; return str; } @@ -555,24 +606,24 @@ static int parse_section_header(SectionHeader *h, val = get8(pp, p_end); if (val < 0) - return -1; + return val; h->tid = val; *pp += 2; - val = get16(pp, p_end); + val = get16(pp, p_end); if (val < 0) - return -1; + return val; h->id = val; val = get8(pp, p_end); if (val < 0) - return -1; + return val; h->version = (val >> 1) & 0x1f; val = get8(pp, p_end); if (val < 0) - return -1; + return val; h->sec_num = val; val = get8(pp, p_end); if (val < 0) - return -1; + return val; h->last_sec_num = val; return 0; } @@ -586,94 +637,95 @@ typedef struct { static const StreamType ISO_types[] = { { 0x01, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, { 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, - { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, - { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, - { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, - { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, + { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, + { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, + { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, + { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, /* Makito encoder sets stream type 0x11 for AAC, * so auto-detect LOAS/LATM instead of hardcoding it. */ #if !CONFIG_LOAS_DEMUXER - { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */ + { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */ #endif - { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, - { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, - { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, - { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, - { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, + { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, + { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, + { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, + { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, + { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, { 0 }, }; static const StreamType HDMV_types[] = { - { 0x80, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_BLURAY }, - { 0x81, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, - { 0x82, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, - { 0x83, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_TRUEHD }, - { 0x84, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, - { 0x85, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD */ - { 0x86, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD MASTER*/ - { 0xa1, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */ - { 0xa2, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS Express Secondary Audio */ + { 0x80, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_BLURAY }, + { 0x81, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, + { 0x82, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { 0x83, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_TRUEHD }, + { 0x84, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, + { 0x85, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD */ + { 0x86, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD MASTER*/ + { 0xa1, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */ + { 0xa2, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS Express Secondary Audio */ { 0x90, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_HDMV_PGS_SUBTITLE }, { 0 }, }; /* ATSC ? */ static const StreamType MISC_types[] = { - { 0x81, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, - { 0x8a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { 0x81, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, + { 0x8a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, { 0 }, }; static const StreamType REGD_types[] = { - { MKTAG('d','r','a','c'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, - { MKTAG('A','C','-','3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, - { MKTAG('B','S','S','D'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_S302M }, - { MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, - { MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, - { MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, - { MKTAG('H','E','V','C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, - { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV }, - { MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, + { MKTAG('d', 'r', 'a', 'c'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, + { MKTAG('A', 'C', '-', '3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, + { MKTAG('B', 'S', 'S', 'D'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_S302M }, + { MKTAG('D', 'T', 'S', '1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { MKTAG('D', 'T', 'S', '2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { MKTAG('D', 'T', 'S', '3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { MKTAG('H', 'E', 'V', 'C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, + { MKTAG('K', 'L', 'V', 'A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV }, + { MKTAG('V', 'C', '-', '1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, { 0 }, }; static const StreamType METADATA_types[] = { { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV }, + { MKTAG('I','D','3',' '), AVMEDIA_TYPE_DATA, AV_CODEC_ID_TIMED_ID3 }, { 0 }, }; /* descriptor present */ static const StreamType DESC_types[] = { - { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */ - { 0x7a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC-3 descriptor */ - { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */ + { 0x7a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC-3 descriptor */ + { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, { 0x56, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_TELETEXT }, { 0x59, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */ { 0 }, }; static void mpegts_find_stream_type(AVStream *st, - uint32_t stream_type, const StreamType *types) + uint32_t stream_type, + const StreamType *types) { if (avcodec_is_open(st->codec)) { av_log(NULL, AV_LOG_DEBUG, "cannot set stream info, codec is open\n"); return; } - for (; types->stream_type; types++) { + for (; types->stream_type; types++) if (stream_type == types->stream_type) { st->codec->codec_type = types->codec_type; st->codec->codec_id = types->codec_id; st->request_probe = 0; return; } - } } static int mpegts_set_stream_info(AVStream *st, PESContext *pes, uint32_t stream_type, uint32_t prog_reg_desc) { - int old_codec_type= st->codec->codec_type; + int old_codec_type = st->codec->codec_type; int old_codec_id = st->codec->codec_id; if (avcodec_is_open(st->codec)) { @@ -682,16 +734,16 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes, } avpriv_set_pts_info(st, 33, 1, 90000); - st->priv_data = pes; + st->priv_data = pes; st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = AV_CODEC_ID_NONE; - st->need_parsing = AVSTREAM_PARSE_FULL; - pes->st = st; + st->need_parsing = AVSTREAM_PARSE_FULL; + pes->st = st; pes->stream_type = stream_type; av_log(pes->stream, AV_LOG_DEBUG, "stream=%d stream_type=%x pid=%x prog_reg_desc=%.4s\n", - st->index, pes->stream_type, pes->pid, (char*)&prog_reg_desc); + st->index, pes->stream_type, pes->pid, (char *)&prog_reg_desc); st->codec->codec_tag = pes->stream_type; @@ -718,23 +770,32 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes, sub_st->id = pes->pid; avpriv_set_pts_info(sub_st, 33, 1, 90000); - sub_st->priv_data = sub_pes; + sub_st->priv_data = sub_pes; sub_st->codec->codec_type = AVMEDIA_TYPE_AUDIO; sub_st->codec->codec_id = AV_CODEC_ID_AC3; - sub_st->need_parsing = AVSTREAM_PARSE_FULL; - sub_pes->sub_st = pes->sub_st = sub_st; + sub_st->need_parsing = AVSTREAM_PARSE_FULL; + sub_pes->sub_st = pes->sub_st = sub_st; } } if (st->codec->codec_id == AV_CODEC_ID_NONE) mpegts_find_stream_type(st, pes->stream_type, MISC_types); - if (st->codec->codec_id == AV_CODEC_ID_NONE){ + if (st->codec->codec_id == AV_CODEC_ID_NONE) { st->codec->codec_id = old_codec_id; - st->codec->codec_type= old_codec_type; + st->codec->codec_type = old_codec_type; } return 0; } +static void reset_pes_packet_state(PESContext *pes) +{ + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + pes->data_index = 0; + pes->flags = 0; + av_buffer_unref(&pes->buffer); +} + static void new_pes_packet(PESContext *pes, AVPacket *pkt) { av_init_packet(pkt); @@ -743,12 +804,13 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt) pkt->data = pes->buffer->data; pkt->size = pes->data_index; - if(pes->total_size != MAX_PES_PAYLOAD && - pes->pes_header_size + pes->data_index != pes->total_size + PES_START_SIZE) { + if (pes->total_size != MAX_PES_PAYLOAD && + pes->pes_header_size + pes->data_index != pes->total_size + + PES_START_SIZE) { av_log(pes->stream, AV_LOG_WARNING, "PES packet size mismatch\n"); pes->flags |= AV_PKT_FLAG_CORRUPT; } - memset(pkt->data+pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); // Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID if (pes->sub_st && pes->stream_type == 0x83 && pes->extended_stream_id == 0x76) @@ -758,15 +820,11 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt) pkt->pts = pes->pts; pkt->dts = pes->dts; /* store position of first TS packet of this PES packet */ - pkt->pos = pes->ts_packet_pos; + pkt->pos = pes->ts_packet_pos; pkt->flags = pes->flags; - /* reset pts values */ - pes->pts = AV_NOPTS_VALUE; - pes->dts = AV_NOPTS_VALUE; pes->buffer = NULL; - pes->data_index = 0; - pes->flags = 0; + reset_pes_packet_state(pes); } static uint64_t get_ts64(GetBitContext *gb, int bits) @@ -776,7 +834,8 @@ static uint64_t get_ts64(GetBitContext *gb, int bits) return get_bits64(gb, bits); } -static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf, int buf_size) +static int read_sl_header(PESContext *pes, SLConfigDescr *sl, + const uint8_t *buf, int buf_size) { GetBitContext gb; int au_start_flag = 0, au_end_flag = 0, ocr_flag = 0, idle_flag = 0; @@ -784,7 +843,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf int dts_flag = -1, cts_flag = -1; int64_t dts = AV_NOPTS_VALUE, cts = AV_NOPTS_VALUE; - init_get_bits(&gb, buf, buf_size*8); + init_get_bits(&gb, buf, buf_size * 8); if (sl->use_au_start) au_start_flag = get_bits1(&gb); @@ -845,31 +904,29 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf /* return non zero if a packet could be constructed */ static int mpegts_push_data(MpegTSFilter *filter, const uint8_t *buf, int buf_size, int is_start, - int64_t pos, int64_t pcr) + int64_t pos) { - PESContext *pes = filter->u.pes_filter.opaque; + PESContext *pes = filter->u.pes_filter.opaque; MpegTSContext *ts = pes->ts; const uint8_t *p; int len, code; - if(!ts->pkt) + if (!ts->pkt) return 0; - if (pcr != -1) - pes->last_pcr = pcr; - if (is_start) { if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { new_pes_packet(pes, ts->pkt); ts->stop_parse = 1; + } else { + reset_pes_packet_state(pes); } - pes->state = MPEGTS_HEADER; - pes->data_index = 0; + pes->state = MPEGTS_HEADER; pes->ts_packet_pos = pos; } p = buf; while (buf_size > 0) { - switch(pes->state) { + switch (pes->state) { case MPEGTS_HEADER: len = PES_START_SIZE - pes->data_index; if (len > buf_size) @@ -880,15 +937,17 @@ static int mpegts_push_data(MpegTSFilter *filter, buf_size -= len; if (pes->data_index == PES_START_SIZE) { /* we got all the PES or section header. We can now - decide */ + * decide */ if (pes->header[0] == 0x00 && pes->header[1] == 0x00 && pes->header[2] == 0x01) { /* it must be an mpeg2 PES stream */ code = pes->header[3] | 0x100; - av_dlog(pes->stream, "pid=%x pes_code=%#x\n", pes->pid, code); + av_dlog(pes->stream, "pid=%x pes_code=%#x\n", pes->pid, + code); if ((pes->st && pes->st->discard == AVDISCARD_ALL && - (!pes->sub_st || pes->sub_st->discard == AVDISCARD_ALL)) || + (!pes->sub_st || + pes->sub_st->discard == AVDISCARD_ALL)) || code == 0x1be) /* padding_stream */ goto skip; @@ -903,7 +962,7 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->total_size = AV_RB16(pes->header + 4); /* NOTE: a zero total size means the PES size is - unbounded */ + * unbounded */ if (!pes->total_size) pes->total_size = MAX_PES_PAYLOAD; @@ -919,29 +978,31 @@ static int mpegts_push_data(MpegTSFilter *filter, code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */ pes->state = MPEGTS_PESHEADER; if (pes->st->codec->codec_id == AV_CODEC_ID_NONE && !pes->st->request_probe) { - av_dlog(pes->stream, "pid=%x stream_type=%x probing\n", - pes->pid, pes->stream_type); - pes->st->request_probe= 1; + av_dlog(pes->stream, + "pid=%x stream_type=%x probing\n", + pes->pid, + pes->stream_type); + pes->st->request_probe = 1; } } else { - pes->state = MPEGTS_PAYLOAD; + pes->state = MPEGTS_PAYLOAD; pes->data_index = 0; } } else { /* otherwise, it should be a table */ /* skip packet */ - skip: +skip: pes->state = MPEGTS_SKIP; continue; } } break; - /**********************************************/ - /* PES packing parsing */ + /**********************************************/ + /* PES packing parsing */ case MPEGTS_PESHEADER: len = PES_HEADER_SIZE - pes->data_index; if (len < 0) - return -1; + return AVERROR_INVALIDDATA; if (len > buf_size) len = buf_size; memcpy(pes->header + pes->data_index, p, len); @@ -950,13 +1011,13 @@ static int mpegts_push_data(MpegTSFilter *filter, buf_size -= len; if (pes->data_index == PES_HEADER_SIZE) { pes->pes_header_size = pes->header[8] + 9; - pes->state = MPEGTS_PESHEADER_FILL; + pes->state = MPEGTS_PESHEADER_FILL; } break; case MPEGTS_PESHEADER_FILL: len = pes->pes_header_size - pes->data_index; if (len < 0) - return -1; + return AVERROR_INVALIDDATA; if (len > buf_size) len = buf_size; memcpy(pes->header + pes->data_index, p, len); @@ -972,10 +1033,7 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->pts = AV_NOPTS_VALUE; pes->dts = AV_NOPTS_VALUE; if ((flags & 0xc0) == 0x80) { - pes->pts = ff_parse_pes_pts(r); - /* video pts is not monotonic, can't be used for dts */ - if (pes->st->codec->codec_type != AVMEDIA_TYPE_VIDEO) - pes->dts = pes->pts; + pes->dts = pes->pts = ff_parse_pes_pts(r); r += 5; } else if ((flags & 0xc0) == 0xc0) { pes->pts = ff_parse_pes_pts(r); @@ -987,9 +1045,9 @@ static int mpegts_push_data(MpegTSFilter *filter, if (flags & 0x01) { /* PES extension */ pes_ext = *r++; /* Skip PES private data, program packet sequence counter and P-STD buffer */ - skip = (pes_ext >> 4) & 0xb; + skip = (pes_ext >> 4) & 0xb; skip += skip & 0x9; - r += skip; + r += skip; if ((pes_ext & 0x41) == 0x01 && (r + 2) <= (pes->header + pes->pes_header_size)) { /* PES extension 2 */ @@ -1002,7 +1060,8 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->state = MPEGTS_PAYLOAD; pes->data_index = 0; if (pes->stream_type == 0x12 && buf_size > 0) { - int sl_header_bytes = read_sl_header(pes, &pes->sl, p, buf_size); + int sl_header_bytes = read_sl_header(pes, &pes->sl, p, + buf_size); pes->pes_header_size += sl_header_bytes; p += sl_header_bytes; buf_size -= sl_header_bytes; @@ -1018,16 +1077,28 @@ static int mpegts_push_data(MpegTSFilter *filter, while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) { if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) { MpegTSFilter *f = pes->ts->pids[p->pcr_pid]; - if (f && f->type == MPEGTS_PES) { - PESContext *pcrpes = f->u.pes_filter.opaque; - if (pcrpes && pcrpes->last_pcr != -1 && pcrpes->st && pcrpes->st->discard != AVDISCARD_ALL) { + if (f) { + AVStream *st = NULL; + if (f->type == MPEGTS_PES) { + PESContext *pcrpes = f->u.pes_filter.opaque; + if (pcrpes) + st = pcrpes->st; + } else if (f->type == MPEGTS_PCR) { + int i; + for (i = 0; i < p->nb_stream_indexes; i++) { + AVStream *pst = pes->stream->streams[p->stream_index[i]]; + if (pst->codec->codec_type == AVMEDIA_TYPE_VIDEO) + st = pst; + } + } + if (f->last_pcr != -1 && st && st->discard != AVDISCARD_ALL) { // teletext packets do not always have correct timestamps, // the standard says they should be handled after 40.6 ms at most, // and the pcr error to this packet should be no more than 100 ms. // TODO: we should interpolate the PCR, not just use the last one - int64_t pcr = pcrpes->last_pcr / 300; - pes->st->pts_wrap_reference = pcrpes->st->pts_wrap_reference; - pes->st->pts_wrap_behavior = pcrpes->st->pts_wrap_behavior; + int64_t pcr = f->last_pcr / 300; + pes->st->pts_wrap_reference = st->pts_wrap_reference; + pes->st->pts_wrap_behavior = st->pts_wrap_behavior; if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { pes->pts = pes->dts = pcr; } else if (pes->dts > pcr + 3654 + 9000) { @@ -1042,33 +1113,36 @@ static int mpegts_push_data(MpegTSFilter *filter, } break; case MPEGTS_PAYLOAD: - if (buf_size > 0 && pes->buffer) { - if (pes->data_index > 0 && pes->data_index+buf_size > pes->total_size) { + if (pes->buffer) { + if (pes->data_index > 0 && + pes->data_index + buf_size > pes->total_size) { new_pes_packet(pes, ts->pkt); pes->total_size = MAX_PES_PAYLOAD; - pes->buffer = av_buffer_alloc(pes->total_size + FF_INPUT_BUFFER_PADDING_SIZE); + pes->buffer = av_buffer_alloc(pes->total_size + + FF_INPUT_BUFFER_PADDING_SIZE); if (!pes->buffer) return AVERROR(ENOMEM); ts->stop_parse = 1; - } else if (pes->data_index == 0 && buf_size > pes->total_size) { + } else if (pes->data_index == 0 && + buf_size > pes->total_size) { // pes packet size is < ts size packet and pes data is padded with 0xff // not sure if this is legal in ts but see issue #2392 buf_size = pes->total_size; } memcpy(pes->buffer->data + pes->data_index, p, buf_size); pes->data_index += buf_size; + /* emit complete packets with known packet size + * decreases demuxer delay for infrequent packets like subtitles from + * a couple of seconds to milliseconds for properly muxed files. + * total_size is the number of bytes following pes_packet_length + * in the pes header, i.e. not counting the first PES_START_SIZE bytes */ + if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD && + pes->pes_header_size + pes->data_index == pes->total_size + PES_START_SIZE) { + ts->stop_parse = 1; + new_pes_packet(pes, ts->pkt); + } } buf_size = 0; - /* emit complete packets with known packet size - * decreases demuxer delay for infrequent packets like subtitles from - * a couple of seconds to milliseconds for properly muxed files. - * total_size is the number of bytes following pes_packet_length - * in the pes header, i.e. not counting the first PES_START_SIZE bytes */ - if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD && - pes->pes_header_size + pes->data_index == pes->total_size + PES_START_SIZE) { - ts->stop_parse = 1; - new_pes_packet(pes, ts->pkt); - } break; case MPEGTS_SKIP: buf_size = 0; @@ -1088,15 +1162,14 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) pes = av_mallocz(sizeof(PESContext)); if (!pes) return 0; - pes->ts = ts; - pes->stream = ts->stream; - pes->pid = pid; + pes->ts = ts; + pes->stream = ts->stream; + pes->pid = pid; pes->pcr_pid = pcr_pid; - pes->state = MPEGTS_SKIP; - pes->pts = AV_NOPTS_VALUE; - pes->dts = AV_NOPTS_VALUE; - pes->last_pcr = -1; - tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); + pes->state = MPEGTS_SKIP; + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); if (!tss) { av_free(pes); return 0; @@ -1115,32 +1188,33 @@ typedef struct { int level; } MP4DescrParseContext; -static int init_MP4DescrParseContext( - MP4DescrParseContext *d, AVFormatContext *s, const uint8_t *buf, - unsigned size, Mp4Descr *descr, int max_descr_count) +static int init_MP4DescrParseContext(MP4DescrParseContext *d, AVFormatContext *s, + const uint8_t *buf, unsigned size, + Mp4Descr *descr, int max_descr_count) { int ret; - if (size > (1<<30)) + if (size > (1 << 30)) return AVERROR_INVALIDDATA; - if ((ret = ffio_init_context(&d->pb, (unsigned char*)buf, size, 0, - NULL, NULL, NULL, NULL)) < 0) + if ((ret = ffio_init_context(&d->pb, (unsigned char *)buf, size, 0, + NULL, NULL, NULL, NULL)) < 0) return ret; - d->s = s; - d->level = 0; - d->descr_count = 0; - d->descr = descr; - d->active_descr = NULL; + d->s = s; + d->level = 0; + d->descr_count = 0; + d->descr = descr; + d->active_descr = NULL; d->max_descr_count = max_descr_count; return 0; } -static void update_offsets(AVIOContext *pb, int64_t *off, int *len) { +static void update_offsets(AVIOContext *pb, int64_t *off, int *len) +{ int64_t new_off = avio_tell(pb); (*len) -= new_off - *off; - *off = new_off; + *off = new_off; } static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len, @@ -1149,8 +1223,9 @@ static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len, static int parse_mp4_descr_arr(MP4DescrParseContext *d, int64_t off, int len) { while (len > 0) { - if (parse_mp4_descr(d, off, len, 0) < 0) - return -1; + int ret = parse_mp4_descr(d, off, len, 0); + if (ret < 0) + return ret; update_offsets(&d->pb, &off, &len); } return 0; @@ -1174,9 +1249,9 @@ static int parse_MP4ODescrTag(MP4DescrParseContext *d, int64_t off, int len) if (len < 2) return 0; id_flags = avio_rb16(&d->pb); - if (!(id_flags & 0x0020)) { //URL_Flag + if (!(id_flags & 0x0020)) { // URL_Flag update_offsets(&d->pb, &off, &len); - return parse_mp4_descr_arr(d, off, len); //ES_Descriptor[] + return parse_mp4_descr_arr(d, off, len); // ES_Descriptor[] } else { return 0; } @@ -1186,7 +1261,7 @@ static int parse_MP4ESDescrTag(MP4DescrParseContext *d, int64_t off, int len) { int es_id = 0; if (d->descr_count >= d->max_descr_count) - return -1; + return AVERROR_INVALIDDATA; ff_mp4_parse_es_descr(&d->pb, &es_id); d->active_descr = d->descr + (d->descr_count++); @@ -1200,11 +1275,12 @@ static int parse_MP4ESDescrTag(MP4DescrParseContext *d, int64_t off, int len) return 0; } -static int parse_MP4DecConfigDescrTag(MP4DescrParseContext *d, int64_t off, int len) +static int parse_MP4DecConfigDescrTag(MP4DescrParseContext *d, int64_t off, + int len) { Mp4Descr *descr = d->active_descr; if (!descr) - return -1; + return AVERROR_INVALIDDATA; d->active_descr->dec_config_descr = av_malloc(len); if (!descr->dec_config_descr) return AVERROR(ENOMEM); @@ -1218,21 +1294,26 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len) Mp4Descr *descr = d->active_descr; int predefined; if (!descr) - return -1; + return AVERROR_INVALIDDATA; predefined = avio_r8(&d->pb); if (!predefined) { int lengths; int flags = avio_r8(&d->pb); - descr->sl.use_au_start = !!(flags & 0x80); - descr->sl.use_au_end = !!(flags & 0x40); - descr->sl.use_rand_acc_pt = !!(flags & 0x20); - descr->sl.use_padding = !!(flags & 0x08); - descr->sl.use_timestamps = !!(flags & 0x04); - descr->sl.use_idle = !!(flags & 0x02); - descr->sl.timestamp_res = avio_rb32(&d->pb); - avio_rb32(&d->pb); + descr->sl.use_au_start = !!(flags & 0x80); + descr->sl.use_au_end = !!(flags & 0x40); + descr->sl.use_rand_acc_pt = !!(flags & 0x20); + descr->sl.use_padding = !!(flags & 0x08); + descr->sl.use_timestamps = !!(flags & 0x04); + descr->sl.use_idle = !!(flags & 0x02); + descr->sl.timestamp_res = avio_rb32(&d->pb); + avio_rb32(&d->pb); descr->sl.timestamp_len = avio_r8(&d->pb); + if (descr->sl.timestamp_len > 64) { + avpriv_request_sample(NULL, "timestamp_len > 64"); + descr->sl.timestamp_len = 64; + return AVERROR_PATCHWELCOME; + } descr->sl.ocr_len = avio_r8(&d->pb); descr->sl.au_len = avio_r8(&d->pb); descr->sl.inst_bitrate_len = avio_r8(&d->pb); @@ -1247,13 +1328,16 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len) } static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len, - int target_tag) { + int target_tag) +{ int tag; int len1 = ff_mp4_read_descr(d->s, &d->pb, &tag); update_offsets(&d->pb, &off, &len); if (len < 0 || len1 > len || len1 <= 0) { - av_log(d->s, AV_LOG_ERROR, "Tag %x length violation new length %d bytes remaining %d\n", tag, len1, len); - return -1; + av_log(d->s, AV_LOG_ERROR, + "Tag %x length violation new length %d bytes remaining %d\n", + tag, len1, len); + return AVERROR_INVALIDDATA; } if (d->level++ >= MAX_LEVEL) { @@ -1262,7 +1346,8 @@ static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len, } if (target_tag && tag != target_tag) { - av_log(d->s, AV_LOG_ERROR, "Found tag %x expected %x\n", tag, target_tag); + av_log(d->s, AV_LOG_ERROR, "Found tag %x expected %x\n", tag, + target_tag); goto done; } @@ -1284,6 +1369,7 @@ static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len, break; } + done: d->level--; avio_seek(&d->pb, off + len1, SEEK_SET); @@ -1294,36 +1380,43 @@ static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size, Mp4Descr *descr, int *descr_count, int max_descr_count) { MP4DescrParseContext d; - if (init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count) < 0) - return -1; + int ret; + + ret = init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count); + if (ret < 0) + return ret; - parse_mp4_descr(&d, avio_tell(&d.pb), size, MP4IODescrTag); + ret = parse_mp4_descr(&d, avio_tell(&d.pb), size, MP4IODescrTag); *descr_count = d.descr_count; - return 0; + return ret; } static int mp4_read_od(AVFormatContext *s, const uint8_t *buf, unsigned size, Mp4Descr *descr, int *descr_count, int max_descr_count) { MP4DescrParseContext d; - if (init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count) < 0) - return -1; + int ret; - parse_mp4_descr_arr(&d, avio_tell(&d.pb), size); + ret = init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count); + if (ret < 0) + return ret; + + ret = parse_mp4_descr_arr(&d, avio_tell(&d.pb), size); *descr_count = d.descr_count; - return 0; + return ret; } -static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) +static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, + int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; SectionHeader h; const uint8_t *p, *p_end; AVIOContext pb; - Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }}; int mp4_descr_count = 0; + Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } }; int i, pid; AVFormatContext *s = ts->stream; @@ -1334,30 +1427,31 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_le if (h.tid != M4OD_TID) return; - mp4_read_od(s, p, (unsigned)(p_end - p), mp4_descr, &mp4_descr_count, MAX_MP4_DESCR_COUNT); + mp4_read_od(s, p, (unsigned) (p_end - p), mp4_descr, &mp4_descr_count, + MAX_MP4_DESCR_COUNT); for (pid = 0; pid < NB_PID_MAX; pid++) { if (!ts->pids[pid]) - continue; + continue; for (i = 0; i < mp4_descr_count; i++) { PESContext *pes; AVStream *st; if (ts->pids[pid]->es_id != mp4_descr[i].es_id) continue; - if (!(ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES)) { + if (ts->pids[pid]->type != MPEGTS_PES) { av_log(s, AV_LOG_ERROR, "pid %x is not PES\n", pid); continue; } pes = ts->pids[pid]->u.pes_filter.opaque; - st = pes->st; - if (!st) { + st = pes->st; + if (!st) continue; - } pes->sl = mp4_descr[i].sl; ffio_init_context(&pb, mp4_descr[i].dec_config_descr, - mp4_descr[i].dec_config_descr_len, 0, NULL, NULL, NULL, NULL); + mp4_descr[i].dec_config_descr_len, 0, + NULL, NULL, NULL, NULL); ff_mp4_read_dec_config_descr(s, st, &pb); if (st->codec->codec_id == AV_CODEC_ID_AAC && st->codec->extradata_size > 0) @@ -1367,13 +1461,13 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_le st->need_parsing = 0; if (st->codec->codec_id <= AV_CODEC_ID_NONE) { - } else if (st->codec->codec_id < AV_CODEC_ID_FIRST_AUDIO) { + // do nothing + } else if (st->codec->codec_id < AV_CODEC_ID_FIRST_AUDIO) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - } else if (st->codec->codec_id < AV_CODEC_ID_FIRST_SUBTITLE) { + else if (st->codec->codec_id < AV_CODEC_ID_FIRST_SUBTITLE) st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - } else if (st->codec->codec_id < AV_CODEC_ID_FIRST_UNKNOWN) { + else if (st->codec->codec_id < AV_CODEC_ID_FIRST_UNKNOWN) st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - } } } for (i = 0; i < mp4_descr_count; i++) @@ -1392,13 +1486,13 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type desc_tag = get8(pp, desc_list_end); if (desc_tag < 0) - return -1; + return AVERROR_INVALIDDATA; desc_len = get8(pp, desc_list_end); if (desc_len < 0) - return -1; + return AVERROR_INVALIDDATA; desc_end = *pp + desc_len; if (desc_end > desc_list_end) - return -1; + return AVERROR_INVALIDDATA; av_dlog(fc, "tag: 0x%02x len=%d\n", desc_tag, desc_len); @@ -1406,73 +1500,149 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type stream_type == STREAM_TYPE_PRIVATE_DATA) mpegts_find_stream_type(st, desc_tag, DESC_types); - switch(desc_tag) { + switch (desc_tag) { case 0x1E: /* SL descriptor */ desc_es_id = get16(pp, desc_end); if (ts && ts->pids[pid]) ts->pids[pid]->es_id = desc_es_id; for (i = 0; i < mp4_descr_count; i++) - if (mp4_descr[i].dec_config_descr_len && - mp4_descr[i].es_id == desc_es_id) { - AVIOContext pb; - ffio_init_context(&pb, mp4_descr[i].dec_config_descr, - mp4_descr[i].dec_config_descr_len, 0, NULL, NULL, NULL, NULL); - ff_mp4_read_dec_config_descr(fc, st, &pb); - if (st->codec->codec_id == AV_CODEC_ID_AAC && - st->codec->extradata_size > 0) - st->need_parsing = 0; - if (st->codec->codec_id == AV_CODEC_ID_MPEG4SYSTEMS) - mpegts_open_section_filter(ts, pid, m4sl_cb, ts, 1); - } + if (mp4_descr[i].dec_config_descr_len && + mp4_descr[i].es_id == desc_es_id) { + AVIOContext pb; + ffio_init_context(&pb, mp4_descr[i].dec_config_descr, + mp4_descr[i].dec_config_descr_len, 0, + NULL, NULL, NULL, NULL); + ff_mp4_read_dec_config_descr(fc, st, &pb); + if (st->codec->codec_id == AV_CODEC_ID_AAC && + st->codec->extradata_size > 0) + st->need_parsing = 0; + if (st->codec->codec_id == AV_CODEC_ID_MPEG4SYSTEMS) + mpegts_open_section_filter(ts, pid, m4sl_cb, ts, 1); + } break; case 0x1F: /* FMC descriptor */ get16(pp, desc_end); - if (mp4_descr_count > 0 && (st->codec->codec_id == AV_CODEC_ID_AAC_LATM || st->request_probe>0) && + if (mp4_descr_count > 0 && + (st->codec->codec_id == AV_CODEC_ID_AAC_LATM || st->request_probe > 0) && mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) { AVIOContext pb; ffio_init_context(&pb, mp4_descr->dec_config_descr, - mp4_descr->dec_config_descr_len, 0, NULL, NULL, NULL, NULL); + mp4_descr->dec_config_descr_len, 0, + NULL, NULL, NULL, NULL); ff_mp4_read_dec_config_descr(fc, st, &pb); if (st->codec->codec_id == AV_CODEC_ID_AAC && - st->codec->extradata_size > 0){ - st->request_probe= st->need_parsing = 0; - st->codec->codec_type= AVMEDIA_TYPE_AUDIO; + st->codec->extradata_size > 0) { + st->request_probe = st->need_parsing = 0; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; } } break; case 0x56: /* DVB teletext descriptor */ - language[0] = get8(pp, desc_end); - language[1] = get8(pp, desc_end); - language[2] = get8(pp, desc_end); - language[3] = 0; - av_dict_set(&st->metadata, "language", language, 0); + { + uint8_t *extradata = NULL; + int language_count = desc_len / 5; + + if (desc_len > 0 && desc_len % 5 != 0) + return AVERROR_INVALIDDATA; + + if (language_count > 0) { + /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */ + if (language_count > sizeof(language) / 4) { + language_count = sizeof(language) / 4; + } + + if (st->codec->extradata == NULL) { + if (ff_alloc_extradata(st->codec, language_count * 2)) { + return AVERROR(ENOMEM); + } + } + + if (st->codec->extradata_size < language_count * 2) + return AVERROR_INVALIDDATA; + + extradata = st->codec->extradata; + + for (i = 0; i < language_count; i++) { + language[i * 4 + 0] = get8(pp, desc_end); + language[i * 4 + 1] = get8(pp, desc_end); + language[i * 4 + 2] = get8(pp, desc_end); + language[i * 4 + 3] = ','; + + memcpy(extradata, *pp, 2); + extradata += 2; + + *pp += 2; + } + + language[i * 4 - 1] = 0; + av_dict_set(&st->metadata, "language", language, 0); + } + } break; case 0x59: /* subtitling descriptor */ - language[0] = get8(pp, desc_end); - language[1] = get8(pp, desc_end); - language[2] = get8(pp, desc_end); - language[3] = 0; - /* hearing impaired subtitles detection */ - switch(get8(pp, desc_end)) { - case 0x20: /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */ - case 0x21: /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */ - case 0x22: /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */ - case 0x23: /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */ - case 0x24: /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */ - case 0x25: /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */ - st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; - break; - } - if (st->codec->extradata) { - if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4)) - avpriv_request_sample(fc, "DVB sub with multiple IDs"); - } else { - if (!ff_alloc_extradata(st->codec, 4)) { - memcpy(st->codec->extradata, *pp, 4); + { + /* 8 bytes per DVB subtitle substream data: + * ISO_639_language_code (3 bytes), + * subtitling_type (1 byte), + * composition_page_id (2 bytes), + * ancillary_page_id (2 bytes) */ + int language_count = desc_len / 8; + + if (desc_len > 0 && desc_len % 8 != 0) + return AVERROR_INVALIDDATA; + + if (language_count > 1) { + avpriv_request_sample(fc, "DVB subtitles with multiple languages"); + } + + if (language_count > 0) { + uint8_t *extradata; + + /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */ + if (language_count > sizeof(language) / 4) { + language_count = sizeof(language) / 4; + } + + if (st->codec->extradata == NULL) { + if (ff_alloc_extradata(st->codec, language_count * 5)) { + return AVERROR(ENOMEM); + } + } + + if (st->codec->extradata_size < language_count * 5) + return AVERROR_INVALIDDATA; + + extradata = st->codec->extradata; + + for (i = 0; i < language_count; i++) { + language[i * 4 + 0] = get8(pp, desc_end); + language[i * 4 + 1] = get8(pp, desc_end); + language[i * 4 + 2] = get8(pp, desc_end); + language[i * 4 + 3] = ','; + + /* hearing impaired subtitles detection using subtitling_type */ + switch (*pp[0]) { + case 0x20: /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */ + case 0x21: /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */ + case 0x22: /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */ + case 0x23: /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */ + case 0x24: /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */ + case 0x25: /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */ + st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; + break; + } + + extradata[4] = get8(pp, desc_end); /* subtitling_type */ + memcpy(extradata, *pp, 4); /* composition_page_id and ancillary_page_id */ + extradata += 5; + + *pp += 4; + } + + language[i * 4 - 1] = 0; + av_dict_set(&st->metadata, "language", language, 0); } } - *pp += 4; - av_dict_set(&st->metadata, "language", language, 0); break; case 0x0a: /* ISO 639 language descriptor */ for (i = 0; i + 4 <= desc_len; i += 4) { @@ -1480,11 +1650,17 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type language[i + 1] = get8(pp, desc_end); language[i + 2] = get8(pp, desc_end); language[i + 3] = ','; - switch (get8(pp, desc_end)) { - case 0x01: st->disposition |= AV_DISPOSITION_CLEAN_EFFECTS; break; - case 0x02: st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; break; - case 0x03: st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; break; - } + switch (get8(pp, desc_end)) { + case 0x01: + st->disposition |= AV_DISPOSITION_CLEAN_EFFECTS; + break; + case 0x02: + st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; + break; + case 0x03: + st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + break; + } } if (i) { language[i - 1] = 0; @@ -1493,7 +1669,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type break; case 0x05: /* registration descriptor */ st->codec->codec_tag = bytestream_get_le32(pp); - av_dlog(fc, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag); + av_dlog(fc, "reg_desc=%.4s\n", (char *)&st->codec->codec_tag); if (st->codec->codec_id == AV_CODEC_ID_NONE) mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types); break; @@ -1527,8 +1703,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len int desc_list_len; uint32_t prog_reg_desc = 0; /* registration descriptor */ - Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }}; int mp4_descr_count = 0; + Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } }; int i; av_dlog(ts->stream, "PMT: len %i\n", section_len); @@ -1540,7 +1716,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len return; av_dlog(ts->stream, "sid=0x%x sec_num=%d/%d\n", - h->id, h->sec_num, h->last_sec_num); + h->id, h->sec_num, h->last_sec_num); if (h->tid != PMT_TID) return; @@ -1559,15 +1735,15 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (program_info_length < 0) return; program_info_length &= 0xfff; - while(program_info_length >= 2) { + while (program_info_length >= 2) { uint8_t tag, len; tag = get8(&p, p_end); len = get8(&p, p_end); av_dlog(ts->stream, "program tag: 0x%02x len=%d\n", tag, len); - if(len > program_info_length - 2) - //something else is broken, exit the program_descriptors_loop + if (len > program_info_length - 2) + // something else is broken, exit the program_descriptors_loop break; program_info_length -= len + 2; if (tag == 0x1d) { // IOD descriptor @@ -1590,7 +1766,10 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (!ts->stream->nb_streams) ts->stop_parse = 2; - for(;;) { + set_pmt_found(ts, h->id); + + + for (;;) { st = 0; pes = NULL; stream_type = get8(&p, p_end); @@ -1598,23 +1777,24 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len break; pid = get16(&p, p_end); if (pid < 0) - break; + goto out; pid &= 0x1fff; if (pid == ts->current_pid) - break; + goto out; /* now create stream */ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (!pes->st) { - pes->st = avformat_new_stream(pes->stream, NULL); + pes->st = avformat_new_stream(pes->stream, NULL); if (!pes->st) goto out; pes->st->id = pes->pid; } st = pes->st; } else if (stream_type != 0x13) { - if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably + if (ts->pids[pid]) + mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); if (pes) { st = avformat_new_stream(pes->stream, NULL); @@ -1647,25 +1827,31 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len desc_list_len = get16(&p, p_end); if (desc_list_len < 0) - break; + goto out; desc_list_len &= 0xfff; - desc_list_end = p + desc_list_len; + desc_list_end = p + desc_list_len; if (desc_list_end > p_end) - break; - for(;;) { - if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end, - mp4_descr, mp4_descr_count, pid, ts) < 0) + goto out; + for (;;) { + if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, + desc_list_end, mp4_descr, + mp4_descr_count, pid, ts) < 0) break; - if (pes && prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) { - ff_program_add_stream_index(ts->stream, h->id, pes->sub_st->index); + if (pes && prog_reg_desc == AV_RL32("HDMV") && + stream_type == 0x83 && pes->sub_st) { + ff_program_add_stream_index(ts->stream, h->id, + pes->sub_st->index); pes->sub_st->codec->codec_tag = st->codec->codec_tag; } } p = desc_list_end; } - out: + if (!ts->pids[pcr_pid]) + mpegts_open_pcr_filter(ts, pcr_pid); + +out: for (i = 0; i < mp4_descr_count; i++) av_free(mp4_descr[i].dec_config_descr); } @@ -1682,7 +1868,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len hex_dump_debug(ts->stream, section, section_len); p_end = section + section_len - 4; - p = section; + p = section; if (parse_section_header(h, &p, p_end) < 0) return; if (h->tid != PAT_TID) @@ -1691,7 +1877,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len ts->stream->ts_id = h->id; clear_programs(ts); - for(;;) { + for (;;) { sid = get16(&p, p_end); if (sid < 0) break; @@ -1721,7 +1907,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (!ts->pids[pmt_pid]) mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); add_pat_entry(ts, sid); - add_pid_to_pmt(ts, sid, 0); //add pat pid to program + add_pid_to_pmt(ts, sid, 0); // add pat pid to program add_pid_to_pmt(ts, sid, pmt_pid); } } @@ -1729,7 +1915,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (sid < 0) { int i,j; for (j=0; j<ts->stream->nb_programs; j++) { - for (i=0; i<ts->nb_prg; i++) + for (i = 0; i < ts->nb_prg; i++) if (ts->prg[i].id == ts->stream->programs[j]->id) break; if (i==ts->nb_prg) @@ -1750,7 +1936,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len hex_dump_debug(ts->stream, section, section_len); p_end = section + section_len - 4; - p = section; + p = section; if (parse_section_header(h, &p, p_end) < 0) return; if (h->tid != SDT_TID) @@ -1761,7 +1947,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len val = get8(&p, p_end); if (val < 0) return; - for(;;) { + for (;;) { sid = get16(&p, p_end); if (sid < 0) break; @@ -1772,10 +1958,10 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (desc_list_len < 0) break; desc_list_len &= 0xfff; - desc_list_end = p + desc_list_len; + desc_list_end = p + desc_list_len; if (desc_list_end > p_end) break; - for(;;) { + for (;;) { desc_tag = get8(&p, desc_list_end); if (desc_tag < 0) break; @@ -1785,9 +1971,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len break; av_dlog(ts->stream, "tag: 0x%02x len=%d\n", - desc_tag, desc_len); + desc_tag, desc_len); - switch(desc_tag) { + switch (desc_tag) { case 0x48: service_type = get8(&p, p_end); if (service_type < 0) @@ -1798,9 +1984,10 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len name = getstr8(&p, p_end); if (name) { AVProgram *program = av_new_program(ts->stream, sid); - if(program) { + if (program) { av_dict_set(&program->metadata, "service_name", name, 0); - av_dict_set(&program->metadata, "service_provider", provider_name, 0); + av_dict_set(&program->metadata, "service_provider", + provider_name, 0); } } av_free(name); @@ -1829,7 +2016,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) int64_t pos; pid = AV_RB16(packet + 1) & 0x1fff; - if(pid && discard_pid(ts, pid)) + if (pid && discard_pid(ts, pid)) return 0; is_start = packet[1] & 0x40; tss = ts->pids[pid]; @@ -1844,32 +2031,32 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) afc = (packet[3] >> 4) & 3; if (afc == 0) /* reserved value */ return 0; - has_adaptation = afc & 2; - has_payload = afc & 1; - is_discontinuity = has_adaptation - && packet[4] != 0 /* with length > 0 */ - && (packet[5] & 0x80); /* and discontinuity indicated */ + has_adaptation = afc & 2; + has_payload = afc & 1; + is_discontinuity = has_adaptation && + packet[4] != 0 && /* with length > 0 */ + (packet[5] & 0x80); /* and discontinuity indicated */ /* continuity check (currently not used) */ cc = (packet[3] & 0xf); expected_cc = has_payload ? (tss->last_cc + 1) & 0x0f : tss->last_cc; - cc_ok = pid == 0x1FFF // null packet PID - || is_discontinuity - || tss->last_cc < 0 - || expected_cc == cc; + cc_ok = pid == 0x1FFF || // null packet PID + is_discontinuity || + tss->last_cc < 0 || + expected_cc == cc; tss->last_cc = cc; if (!cc_ok) { av_log(ts->stream, AV_LOG_DEBUG, "Continuity check failed for pid %d expected %d got %d\n", pid, expected_cc, cc); - if(tss->type == MPEGTS_PES) { + if (tss->type == MPEGTS_PES) { PESContext *pc = tss->u.pes_filter.opaque; pc->flags |= AV_PKT_FLAG_CORRUPT; } } - if (!has_payload) + if (!has_payload && tss->type != MPEGTS_PCR) return 0; p = packet + 4; if (has_adaptation) { @@ -1878,7 +2065,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } /* if past the end of packet, ignore */ p_end = packet + TS_PACKET_SIZE; - if (p >= p_end) + if (p > p_end || (p == p_end && tss->type != MPEGTS_PCR)) return 0; pos = avio_tell(ts->stream->pb); @@ -1912,17 +2099,35 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) p, p_end - p, 0); } } + + // stop find_stream_info from waiting for more streams + // when all programs have received a PMT + if (ts->stream->ctx_flags & AVFMTCTX_NOHEADER) { + int i; + for (i = 0; i < ts->nb_prg; i++) { + if (!ts->prg[i].pmt_found) + break; + } + if (i == ts->nb_prg && ts->nb_prg > 0) { + if (ts->stream->nb_streams > 1 || pos > 100000) { + av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n"); + ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER; + } + } + } + } else { int ret; - int64_t pcr = -1; int64_t pcr_h; int pcr_l; if (parse_pcr(&pcr_h, &pcr_l, packet) == 0) - pcr = pcr_h * 300 + pcr_l; + tss->last_pcr = pcr_h * 300 + pcr_l; // Note: The position here points actually behind the current packet. - if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, - pos - ts->raw_packet_size, pcr)) < 0) - return ret; + if (tss->type == MPEGTS_PES) { + if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, + pos - ts->raw_packet_size)) < 0) + return ret; + } } return 0; @@ -1931,7 +2136,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) static void reanalyze(MpegTSContext *ts) { AVIOContext *pb = ts->stream->pb; int64_t pos = avio_tell(pb); - if(pos < 0) + if (pos < 0) return; pos -= ts->pos47_full; if (pos == TS_PACKET_SIZE) { @@ -1943,7 +2148,7 @@ static void reanalyze(MpegTSContext *ts) { } ts->size_stat_count ++; - if(ts->size_stat_count > SIZE_STAT_THRESHOLD) { + if (ts->size_stat_count > SIZE_STAT_THRESHOLD) { int newsize = 0; if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) { newsize = TS_PACKET_SIZE; @@ -1962,34 +2167,36 @@ static void reanalyze(MpegTSContext *ts) { } /* XXX: try to find a better synchro over several packets (use - get_packet_size() ?) */ + * get_packet_size() ?) */ static int mpegts_resync(AVFormatContext *s) { AVIOContext *pb = s->pb; int c, i; - for(i = 0;i < MAX_RESYNC_SIZE; i++) { + for (i = 0; i < MAX_RESYNC_SIZE; i++) { c = avio_r8(pb); if (url_feof(pb)) - return -1; + return AVERROR_EOF; if (c == 0x47) { avio_seek(pb, -1, SEEK_CUR); reanalyze(s->priv_data); return 0; } } - av_log(s, AV_LOG_ERROR, "max resync size reached, could not find sync byte\n"); + av_log(s, AV_LOG_ERROR, + "max resync size reached, could not find sync byte\n"); /* no sync found */ - return -1; + return AVERROR_INVALIDDATA; } -/* return -1 if error or EOF. Return 0 if OK. */ -static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, const uint8_t **data) +/* return AVERROR_something if error or EOF. Return 0 if OK. */ +static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, + const uint8_t **data) { AVIOContext *pb = s->pb; int len; - for(;;) { + for (;;) { len = ffio_read_indirect(pb, buf, TS_PACKET_SIZE, data); if (len != TS_PACKET_SIZE) return len < 0 ? len : AVERROR_EOF; @@ -2032,13 +2239,13 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) for (i = 0; i < NB_PID_MAX; i++) { if (ts->pids[i]) { if (ts->pids[i]->type == MPEGTS_PES) { - PESContext *pes = ts->pids[i]->u.pes_filter.opaque; - av_buffer_unref(&pes->buffer); - pes->data_index = 0; - pes->state = MPEGTS_SKIP; /* skip until pes header */ - pes->last_pcr = -1; + PESContext *pes = ts->pids[i]->u.pes_filter.opaque; + av_buffer_unref(&pes->buffer); + pes->data_index = 0; + pes->state = MPEGTS_SKIP; /* skip until pes header */ } ts->pids[i]->last_cc = -1; + ts->pids[i]->last_pcr = -1; } } } @@ -2046,7 +2253,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) ts->stop_parse = 0; packet_num = 0; memset(packet + TS_PACKET_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE); - for(;;) { + for (;;) { packet_num++; if (nb_packets != 0 && packet_num >= nb_packets || ts->stop_parse > 1) { @@ -2070,41 +2277,41 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) static int mpegts_probe(AVProbeData *p) { - const int size= p->buf_size; - int maxscore=0; - int sumscore=0; + const int size = p->buf_size; + int maxscore = 0; + int sumscore = 0; int i; - int check_count= size / TS_FEC_PACKET_SIZE; + int check_count = size / TS_FEC_PACKET_SIZE; #define CHECK_COUNT 10 #define CHECK_BLOCK 100 if (check_count < CHECK_COUNT) - return -1; + return AVERROR_INVALIDDATA; - for (i=0; i<check_count; i+=CHECK_BLOCK){ + for (i = 0; i<check_count; i+=CHECK_BLOCK) { int left = FFMIN(check_count - i, CHECK_BLOCK); - int score = analyze(p->buf + TS_PACKET_SIZE *i, TS_PACKET_SIZE *left, TS_PACKET_SIZE , NULL); - int dvhs_score= analyze(p->buf + TS_DVHS_PACKET_SIZE*i, TS_DVHS_PACKET_SIZE*left, TS_DVHS_PACKET_SIZE, NULL); - int fec_score = analyze(p->buf + TS_FEC_PACKET_SIZE *i, TS_FEC_PACKET_SIZE *left, TS_FEC_PACKET_SIZE , NULL); + int score = analyze(p->buf + TS_PACKET_SIZE *i, TS_PACKET_SIZE *left, TS_PACKET_SIZE , NULL); + int dvhs_score = analyze(p->buf + TS_DVHS_PACKET_SIZE*i, TS_DVHS_PACKET_SIZE*left, TS_DVHS_PACKET_SIZE, NULL); + int fec_score = analyze(p->buf + TS_FEC_PACKET_SIZE *i, TS_FEC_PACKET_SIZE *left, TS_FEC_PACKET_SIZE , NULL); score = FFMAX3(score, dvhs_score, fec_score); sumscore += score; maxscore = FFMAX(maxscore, score); } - sumscore = sumscore*CHECK_COUNT/check_count; - maxscore = maxscore*CHECK_COUNT/CHECK_BLOCK; + sumscore = sumscore * CHECK_COUNT / check_count; + maxscore = maxscore * CHECK_COUNT / CHECK_BLOCK; av_dlog(0, "TS score: %d %d\n", sumscore, maxscore); - if (sumscore > 6) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT; - else if (maxscore > 6) return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT; - else return -1; + if (sumscore > 6) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT; + else if (maxscore > 6) return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT; + else + return AVERROR_INVALIDDATA; } /* return the 90kHz PCR and the extension for the 27MHz PCR. return - (-1) if not available */ -static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, - const uint8_t *packet) + * (-1) if not available */ +static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet) { int afc, len, flags; const uint8_t *p; @@ -2112,21 +2319,21 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, afc = (packet[3] >> 4) & 3; if (afc <= 1) - return -1; - p = packet + 4; + return AVERROR_INVALIDDATA; + p = packet + 4; len = p[0]; p++; if (len == 0) - return -1; + return AVERROR_INVALIDDATA; flags = *p++; len--; if (!(flags & 0x10)) - return -1; + return AVERROR_INVALIDDATA; if (len < 6) - return -1; - v = AV_RB32(p); - *ppcr_high = ((int64_t)v << 1) | (p[4] >> 7); - *ppcr_low = ((p[4] & 1) << 8) | p[5]; + return AVERROR_INVALIDDATA; + v = AV_RB32(p); + *ppcr_high = ((int64_t) v << 1) | (p[4] >> 7); + *ppcr_low = ((p[4] & 1) << 8) | p[5]; return 0; } @@ -2142,8 +2349,8 @@ static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) { static int mpegts_read_header(AVFormatContext *s) { MpegTSContext *ts = s->priv_data; - AVIOContext *pb = s->pb; - uint8_t buf[8*1024]={0}; + AVIOContext *pb = s->pb; + uint8_t buf[8 * 1024] = {0}; int len; int64_t pos; @@ -2157,7 +2364,7 @@ static int mpegts_read_header(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n"); ts->raw_packet_size = TS_PACKET_SIZE; } - ts->stream = s; + ts->stream = s; ts->auto_guess = 0; if (s->iformat == &ff_mpegts_demuxer) { @@ -2190,19 +2397,19 @@ static int mpegts_read_header(AVFormatContext *s) st = avformat_new_stream(s, NULL); if (!st) - goto fail; + return AVERROR(ENOMEM); avpriv_set_pts_info(st, 60, 1, 27000000); st->codec->codec_type = AVMEDIA_TYPE_DATA; - st->codec->codec_id = AV_CODEC_ID_MPEG2TS; + st->codec->codec_id = AV_CODEC_ID_MPEG2TS; /* we iterate until we find two PCRs to estimate the bitrate */ - pcr_pid = -1; - nb_pcrs = 0; + pcr_pid = -1; + nb_pcrs = 0; nb_packets = 0; - for(;;) { + for (;;) { ret = read_packet(s, packet, ts->raw_packet_size, &data); if (ret < 0) - goto fail; + return ret; pid = AV_RB16(data + 1) & 0x1fff; if ((pcr_pid == -1 || pcr_pid == pid) && parse_pcr(&pcr_h, &pcr_l, data) == 0) { @@ -2222,24 +2429,21 @@ static int mpegts_read_header(AVFormatContext *s) /* NOTE1: the bitrate is computed without the FEC */ /* NOTE2: it is only the bitrate of the start of the stream */ ts->pcr_incr = (pcrs[1] - pcrs[0]) / (packet_count[1] - packet_count[0]); - ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0]; - s->bit_rate = (TS_PACKET_SIZE * 8) * 27e6 / ts->pcr_incr; + ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0]; + s->bit_rate = TS_PACKET_SIZE * 8 * 27e6 / ts->pcr_incr; st->codec->bit_rate = s->bit_rate; - st->start_time = ts->cur_pcr; + st->start_time = ts->cur_pcr; av_dlog(ts->stream, "start=%0.3f pcr=%0.3f incr=%d\n", st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr); } seek_back(s, pb, pos); return 0; - fail: - return -1; } #define MAX_PACKET_READAHEAD ((128 * 1024) / 188) -static int mpegts_raw_read_packet(AVFormatContext *s, - AVPacket *pkt) +static int mpegts_raw_read_packet(AVFormatContext *s, AVPacket *pkt) { MpegTSContext *ts = s->priv_data; int ret, i; @@ -2250,8 +2454,8 @@ static int mpegts_raw_read_packet(AVFormatContext *s, if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) return AVERROR(ENOMEM); - pkt->pos= avio_tell(s->pb); ret = read_packet(s, pkt->data, ts->raw_packet_size, &data); + pkt->pos = avio_tell(s->pb); if (ret < 0) { av_free_packet(pkt); return ret; @@ -2264,12 +2468,13 @@ static int mpegts_raw_read_packet(AVFormatContext *s, if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) { /* we read the next PCR (XXX: optimize it by using a bigger buffer */ pos = avio_tell(s->pb); - for(i = 0; i < MAX_PACKET_READAHEAD; i++) { + for (i = 0; i < MAX_PACKET_READAHEAD; i++) { avio_seek(s->pb, pos + i * ts->raw_packet_size, SEEK_SET); avio_read(s->pb, pcr_buf, 12); if (parse_pcr(&next_pcr_h, &next_pcr_l, pcr_buf) == 0) { /* XXX: not precise enough */ - ts->pcr_incr = ((next_pcr_h - pcr_h) * 300 + (next_pcr_l - pcr_l)) / + ts->pcr_incr = + ((next_pcr_h - pcr_h) * 300 + (next_pcr_l - pcr_l)) / (i + 1); break; } @@ -2278,16 +2483,15 @@ static int mpegts_raw_read_packet(AVFormatContext *s, /* no next PCR found: we use previous increment */ ts->cur_pcr = pcr_h * 300 + pcr_l; } - pkt->pts = ts->cur_pcr; + pkt->pts = ts->cur_pcr; pkt->duration = ts->pcr_incr; - ts->cur_pcr += ts->pcr_incr; + ts->cur_pcr += ts->pcr_incr; } pkt->stream_index = 0; return 0; } -static int mpegts_read_packet(AVFormatContext *s, - AVPacket *pkt) +static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt) { MpegTSContext *ts = s->priv_data; int ret, i; @@ -2298,7 +2502,7 @@ static int mpegts_read_packet(AVFormatContext *s, if (ret < 0) { av_free_packet(ts->pkt); /* flush pes data left */ - for (i = 0; i < NB_PID_MAX; i++) { + for (i = 0; i < NB_PID_MAX; i++) if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) { PESContext *pes = ts->pids[i]->u.pes_filter.opaque; if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { @@ -2308,7 +2512,6 @@ static int mpegts_read_packet(AVFormatContext *s, break; } } - } } if (!ret && pkt->size < 0) @@ -2322,8 +2525,9 @@ static void mpegts_free(MpegTSContext *ts) clear_programs(ts); - for(i=0;i<NB_PID_MAX;i++) - if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); + for (i = 0; i < NB_PID_MAX; i++) + if (ts->pids[i]) + mpegts_close_filter(ts, ts->pids[i]); } static int mpegts_read_close(AVFormatContext *s) @@ -2339,9 +2543,12 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, MpegTSContext *ts = s->priv_data; int64_t pos, timestamp; uint8_t buf[TS_PACKET_SIZE]; - int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid; + int pcr_l, pcr_pid = + ((PESContext *)s->streams[stream_index]->priv_data)->pcr_pid; int pos47 = ts->pos47_full % ts->raw_packet_size; - pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47; + pos = + ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * + ts->raw_packet_size + pos47; while(pos < pos_limit) { if (avio_seek(s->pb, pos, SEEK_SET) < 0) return AV_NOPTS_VALUE; @@ -2379,15 +2586,15 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index, int ret; AVPacket pkt; av_init_packet(&pkt); - ret= av_read_frame(s, &pkt); - if(ret < 0) + ret = av_read_frame(s, &pkt); + if (ret < 0) return AV_NOPTS_VALUE; av_free_packet(&pkt); - if(pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0){ + if (pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0) { ff_reduce_index(s, pkt.stream_index); av_add_index_entry(s->streams[pkt.stream_index], pkt.pos, pkt.dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */); - if(pkt.stream_index == stream_index && pkt.pos >= *ppos){ - *ppos= pkt.pos; + if (pkt.stream_index == stream_index && pkt.pos >= *ppos) { + *ppos = pkt.pos; return pkt.dts; } } @@ -2418,18 +2625,18 @@ MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s) } /* return the consumed length if a packet was output, or -1 if no - packet is output */ + * packet is output */ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, - const uint8_t *buf, int len) + const uint8_t *buf, int len) { int len1; len1 = len; ts->pkt = pkt; - for(;;) { + for (;;) { ts->stop_parse = 0; if (len < TS_PACKET_SIZE) - return -1; + return AVERROR_INVALIDDATA; if (buf[0] != 0x47) { buf++; len--; diff --git a/chromium/third_party/ffmpeg/libavformat/mpegts.h b/chromium/third_party/ffmpeg/libavformat/mpegts.h index 269c23b9257..7dfe844bdb0 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegts.h +++ b/chromium/third_party/ffmpeg/libavformat/mpegts.h @@ -52,12 +52,14 @@ #define STREAM_TYPE_AUDIO_AAC_LATM 0x11 #define STREAM_TYPE_VIDEO_MPEG4 0x10 #define STREAM_TYPE_VIDEO_H264 0x1b +#define STREAM_TYPE_VIDEO_HEVC 0x24 //Definition of 0x24 HEVC video MPEG TS stream type #define STREAM_TYPE_VIDEO_CAVS 0x42 #define STREAM_TYPE_VIDEO_VC1 0xea #define STREAM_TYPE_VIDEO_DIRAC 0xd1 #define STREAM_TYPE_AUDIO_AC3 0x81 -#define STREAM_TYPE_AUDIO_DTS 0x8a +#define STREAM_TYPE_AUDIO_DTS 0x82 +#define STREAM_TYPE_AUDIO_TRUEHD 0x83 typedef struct MpegTSContext MpegTSContext; @@ -104,4 +106,10 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type Mp4Descr *mp4_descr, int mp4_descr_count, int pid, MpegTSContext *ts); +/** + * Check presence of H264 startcode + * @return <0 to stop processing + */ +int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt); + #endif /* AVFORMAT_MPEGTS_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c index 1d51b97bdf0..48477614fed 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c @@ -86,6 +86,8 @@ typedef struct MpegTSWrite { int flags; int copyts; int tables_version; + + int omit_video_pes_length; } MpegTSWrite; /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */ @@ -124,6 +126,8 @@ static const AVOption options[] = { offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_INT, {.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}, + { "omit_video_pes_length", "Omit the PES packet length for video packets", + offsetof(MpegTSWrite, omit_video_pes_length), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; @@ -259,7 +263,7 @@ static void mpegts_write_pat(AVFormatContext *s) data, q - data); } -static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) +static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) { MpegTSWrite *ts = s->priv_data; uint8_t data[1012], *q, *desc_length_ptr, *program_info_length_ptr; @@ -292,6 +296,9 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) case AV_CODEC_ID_H264: stream_type = STREAM_TYPE_VIDEO_H264; break; + case AV_CODEC_ID_HEVC: + stream_type = STREAM_TYPE_VIDEO_HEVC; + break; case AV_CODEC_ID_CAVS: stream_type = STREAM_TYPE_VIDEO_CAVS; break; @@ -311,10 +318,20 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) case AV_CODEC_ID_AC3: stream_type = STREAM_TYPE_AUDIO_AC3; break; + case AV_CODEC_ID_DTS: + stream_type = STREAM_TYPE_AUDIO_DTS; + break; + case AV_CODEC_ID_TRUEHD: + stream_type = STREAM_TYPE_AUDIO_TRUEHD; + break; default: stream_type = STREAM_TYPE_PRIVATE_DATA; break; } + + if (q - data > sizeof(data) - 32) + return AVERROR(EINVAL); + *q++ = stream_type; put16(&q, 0xe000 | ts_st->pid); desc_length_ptr = q; @@ -346,7 +363,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) len_ptr = q++; *len_ptr = 0; - for (p = lang->value; next && *len_ptr < 255 / 4 * 4; p = next + 1) { + for (p = lang->value; next && *len_ptr < 255 / 4 * 4 && q - data < sizeof(data) - 4; p = next + 1) { next = strchr(p, ','); if (strlen(p) != 3 && (!next || next != p + 3)) continue; /* not a 3-letter code */ @@ -373,21 +390,79 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) break; case AVMEDIA_TYPE_SUBTITLE: { - const char *language; - language = lang && strlen(lang->value)==3 ? lang->value : "eng"; - *q++ = 0x59; - *q++ = 8; - *q++ = language[0]; - *q++ = language[1]; - *q++ = language[2]; - *q++ = 0x10; /* normal subtitles (0x20 = if hearing pb) */ - if(st->codec->extradata_size == 4) { - memcpy(q, st->codec->extradata, 4); - q += 4; - } else { - put16(&q, 1); /* page id */ - put16(&q, 1); /* ancillary page id */ - } + const char default_language[] = "und"; + const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language; + + if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) { + uint8_t *len_ptr; + int extradata_copied = 0; + + *q++ = 0x59; /* subtitling_descriptor */ + len_ptr = q++; + + while (strlen(language) >= 3 && (sizeof(data) - (q - data)) >= 8) { /* 8 bytes per DVB subtitle substream data */ + *q++ = *language++; + *q++ = *language++; + *q++ = *language++; + /* Skip comma */ + if (*language != '\0') + language++; + + if (st->codec->extradata_size - extradata_copied >= 5) { + *q++ = st->codec->extradata[extradata_copied + 4]; /* subtitling_type */ + memcpy(q, st->codec->extradata + extradata_copied, 4); /* composition_page_id and ancillary_page_id */ + extradata_copied += 5; + q += 4; + } else { + /* subtitling_type: + * 0x10 - normal with no monitor aspect ratio criticality + * 0x20 - for the hard of hearing with no monitor aspect ratio criticality */ + *q++ = (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED) ? 0x20 : 0x10; + if ((st->codec->extradata_size == 4) && (extradata_copied == 0)) { + /* support of old 4-byte extradata format */ + memcpy(q, st->codec->extradata, 4); /* composition_page_id and ancillary_page_id */ + extradata_copied += 4; + q += 4; + } else { + put16(&q, 1); /* composition_page_id */ + put16(&q, 1); /* ancillary_page_id */ + } + } + } + + *len_ptr = q - len_ptr - 1; + } else if (st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) { + uint8_t *len_ptr = NULL; + int extradata_copied = 0; + + /* The descriptor tag. teletext_descriptor */ + *q++ = 0x56; + len_ptr = q++; + + while (strlen(language) >= 3 && q - data < sizeof(data) - 6) { + *q++ = *language++; + *q++ = *language++; + *q++ = *language++; + /* Skip comma */ + if (*language != '\0') + language++; + + if (st->codec->extradata_size - 1 > extradata_copied) { + memcpy(q, st->codec->extradata + extradata_copied, 2); + extradata_copied += 2; + q += 2; + } else { + /* The Teletext descriptor: + * teletext_type: This 5-bit field indicates the type of Teletext page indicated. (0x01 Initial Teletext page) + * teletext_magazine_number: This is a 3-bit field which identifies the magazine number. + * teletext_page_number: This is an 8-bit field giving two 4-bit hex digits identifying the page number. */ + *q++ = 0x08; + *q++ = 0x00; + } + } + + *len_ptr = q - len_ptr - 1; + } } break; case AVMEDIA_TYPE_VIDEO: @@ -418,6 +493,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) } mpegts_write_section1(&service->pmt, PMT_TID, service->sid, ts->tables_version, 0, 0, data, q - data); + return 0; } /* NOTE: str == NULL is accepted for an empty string */ @@ -562,7 +638,7 @@ static int mpegts_write_header(AVFormatContext *s) ts->sdt.write_packet = section_write_packet; ts->sdt.opaque = s; - pids = av_malloc(s->nb_streams * sizeof(*pids)); + pids = av_malloc_array(s->nb_streams, sizeof(*pids)); if (!pids) return AVERROR(ENOMEM); @@ -630,6 +706,10 @@ static int mpegts_write_header(AVFormatContext *s) goto fail; } ast = avformat_new_stream(ts_st->amux, NULL); + if (!ast) { + ret = AVERROR(ENOMEM); + goto fail; + } ret = avcodec_copy_context(ast->codec, st->codec); if (ret != 0) goto fail; @@ -859,7 +939,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, MpegTSWrite *ts = s->priv_data; uint8_t buf[TS_PACKET_SIZE]; uint8_t *q; - int val, is_start, len, header_len, write_pcr, private_code, flags; + int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags; int afc_len, stuffing_len; int64_t pcr = -1; /* avoid warning */ int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE); @@ -923,11 +1003,13 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, } if (is_start) { int pes_extension = 0; + int pes_header_stuffing_bytes = 0; /* write PES header */ *q++ = 0x00; *q++ = 0x00; *q++ = 0x01; - private_code = 0; + is_dvb_subtitle = 0; + is_dvb_teletext = 0; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (st->codec->codec_id == AV_CODEC_ID_DIRAC) { *q++ = 0xfd; @@ -944,8 +1026,12 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, *q++ = 0xfd; } else { *q++ = 0xbd; - if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - private_code = 0x20; + if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) { + is_dvb_subtitle = 1; + } else if (st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) { + is_dvb_teletext = 1; + } } } header_len = 0; @@ -982,11 +1068,21 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, flags |= 0x01; header_len += 3; } + if (is_dvb_teletext) { + pes_header_stuffing_bytes = 0x24 - header_len; + header_len = 0x24; + } len = payload_size + header_len + 3; - if (private_code != 0) - len++; + /* 3 extra bytes should be added to DVB subtitle payload: 0x20 0x00 at the beginning and trailing 0xff */ + if (is_dvb_subtitle) { + len += 3; + payload_size++; + } if (len > 0xffff) len = 0; + if (ts->omit_video_pes_length && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + len = 0; + } *q++ = len >> 8; *q++ = len; val = 0x80; @@ -1025,8 +1121,17 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, } - if (private_code != 0) - *q++ = private_code; + if (is_dvb_subtitle) { + /* First two fields of DVB subtitles PES data: + * data_identifier: for DVB subtitle streams shall be coded with the value 0x20 + * subtitle_stream_id: for DVB subtitle stream shall be identified by the value 0x00 */ + *q++ = 0x20; + *q++ = 0x00; + } + if (is_dvb_teletext) { + memset(q, 0xff, pes_header_stuffing_bytes); + q += pes_header_stuffing_bytes; + } is_start = 0; } /* header size */ @@ -1057,7 +1162,14 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, } } } - memcpy(buf + TS_PACKET_SIZE - len, payload, len); + + if (is_dvb_subtitle && payload_size == len) { + memcpy(buf + TS_PACKET_SIZE - len, payload, len - 1); + buf[TS_PACKET_SIZE - 1] = 0xff; /* end_of_PES_data_field_marker: an 8-bit field with fixed contents 0xff for DVB subtitle */ + } else { + memcpy(buf + TS_PACKET_SIZE - len, payload, len); + } + payload += len; payload_size -= len; mpegts_prefix_m2ts_header(s); @@ -1067,6 +1179,19 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, ts_st->prev_payload_key = key; } +int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt) +{ + if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) { + if (!st->nb_frames) { + av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, " + "no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb)\n"); + return AVERROR(EINVAL); + } + av_log(s, AV_LOG_WARNING, "H.264 bitstream error, startcode missing\n"); + } + return 0; +} + static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; @@ -1106,15 +1231,9 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) if (st->codec->codec_id == AV_CODEC_ID_H264) { const uint8_t *p = buf, *buf_end = p+size; uint32_t state = -1; - - if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) { - if (!st->nb_frames) { - av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, " - "no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb)\n"); - return AVERROR(EINVAL); - } - av_log(s, AV_LOG_WARNING, "H.264 bitstream error, startcode missing\n"); - } + int ret = ff_check_h264_startcode(s, st, pkt); + if (ret < 0) + return ret; do { p = avpriv_find_start_code(p, buf_end, &state); diff --git a/chromium/third_party/ffmpeg/libavformat/mtv.c b/chromium/third_party/ffmpeg/libavformat/mtv.c index 0517dd2d835..b449d5886f1 100644 --- a/chromium/third_party/ffmpeg/libavformat/mtv.c +++ b/chromium/third_party/ffmpeg/libavformat/mtv.c @@ -32,7 +32,8 @@ #define MTV_ASUBCHUNK_DATA_SIZE 500 #define MTV_HEADER_SIZE 512 #define MTV_AUDIO_PADDING_SIZE 12 -#define AUDIO_SAMPLING_RATE 44100 +#define MTV_IMAGE_DEFAULT_BPP 16 +#define MTV_AUDIO_SAMPLING_RATE 44100 typedef struct MTVDemuxContext { @@ -52,12 +53,22 @@ typedef struct MTVDemuxContext { static int mtv_probe(AVProbeData *p) { + /* we need at least 57 bytes from the header + * to try parsing all required fields + */ + if (p->buf_size < 57) + return 0; + /* Magic is 'AMV' */ if (*p->buf != 'A' || *(p->buf + 1) != 'M' || *(p->buf + 2) != 'V') return 0; + /* Audio magic is always MP3 */ + if (p->buf[43] != 'M' || p->buf[44] != 'P' || p->buf[45] != '3') + return 0; + /* Check for nonzero in bpp and (width|height) header fields */ - if(p->buf_size < 57 || !(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54]))) + if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54]))) return 0; /* If width or height are 0 then imagesize header field should not */ @@ -69,8 +80,20 @@ static int mtv_probe(AVProbeData *p) return 0; } - if(p->buf[51] != 16) - return AVPROBE_SCORE_EXTENSION / 2; // But we are going to assume 16bpp anyway .. + /* Image bpp is not an absolutely required + * field as we latter claim it should be 16 + * no matter what. All samples in the wild + * are RGB565/555. + */ + if(p->buf[51] != MTV_IMAGE_DEFAULT_BPP) + return AVPROBE_SCORE_EXTENSION / 2; + + /* We had enough data to parse header values + * but we expect to be able to get 512 bytes + * of header to be sure. + */ + if (p->buf_size < MTV_HEADER_SIZE) + return AVPROBE_SCORE_EXTENSION; return AVPROBE_SCORE_MAX; } @@ -89,22 +112,30 @@ static int mtv_read_header(AVFormatContext *s) mtv->audio_identifier = avio_rl24(pb); mtv->audio_br = avio_rl16(pb); mtv->img_colorfmt = avio_rl24(pb); - mtv->img_bpp = avio_r8(pb); + mtv->img_bpp = avio_r8(pb)>>3; mtv->img_width = avio_rl16(pb); mtv->img_height = avio_rl16(pb); mtv->img_segment_size = avio_rl16(pb); + /* Assume 16bpp even if claimed otherwise. + * We know its going to be RGBG565/555 anyway + */ + if (mtv->img_bpp != MTV_IMAGE_DEFAULT_BPP) { + av_log (s, AV_LOG_WARNING, "Header claims %dbpp (!= 16). Ignoring\n", + mtv->img_bpp); + mtv->img_bpp = MTV_IMAGE_DEFAULT_BPP; + } + /* Calculate width and height if missing from header */ - if(mtv->img_bpp>>3){ if(!mtv->img_width && mtv->img_height) - mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3) + mtv->img_width=mtv->img_segment_size / (mtv->img_bpp) / mtv->img_height; if(!mtv->img_height && mtv->img_width) - mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3) + mtv->img_height=mtv->img_segment_size / (mtv->img_bpp) / mtv->img_width; - } + if(!mtv->img_height || !mtv->img_width || !mtv->img_segment_size){ av_log(s, AV_LOG_ERROR, "width or height or segment_size is invalid and I cannot calculate them from other information\n"); return AVERROR(EINVAL); @@ -149,7 +180,7 @@ static int mtv_read_header(AVFormatContext *s) if(!st) return AVERROR(ENOMEM); - avpriv_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE); + avpriv_set_pts_info(st, 64, 1, MTV_AUDIO_SAMPLING_RATE); st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = AV_CODEC_ID_MP3; st->codec->bit_rate = mtv->audio_br; diff --git a/chromium/third_party/ffmpeg/libavformat/mux.c b/chromium/third_party/ffmpeg/libavformat/mux.c index 79625c6547c..a3a63f29a53 100644 --- a/chromium/third_party/ffmpeg/libavformat/mux.c +++ b/chromium/third_party/ffmpeg/libavformat/mux.c @@ -102,7 +102,7 @@ static void frac_add(AVFrac *f, int64_t incr) f->num = num; } -AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission) +AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precision) { AVRational q; int j; @@ -113,9 +113,9 @@ AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precissi q = st->codec->time_base; } for (j=2; j<14; j+= 1+(j>2)) - while (q.den / q.num < min_precission && q.num % j == 0) + while (q.den / q.num < min_precision && q.num % j == 0) q.num /= j; - while (q.den / q.num < min_precission && q.den < (1<<24)) + while (q.den / q.num < min_precision && q.den < (1<<24)) q.den <<= 1; return q; @@ -189,7 +189,7 @@ static int validate_codec_tag(AVFormatContext *s, AVStream *st) const AVCodecTag *avctag; int n; enum AVCodecID id = AV_CODEC_ID_NONE; - unsigned int tag = 0; + int64_t tag = -1; /** * Check that tag + id is in the table @@ -212,7 +212,7 @@ static int validate_codec_tag(AVFormatContext *s, AVStream *st) } if (id != AV_CODEC_ID_NONE) return 0; - if (tag && (st->codec->strict_std_compliance >= FF_COMPLIANCE_NORMAL)) + if (tag >= 0 && (st->codec->strict_std_compliance >= FF_COMPLIANCE_NORMAL)) return 0; return 1; } @@ -232,12 +232,17 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) if ((ret = av_opt_set_dict(s, &tmp)) < 0) goto fail; if (s->priv_data && s->oformat->priv_class && *(const AVClass**)s->priv_data==s->oformat->priv_class && - (ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) + (ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; +#if FF_API_LAVF_BITEXACT + if (s->nb_streams && s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT) + s->flags |= AVFMT_FLAG_BITEXACT; +#endif + // some sanity checks if (s->nb_streams == 0 && !(of->flags & AVFMT_NOSTREAMS)) { - av_log(s, AV_LOG_ERROR, "no streams\n"); + av_log(s, AV_LOG_ERROR, "No streams to mux were specified\n"); ret = AVERROR(EINVAL); goto fail; } @@ -320,6 +325,9 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) av_log(s, AV_LOG_WARNING, "Codec for stream %d does not use global headers " "but container format requires global headers\n", i); + + if (codec->codec_type != AVMEDIA_TYPE_ATTACHMENT) + s->internal->nb_interleaved_streams++; } if (!s->priv_data && of->priv_data_size > 0) { @@ -331,13 +339,13 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) if (of->priv_class) { *(const AVClass **)s->priv_data = of->priv_class; av_opt_set_defaults(s->priv_data); - if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) + if ((ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; } } /* set muxer identification string */ - if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { + if (!(s->flags & AVFMT_FLAG_BITEXACT)) { av_dict_set(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0); } else { av_dict_set(&s->metadata, "encoder", NULL, 0); @@ -414,6 +422,15 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) return 0; } +#define AV_PKT_FLAG_UNCODED_FRAME 0x2000 + +/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but + it is only being used internally to this file as a consistency check. + The value is chosen to be very unlikely to appear on its own and to cause + immediate failure if used anywhere as a real size. */ +#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame)) + + //FIXME merge with compute_pkt_fields static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) { @@ -423,6 +440,12 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) av_dlog(s, "compute_pkt_fields2: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), delay, pkt->size, pkt->stream_index); + if (pkt->duration < 0 && st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) { + av_log(s, AV_LOG_WARNING, "Packet with invalid duration %d in stream %d\n", + pkt->duration, pkt->stream_index); + pkt->duration = 0; + } + /* duration field */ if (pkt->duration == 0) { ff_compute_frame_duration(&num, &den, st, NULL, pkt); @@ -479,7 +502,9 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) /* update pts */ switch (st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: - frame_size = ff_get_audio_frame_size(st->codec, pkt->size, 1); + frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ? + ((AVFrame *)pkt->data)->nb_samples : + ff_get_audio_frame_size(st->codec, pkt->size, 1); /* HACK/FIXME, we skip the initial 0 size packets as they are most * likely equal to the encoder delay, but it would be better if we @@ -510,11 +535,21 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) { int ret, did_split; + if (s->output_ts_offset) { + AVStream *st = s->streams[pkt->stream_index]; + int64_t offset = av_rescale_q(s->output_ts_offset, AV_TIME_BASE_Q, st->time_base); + + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + } + if (s->avoid_negative_ts > 0) { AVStream *st = s->streams[pkt->stream_index]; int64_t offset = st->mux_ts_offset; - if (pkt->dts < 0 && pkt->dts != AV_NOPTS_VALUE && !s->offset) { + if ((pkt->dts < 0 || s->avoid_negative_ts == 2) && pkt->dts != AV_NOPTS_VALUE && !s->offset) { s->offset = -pkt->dts; s->offset_timebase = st->time_base; } @@ -536,7 +571,14 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } did_split = av_packet_split_side_data(pkt); - ret = s->oformat->write_packet(s, pkt); + if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { + AVFrame *frame = (AVFrame *)pkt->data; + av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); + ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0); + av_frame_free(&frame); + } else { + ret = s->oformat->write_packet(s, pkt); + } if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) avio_flush(s->pb); @@ -547,10 +589,33 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } +static int check_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (!pkt) + return 0; + + if (pkt->stream_index < 0 || pkt->stream_index >= s->nb_streams) { + av_log(s, AV_LOG_ERROR, "Invalid packet stream index: %d\n", + pkt->stream_index); + return AVERROR(EINVAL); + } + + if (s->streams[pkt->stream_index]->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) { + av_log(s, AV_LOG_ERROR, "Received a packet for an attachment stream.\n"); + return AVERROR(EINVAL); + } + + return 0; +} + int av_write_frame(AVFormatContext *s, AVPacket *pkt) { int ret; + ret = check_packet(s, pkt); + if (ret < 0) + return ret; + if (!pkt) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { ret = s->oformat->write_packet(s, NULL); @@ -585,6 +650,7 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, AVPacketList **next_point, *this_pktl; AVStream *st = s->streams[pkt->stream_index]; int chunked = s->max_chunk_size || s->max_chunk_duration; + int ret; this_pktl = av_mallocz(sizeof(AVPacketList)); if (!this_pktl) @@ -596,8 +662,17 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif pkt->buf = NULL; - av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-allocated memory - av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data + if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { + av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); + av_assert0(((AVFrame *)pkt->data)->buf); + } else { + // duplicate the packet if it uses non-allocated memory + if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) { + av_free(this_pktl); + return ret; + } + av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data + } if (s->streams[pkt->stream_index]->last_in_packet_buffer) { next_point = &(st->last_in_packet_buffer->next); @@ -677,7 +752,6 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, { AVPacketList *pktl; int stream_count = 0, noninterleaved_count = 0; - int64_t delta_dts_max = 0; int i, ret; if (pkt) { @@ -694,27 +768,38 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } - if (s->nb_streams == stream_count) { + if (s->internal->nb_interleaved_streams == stream_count) flush = 1; - } else if (!flush) { - for (i=0; i < s->nb_streams; i++) { - if (s->streams[i]->last_in_packet_buffer) { - int64_t delta_dts = - av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts, - s->streams[i]->time_base, - AV_TIME_BASE_Q) - - av_rescale_q(s->packet_buffer->pkt.dts, - s->streams[s->packet_buffer->pkt.stream_index]->time_base, - AV_TIME_BASE_Q); - delta_dts_max= FFMAX(delta_dts_max, delta_dts); - } + + if (s->max_interleave_delta > 0 && s->packet_buffer && !flush) { + AVPacket *top_pkt = &s->packet_buffer->pkt; + int64_t delta_dts = INT64_MIN; + int64_t top_dts = av_rescale_q(top_pkt->dts, + s->streams[top_pkt->stream_index]->time_base, + AV_TIME_BASE_Q); + + for (i = 0; i < s->nb_streams; i++) { + int64_t last_dts; + const AVPacketList *last = s->streams[i]->last_in_packet_buffer; + + if (!last) + continue; + + last_dts = av_rescale_q(last->pkt.dts, + s->streams[i]->time_base, + AV_TIME_BASE_Q); + delta_dts = FFMAX(delta_dts, last_dts - top_dts); } - if (s->nb_streams == stream_count+noninterleaved_count && - delta_dts_max > 20*AV_TIME_BASE) { - av_log(s, AV_LOG_DEBUG, "flushing with %d noninterleaved\n", noninterleaved_count); + + if (delta_dts > s->max_interleave_delta) { + av_log(s, AV_LOG_DEBUG, + "Delay between the first packet and last packet in the " + "muxing queue is %"PRId64" > %"PRId64": forcing output\n", + delta_dts, s->max_interleave_delta); flush = 1; } } + if (stream_count && flush) { AVStream *st; pktl = s->packet_buffer; @@ -760,20 +845,22 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) { int ret, flush = 0; + ret = check_packet(s, pkt); + if (ret < 0) + goto fail; + if (pkt) { AVStream *st = s->streams[pkt->stream_index]; - //FIXME/XXX/HACK drop zero sized packets - if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->size == 0) - return 0; - av_dlog(s, "av_interleaved_write_frame size:%d dts:%s pts:%s\n", pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts)); if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - return ret; + goto fail; - if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - return AVERROR(EINVAL); + if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { + ret = AVERROR(EINVAL); + goto fail; + } } else { av_dlog(s, "av_interleaved_write_frame FLUSH\n"); flush = 1; @@ -782,6 +869,11 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) for (;; ) { AVPacket opkt; int ret = interleave_packet(s, &opkt, pkt, flush); + if (pkt) { + memset(pkt, 0, sizeof(*pkt)); + av_init_packet(pkt); + pkt = NULL; + } if (ret <= 0) //FIXME cleanup needed for ret<0 ? return ret; @@ -790,13 +882,15 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) s->streams[opkt.stream_index]->nb_frames++; av_free_packet(&opkt); - pkt = NULL; if (ret < 0) return ret; if(s->pb && s->pb->error) return s->pb->error; } +fail: + av_packet_unref(pkt); + return ret; } int av_write_trailer(AVFormatContext *s) @@ -871,3 +965,51 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, dst->streams[dst_stream]->time_base); return av_write_frame(dst, &local_pkt); } + +static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index, + AVFrame *frame, int interleaved) +{ + AVPacket pkt, *pktp; + + av_assert0(s->oformat); + if (!s->oformat->write_uncoded_frame) + return AVERROR(ENOSYS); + + if (!frame) { + pktp = NULL; + } else { + pktp = &pkt; + av_init_packet(&pkt); + pkt.data = (void *)frame; + pkt.size = UNCODED_FRAME_PACKET_SIZE; + pkt.pts = + pkt.dts = frame->pts; + pkt.duration = av_frame_get_pkt_duration(frame); + pkt.stream_index = stream_index; + pkt.flags |= AV_PKT_FLAG_UNCODED_FRAME; + } + + return interleaved ? av_interleaved_write_frame(s, pktp) : + av_write_frame(s, pktp); +} + +int av_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame) +{ + return av_write_uncoded_frame_internal(s, stream_index, frame, 0); +} + +int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame) +{ + return av_write_uncoded_frame_internal(s, stream_index, frame, 1); +} + +int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index) +{ + av_assert0(s->oformat); + if (!s->oformat->write_uncoded_frame) + return AVERROR(ENOSYS); + return s->oformat->write_uncoded_frame(s, stream_index, NULL, + AV_WRITE_UNCODED_FRAME_QUERY); +} diff --git a/chromium/third_party/ffmpeg/libavformat/mvdec.c b/chromium/third_party/ffmpeg/libavformat/mvdec.c index 5525233db56..6e7c3ffd113 100644 --- a/chromium/third_party/ffmpeg/libavformat/mvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mvdec.c @@ -24,48 +24,55 @@ * Silicon Graphics Movie demuxer */ +#include "libavutil/channel_layout.h" #include "libavutil/eval.h" #include "libavutil/intreadwrite.h" #include "libavutil/rational.h" + #include "avformat.h" #include "internal.h" -typedef struct { +typedef struct MvContext { int nb_video_tracks; int nb_audio_tracks; - int eof_count; /**< number of streams that have finished */ - int stream_index; /**< current stream index */ - int frame[2]; /**< frame nb for current stream */ + int eof_count; ///< number of streams that have finished + int stream_index; ///< current stream index + int frame[2]; ///< frame nb for current stream + + int acompression; ///< compression level for audio stream + int aformat; ///< audio format } MvContext; #define AUDIO_FORMAT_SIGNED 401 static int mv_probe(AVProbeData *p) { - if (AV_RB32(p->buf) == MKBETAG('M','O','V','I') && AV_RB16(p->buf + 4) < 3) + if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') && + AV_RB16(p->buf + 4) < 3) return AVPROBE_SCORE_MAX; return 0; } -static char * var_read_string(AVIOContext *pb, int size) +static char *var_read_string(AVIOContext *pb, int size) { - char *str = av_malloc(size + 1); int n; + char *str = av_malloc(size + 1); if (!str) return NULL; n = avio_get_str(pb, size, str, size + 1); if (n < size) - avio_skip(pb, size - n); + avio_skip(pb, size - n); return str; } static int var_read_int(AVIOContext *pb, int size) { int v; - char * s = var_read_string(pb, size); - if (!s || sscanf(s, "%d", &v) != 1) - v = 0; + char *s = var_read_string(pb, size); + if (!s) + return 0; + v = strtol(s, NULL, 10); av_free(s); return v; } @@ -73,9 +80,9 @@ static int var_read_int(AVIOContext *pb, int size) static AVRational var_read_float(AVIOContext *pb, int size) { AVRational v; - char * s = var_read_string(pb, size); + char *s = var_read_string(pb, size); if (!s) - return (AVRational){0, 0}; + return (AVRational) { 0, 0 }; v = av_d2q(av_strtod(s, NULL), INT_MAX); av_free(s); return v; @@ -88,13 +95,15 @@ static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size) av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL); } -static int set_channels(AVFormatContext *avctx, AVStream *st, int channels) { +static int set_channels(AVFormatContext *avctx, AVStream *st, int channels) +{ if (channels <= 0) { - av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid\n", channels); + av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid.\n", channels); return AVERROR_INVALIDDATA; } - st->codec->channels = channels; - st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; + st->codec->channels = channels; + st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO + : AV_CH_LAYOUT_STEREO; return 0; } @@ -102,7 +111,8 @@ static int set_channels(AVFormatContext *avctx, AVStream *st, int channels) { * Parse global variable * @return < 0 if unknown */ -static int parse_global_var(AVFormatContext *avctx, AVStream *st, const char *name, int size) +static int parse_global_var(AVFormatContext *avctx, AVStream *st, + const char *name, int size) { MvContext *mv = avctx->priv_data; AVIOContext *pb = avctx->pb; @@ -112,10 +122,11 @@ static int parse_global_var(AVFormatContext *avctx, AVStream *st, const char *na mv->nb_audio_tracks = var_read_int(pb, size); } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) { var_read_metadata(avctx, name, size); - } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") || !strcmp(name, "OPTIMIZED")) { + } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") || + !strcmp(name, "OPTIMIZED")) { avio_skip(pb, size); // ignore } else - return -1; + return AVERROR_INVALIDDATA; return 0; } @@ -124,15 +135,17 @@ static int parse_global_var(AVFormatContext *avctx, AVStream *st, const char *na * Parse audio variable * @return < 0 if unknown */ -static int parse_audio_var(AVFormatContext *avctx, AVStream *st, const char *name, int size) +static int parse_audio_var(AVFormatContext *avctx, AVStream *st, + const char *name, int size) { + MvContext *mv = avctx->priv_data; AVIOContext *pb = avctx->pb; if (!strcmp(name, "__DIR_COUNT")) { st->nb_frames = var_read_int(pb, size); } else if (!strcmp(name, "AUDIO_FORMAT")) { - st->codec->codec_id = var_read_int(pb, size); + mv->aformat = var_read_int(pb, size); } else if (!strcmp(name, "COMPRESSION")) { - st->codec->codec_tag = var_read_int(pb, size); + mv->acompression = var_read_int(pb, size); } else if (!strcmp(name, "DEFAULT_VOL")) { var_read_metadata(avctx, name, size); } else if (!strcmp(name, "NUM_CHANNELS")) { @@ -143,7 +156,8 @@ static int parse_audio_var(AVFormatContext *avctx, AVStream *st, const char *nam } else if (!strcmp(name, "SAMPLE_WIDTH")) { st->codec->bits_per_coded_sample = var_read_int(pb, size) * 8; } else - return -1; + return AVERROR_INVALIDDATA; + return 0; } @@ -151,13 +165,14 @@ static int parse_audio_var(AVFormatContext *avctx, AVStream *st, const char *nam * Parse video variable * @return < 0 if unknown */ -static int parse_video_var(AVFormatContext *avctx, AVStream *st, const char *name, int size) +static int parse_video_var(AVFormatContext *avctx, AVStream *st, + const char *name, int size) { AVIOContext *pb = avctx->pb; if (!strcmp(name, "__DIR_COUNT")) { st->nb_frames = st->duration = var_read_int(pb, size); } else if (!strcmp(name, "COMPRESSION")) { - char * str = var_read_string(pb, size); + char *str = var_read_string(pb, size); if (!str) return AVERROR_INVALIDDATA; if (!strcmp(str, "1")) { @@ -172,35 +187,40 @@ static int parse_video_var(AVFormatContext *avctx, AVStream *st, const char *nam } else if (!strcmp(str, "MVC2")) { st->codec->codec_id = AV_CODEC_ID_MVC2; } else { - avpriv_request_sample(avctx, "video compression %s", str); + avpriv_request_sample(avctx, "Video compression %s", str); } av_free(str); } else if (!strcmp(name, "FPS")) { AVRational fps = var_read_float(pb, size); avpriv_set_pts_info(st, 64, fps.den, fps.num); + st->avg_frame_rate = fps; } else if (!strcmp(name, "HEIGHT")) { st->codec->height = var_read_int(pb, size); } else if (!strcmp(name, "PIXEL_ASPECT")) { st->sample_aspect_ratio = var_read_float(pb, size); av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, - st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, INT_MAX); + st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, + INT_MAX); } else if (!strcmp(name, "WIDTH")) { st->codec->width = var_read_int(pb, size); } else if (!strcmp(name, "ORIENTATION")) { if (var_read_int(pb, size) == 1101) { - st->codec->extradata = av_strdup("BottomUp"); - st->codec->extradata_size = 9; + st->codec->extradata = av_strdup("BottomUp"); + st->codec->extradata_size = 9; } } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) { var_read_metadata(avctx, name, size); } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) { avio_skip(pb, size); // ignore } else - return -1; + return AVERROR_INVALIDDATA; + return 0; } -static void read_table(AVFormatContext *avctx, AVStream *st, int (*parse)(AVFormatContext *avctx, AVStream *st, const char *name, int size)) +static void read_table(AVFormatContext *avctx, AVStream *st, + int (*parse)(AVFormatContext *avctx, AVStream *st, + const char *name, int size)) { int count, i; AVIOContext *pb = avctx->pb; @@ -214,7 +234,7 @@ static void read_table(AVFormatContext *avctx, AVStream *st, int (*parse)(AVForm name[sizeof(name) - 1] = 0; size = avio_rb32(pb); if (parse(avctx, st, name, size) < 0) { - avpriv_request_sample(avctx, "variable %s", name); + avpriv_request_sample(avctx, "Variable %s", name); avio_skip(pb, size); } } @@ -253,7 +273,7 @@ static int mv_read_header(AVFormatContext *avctx) avio_skip(pb, 22); /* allocate audio track first to prevent unnecessary seeking - (audio packet always precede video packet for a given frame) */ + * (audio packet always precede video packet for a given frame) */ ast = avformat_new_stream(avctx, NULL); if (!ast) return AVERROR(ENOMEM); @@ -261,9 +281,10 @@ static int mv_read_header(AVFormatContext *avctx) vst = avformat_new_stream(avctx, NULL); if (!vst) return AVERROR(ENOMEM); - vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; avpriv_set_pts_info(vst, 64, 1, 15); - vst->nb_frames = avio_rb32(pb); + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + vst->avg_frame_rate = av_inv_q(vst->time_base); + vst->nb_frames = avio_rb32(pb); v = avio_rb32(pb); switch (v) { case 1: @@ -274,7 +295,7 @@ static int mv_read_header(AVFormatContext *avctx) vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO; break; default: - avpriv_request_sample(avctx, "video compression %i", v); + avpriv_request_sample(avctx, "Video compression %i", v); break; } vst->codec->codec_tag = 0; @@ -282,9 +303,9 @@ static int mv_read_header(AVFormatContext *avctx) vst->codec->height = avio_rb32(pb); avio_skip(pb, 12); - ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->nb_frames = vst->nb_frames; - ast->codec->sample_rate = avio_rb32(pb); + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + ast->nb_frames = vst->nb_frames; + ast->codec->sample_rate = avio_rb32(pb); avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate); if (set_channels(avctx, ast, avio_rb32(pb)) < 0) return AVERROR_INVALIDDATA; @@ -293,7 +314,7 @@ static int mv_read_header(AVFormatContext *avctx) if (v == AUDIO_FORMAT_SIGNED) { ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE; } else { - avpriv_request_sample(avctx, "audio compression (format %i)", v); + avpriv_request_sample(avctx, "Audio compression (format %i)", v); } avio_skip(pb, 12); @@ -307,8 +328,8 @@ static int mv_read_header(AVFormatContext *avctx) uint32_t asize = avio_rb32(pb); uint32_t vsize = avio_rb32(pb); 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); + 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->codec->channels * 2); } } else if (!version && avio_rb16(pb) == 3) { @@ -317,31 +338,33 @@ static int mv_read_header(AVFormatContext *avctx) read_table(avctx, NULL, parse_global_var); if (mv->nb_audio_tracks > 1) { - avpriv_request_sample(avctx, "multiple audio streams support"); + avpriv_request_sample(avctx, "Multiple audio streams support"); return AVERROR_PATCHWELCOME; } else if (mv->nb_audio_tracks) { ast = avformat_new_stream(avctx, NULL); if (!ast) return AVERROR(ENOMEM); ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - /* temporarily store compression value in codec_tag; format value in codec_id */ read_table(avctx, ast, parse_audio_var); - if (ast->codec->codec_tag == 100 && ast->codec->codec_id == AUDIO_FORMAT_SIGNED && ast->codec->bits_per_coded_sample == 16) { + if (mv->acompression == 100 && + mv->aformat == AUDIO_FORMAT_SIGNED && + ast->codec->bits_per_coded_sample == 16) { ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE; } else { - avpriv_request_sample(avctx, "audio compression %i (format %i, width %i)", - ast->codec->codec_tag, ast->codec->codec_id, ast->codec->bits_per_coded_sample); + avpriv_request_sample(avctx, + "Audio compression %i (format %i, sr %i)", + mv->acompression, mv->aformat, + ast->codec->bits_per_coded_sample); ast->codec->codec_id = AV_CODEC_ID_NONE; } - ast->codec->codec_tag = 0; if (ast->codec->channels <= 0) { - av_log(avctx, AV_LOG_ERROR, "No valid channel count found\n"); + av_log(avctx, AV_LOG_ERROR, "No valid channel count found.\n"); return AVERROR_INVALIDDATA; } } if (mv->nb_video_tracks > 1) { - avpriv_request_sample(avctx, "multiple video streams support"); + avpriv_request_sample(avctx, "Multiple video streams support"); return AVERROR_PATCHWELCOME; } else if (mv->nb_video_tracks) { vst = avformat_new_stream(avctx, NULL); @@ -357,7 +380,7 @@ static int mv_read_header(AVFormatContext *avctx) if (mv->nb_video_tracks) read_index(pb, vst); } else { - avpriv_request_sample(avctx, "version %i", version); + avpriv_request_sample(avctx, "Version %i", version); return AVERROR_PATCHWELCOME; } @@ -374,9 +397,9 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt) int ret; uint64_t pos; - if (frame < st->nb_index_entries) { + if (frame < st->nb_index_entries) { index = &st->index_entries[frame]; - pos = avio_tell(pb); + pos = avio_tell(pb); if (index->pos > pos) avio_skip(pb, index->pos - pos); else if (index->pos < pos) { @@ -391,8 +414,8 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt) return ret; pkt->stream_index = mv->stream_index; - pkt->pts = index->timestamp; - pkt->flags |= AV_PKT_FLAG_KEY; + pkt->pts = index->timestamp; + pkt->flags |= AV_PKT_FLAG_KEY; mv->frame[mv->stream_index]++; mv->eof_count = 0; @@ -400,6 +423,9 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt) mv->eof_count++; if (mv->eof_count >= avctx->nb_streams) return AVERROR_EOF; + + // avoid returning 0 without a packet + return AVERROR(EAGAIN); } mv->stream_index++; @@ -409,7 +435,8 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt) return 0; } -static int mv_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags) +static int mv_read_seek(AVFormatContext *avctx, int stream_index, + int64_t timestamp, int flags) { MvContext *mv = avctx->priv_data; AVStream *st = avctx->streams[stream_index]; @@ -423,7 +450,7 @@ static int mv_read_seek(AVFormatContext *avctx, int stream_index, int64_t timest frame = av_index_search_timestamp(st, timestamp, flags); if (frame < 0) - return -1; + return AVERROR_INVALIDDATA; for (i = 0; i < avctx->nb_streams; i++) mv->frame[i] = frame; diff --git a/chromium/third_party/ffmpeg/libavformat/mvi.c b/chromium/third_party/ffmpeg/libavformat/mvi.c index 5efc4431524..a7cfcb9a7a5 100644 --- a/chromium/third_party/ffmpeg/libavformat/mvi.c +++ b/chromium/third_party/ffmpeg/libavformat/mvi.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/channel_layout.h" #include "avformat.h" #include "internal.h" @@ -95,7 +97,8 @@ static int read_header(AVFormatContext *s) mvi->audio_frame_size = ((uint64_t)mvi->audio_data_size << MVI_FRAC_BITS) / frames_count; if (mvi->audio_frame_size <= 1 << MVI_FRAC_BITS - 1) { - av_log(s, AV_LOG_ERROR, "Invalid audio_data_size (%d) or frames_count (%d)\n", + av_log(s, AV_LOG_ERROR, + "Invalid audio_data_size (%"PRIu32") or frames_count (%u)\n", mvi->audio_data_size, frames_count); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.c b/chromium/third_party/ffmpeg/libavformat/mxf.c index 4a4158a1d33..d20ed946ac6 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.c +++ b/chromium/third_party/ffmpeg/libavformat/mxf.c @@ -45,6 +45,7 @@ const MXFCodecUL ff_mxf_codec_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x71,0x00,0x00,0x00 }, 13, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x03,0x02,0x00,0x00 }, 14, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC SPS/PPS in-band */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x01 }, 16, AV_CODEC_ID_V210 }, /* V210 */ /* SoundEssenceCompression */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, 13, AV_CODEC_ID_PCM_S16LE }, /* Uncompressed */ @@ -107,7 +108,7 @@ int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat * return -1; } -static const MXFSamplesPerFrame mxf_samples_per_frames[] = { +static const MXFSamplesPerFrame mxf_spf[] = { { { 1001, 24000 }, { 2002, 0, 0, 0, 0, 0 } }, // FILM 23.976 { { 1, 24}, { 2000, 0, 0, 0, 0, 0 } }, // FILM 24 { { 1001, 30000 }, { 1602, 1601, 1602, 1601, 1602, 0 } }, // NTSC 29.97 @@ -116,22 +117,33 @@ static const MXFSamplesPerFrame mxf_samples_per_frames[] = { { { 1, 50 }, { 960, 0, 0, 0, 0, 0 } }, // PAL 50 }; -const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base) +static const AVRational mxf_time_base[] = { + { 1001, 24000 }, + { 1, 24}, + { 1001, 30000 }, + { 1001, 60000 }, + { 1, 25 }, + { 1, 50 }, + { 0, 0} +}; + +const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, + AVRational time_base) { - int i; - for (i = 0; i < FF_ARRAY_ELEMS(mxf_samples_per_frames); i++) { - if (!av_cmp_q(mxf_samples_per_frames[i].time_base, time_base)) - return &mxf_samples_per_frames[i]; - } + int idx = av_find_nearest_q_idx(time_base, mxf_time_base); + AVRational diff = av_sub_q(time_base, mxf_time_base[idx]); - // Find closest container time base for approximative codec time base like 1/29.97, 1/30, ... - for (i = 0; i < FF_ARRAY_ELEMS(mxf_samples_per_frames); i++) { - if (fabs(av_q2d(mxf_samples_per_frames[i].time_base) - av_q2d(time_base)) < 0.0001) { - av_log(s, AV_LOG_WARNING, "%d/%d input time base matched %d/%d container time base\n", - time_base.num, time_base.den, - mxf_samples_per_frames[i].time_base.num, mxf_samples_per_frames[i].time_base.den); - return &mxf_samples_per_frames[i]; - } - } - return NULL; + diff.num = abs(diff.num); + + if (av_cmp_q(diff, (AVRational){1, 1000}) >= 0) + return NULL; + + if (av_cmp_q(time_base, mxf_time_base[idx])) + av_log(s, AV_LOG_WARNING, + "%d/%d input time base matched %d/%d container time base\n", + time_base.num, time_base.den, + mxf_spf[idx].time_base.num, + mxf_spf[idx].time_base.den); + + return &mxf_spf[idx]; } diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.h b/chromium/third_party/ffmpeg/libavformat/mxf.h index 4c751e8eef8..cf7ec0bab59 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.h +++ b/chromium/third_party/ffmpeg/libavformat/mxf.h @@ -79,7 +79,32 @@ extern const MXFCodecUL ff_mxf_pixel_format_uls[]; int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt); const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base); -#define PRINT_KEY(pc, s, x) av_dlog(pc, "%s %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", s, \ - (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15]) +#ifdef DEBUG +#define PRINT_KEY(pc, s, x) \ + av_log(pc, AV_LOG_VERBOSE, \ + "%s " \ + "0x%02x,0x%02x,0x%02x,0x%02x," \ + "0x%02x,0x%02x,0x%02x,0x%02x," \ + "0x%02x,0x%02x,0x%02x,0x%02x," \ + "0x%02x,0x%02x,0x%02x,0x%02x ", \ + s, \ + (x)[0], (x)[1], (x)[2], (x)[3], \ + (x)[4], (x)[5], (x)[6], (x)[7], \ + (x)[8], (x)[9], (x)[10], (x)[11], \ + (x)[12], (x)[13], (x)[14], (x)[15]); \ + av_log(pc, AV_LOG_INFO, \ + "%s " \ + "%02x.%02x.%02x.%02x." \ + "%02x.%02x.%02x.%02x." \ + "%02x.%02x.%02x.%02x." \ + "%02x.%02x.%02x.%02x\n", \ + s, \ + (x)[0], (x)[1], (x)[2], (x)[3], \ + (x)[4], (x)[5], (x)[6], (x)[7], \ + (x)[8], (x)[9], (x)[10], (x)[11], \ + (x)[12], (x)[13], (x)[14], (x)[15]) +#else +#define PRINT_KEY(pc, s, x) +#endif #endif /* AVFORMAT_MXF_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/mxfdec.c b/chromium/third_party/ffmpeg/libavformat/mxfdec.c index 61c0cb2366b..0d17a029640 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfdec.c @@ -43,7 +43,7 @@ * Only tracks with associated descriptors will be decoded. "Highly Desirable" SMPTE 377M D.1 */ -#include <stdint.h> +#include <inttypes.h> #include "libavutil/aes.h" #include "libavutil/avassert.h" @@ -135,7 +135,7 @@ typedef struct { AVRational edit_rate; int intra_only; uint64_t sample_count; - int64_t original_duration; ///< duration before multiplying st->duration by SampleRate/EditRate + int64_t original_duration; /* st->duration in SampleRate/EditRate units */ } MXFTrack; typedef struct { @@ -148,9 +148,11 @@ typedef struct { int width; int height; /* Field height, not frame height */ int frame_layout; /* See MXFFrameLayout enum */ +#define MXF_TFF 1 +#define MXF_BFF 2 + int field_dominance; int channels; int bits_per_sample; - int field_dominance; unsigned int component_depth; unsigned int horiz_subsampling; unsigned int vert_subsampling; @@ -252,13 +254,13 @@ static int mxf_read_close(AVFormatContext *s); static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 }; static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; static const uint8_t mxf_avid_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0e,0x04,0x03,0x01 }; -static const uint8_t mxf_system_item_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x03,0x01,0x04 }; +static const uint8_t mxf_system_item_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x03,0x01,0x04 }; static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; /* complete keys to match */ static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; -static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x11,0x01,0x00 }; +static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x11,0x01,0x00 }; static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -331,7 +333,7 @@ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, data_ptr = pkt->data; end_ptr = pkt->data + length; buf_ptr = pkt->data + 4; /* skip SMPTE 331M header */ - for (; buf_ptr + st->codec->channels*4 <= end_ptr; ) { + for (; end_ptr - buf_ptr >= st->codec->channels * 4; ) { for (i = 0; i < st->codec->channels; i++) { uint32_t sample = bytestream_get_le32(&buf_ptr); if (st->codec->bits_per_coded_sample == 24) @@ -487,9 +489,32 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size partition->index_sid = avio_rb32(pb); avio_skip(pb, 8); partition->body_sid = avio_rb32(pb); - avio_read(pb, op, sizeof(UID)); + if (avio_read(pb, op, sizeof(UID)) != sizeof(UID)) { + av_log(mxf->fc, AV_LOG_ERROR, "Failed reading UID\n"); + return AVERROR_INVALIDDATA; + } nb_essence_containers = avio_rb32(pb); + if (partition->this_partition && + partition->previous_partition == partition->this_partition) { + av_log(mxf->fc, AV_LOG_ERROR, + "PreviousPartition equal to ThisPartition %"PRIx64"\n", + partition->previous_partition); + /* override with the actual previous partition offset */ + if (!mxf->parsing_backward && mxf->last_forward_partition > 1) { + MXFPartition *prev = + mxf->partitions + mxf->last_forward_partition - 2; + partition->previous_partition = prev->this_partition; + } + /* if no previous body partition are found point to the header + * partition */ + if (partition->previous_partition == partition->this_partition) + partition->previous_partition = 0; + av_log(mxf->fc, AV_LOG_ERROR, + "Overriding PreviousPartition with %"PRIx64"\n", + partition->previous_partition); + } + /* some files don'thave FooterPartition set in every partition */ if (footer_partition) { if (mxf->footer_partition && mxf->footer_partition != footer_partition) { @@ -537,8 +562,10 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size /* only nag once */ if (!mxf->op) - av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %u ECs - assuming %s\n", - nb_essence_containers, op == OP1a ? "OP1a" : "OPAtom"); + av_log(mxf->fc, AV_LOG_WARNING, + "\"OPAtom\" with %"PRIu32" ECs - assuming %s\n", + nb_essence_containers, + op == OP1a ? "OP1a" : "OPAtom"); mxf->op = op; } else @@ -549,14 +576,15 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size } if (partition->kag_size <= 0 || partition->kag_size > (1 << 20)) { - av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", partition->kag_size); + av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %"PRId32" - guessing ", + partition->kag_size); if (mxf->op == OPSONYOpt) partition->kag_size = 512; else partition->kag_size = 1; - av_log(mxf->fc, AV_LOG_WARNING, "%i\n", partition->kag_size); + av_log(mxf->fc, AV_LOG_WARNING, "%"PRId32"\n", partition->kag_size); } return 0; @@ -666,7 +694,7 @@ static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid case 0x4804: avio_read(pb, track->track_number, 4); break; - case 0x4B01: + case 0x4b01: track->edit_rate.num = avio_rb32(pb); track->edit_rate.den = avio_rb32(pb); break; @@ -925,31 +953,31 @@ static void *mxf_resolve_strong_ref(MXFContext *mxf, UID *strong_ref, enum MXFMe static const MXFCodecUL mxf_picture_essence_container_uls[] = { // video essence container uls - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; /* EC ULs for intra-only formats */ static const MXFCodecUL mxf_intra_only_essence_container_uls[] = { - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x00,0x00 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MXF-GC SMPTE D-10 Mappings */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x00,0x00 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MXF-GC SMPTE D-10 Mappings */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; /* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */ static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = { - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; static const MXFCodecUL mxf_sound_essence_container_uls[] = { // sound essence container uls - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, AV_CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, AV_CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, AV_CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */ - { { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0xFF,0x4B,0x46,0x41,0x41,0x00,0x0D,0x4D,0x4F }, 14, AV_CODEC_ID_PCM_S16LE }, /* 0001GL00.MXF.A1.mxf_opatom.mxf */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, AV_CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, AV_CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, AV_CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */ + { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4F }, 14, AV_CODEC_ID_PCM_S16LE }, /* 0001GL00.MXF.A1.mxf_opatom.mxf */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; @@ -1246,7 +1274,9 @@ static int mxf_compute_index_tables(MXFContext *mxf) } } - if (!(mxf->index_tables = av_calloc(mxf->nb_index_tables, sizeof(MXFIndexTable)))) { + mxf->index_tables = av_mallocz_array(mxf->nb_index_tables, + sizeof(*mxf->index_tables)); + if (!mxf->index_tables) { av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; @@ -1265,8 +1295,12 @@ static int mxf_compute_index_tables(MXFContext *mxf) for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { MXFIndexTable *t = &mxf->index_tables[j]; - if (!(t->segments = av_calloc(t->nb_segments, sizeof(MXFIndexTableSegment*)))) { - av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment pointer array\n"); + t->segments = av_mallocz_array(t->nb_segments, + sizeof(*t->segments)); + + if (!t->segments) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment" + " pointer array\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; } @@ -1453,15 +1487,19 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (st->duration == -1) st->duration = AV_NOPTS_VALUE; st->start_time = component->start_position; - if (material_track->edit_rate.num <= 0 || material_track->edit_rate.den <= 0) { + if (material_track->edit_rate.num <= 0 || + material_track->edit_rate.den <= 0) { av_log(mxf->fc, AV_LOG_WARNING, - "invalid edit rate (%d/%d) found on stream #%d, defaulting to 25/1\n", - material_track->edit_rate.num, material_track->edit_rate.den, st->index); + "Invalid edit rate (%d/%d) found on stream #%d, " + "defaulting to 25/1\n", + material_track->edit_rate.num, + material_track->edit_rate.den, st->index); material_track->edit_rate = (AVRational){25, 1}; } avpriv_set_pts_info(st, 64, material_track->edit_rate.den, material_track->edit_rate.num); - /* ensure SourceTrack EditRate == MaterialTrack EditRate since only the former is accessible via st->priv_data */ + /* ensure SourceTrack EditRate == MaterialTrack EditRate since only + * the former is accessible via st->priv_data */ source_track->edit_rate = material_track->edit_rate; PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul); @@ -1543,7 +1581,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) case MixedFields: break; case SeparateFields: - st->codec->height *= 2; /* Turn field height into frame height. */ + switch (descriptor->field_dominance) { + case MXF_TFF: + st->codec->field_order = AV_FIELD_TT; + break; + case MXF_BFF: + st->codec->field_order = AV_FIELD_BB; + break; + default: + avpriv_request_sample(mxf->fc, + "Field dominance %d support", + descriptor->field_dominance); + break; + } + /* Turn field height into frame height. */ + st->codec->height *= 2; break; default: av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout); @@ -1587,7 +1639,9 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) /* if duration is set, rescale it from EditRate to SampleRate */ if (st->duration != AV_NOPTS_VALUE) - st->duration = av_rescale_q(st->duration, av_inv_q(material_track->edit_rate), st->time_base); + st->duration = av_rescale_q(st->duration, + av_inv_q(material_track->edit_rate), + st->time_base); /* TODO: implement AV_CODEC_ID_RAWAUDIO */ if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) { @@ -1632,7 +1686,7 @@ static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str) if (size < 0) return AVERROR(EINVAL); - buf_size = size + size/2 + 1; + buf_size = size + size / 2 + 1; *str = av_malloc(buf_size); if (!*str) return AVERROR(ENOMEM); @@ -1665,7 +1719,7 @@ static int mxf_uid_to_str(UID uid, char **str) static int mxf_timestamp_to_str(uint64_t timestamp, char **str) { - struct tm time = {0}; + struct tm time = { 0 }; time.tm_year = (timestamp >> 48) - 1900; time.tm_mon = (timestamp >> 40 & 0xFF) - 1; time.tm_mday = (timestamp >> 32 & 0xFF); @@ -1673,9 +1727,14 @@ static int mxf_timestamp_to_str(uint64_t timestamp, char **str) time.tm_min = (timestamp >> 16 & 0xFF); time.tm_sec = (timestamp >> 8 & 0xFF); - /* ensure month/day are valid */ - time.tm_mon = FFMAX(time.tm_mon, 0); - time.tm_mday = FFMAX(time.tm_mday, 1); + /* msvcrt versions of strftime calls the invalid parameter handler + * (aborting the process if one isn't set) if the parameters are out + * of range. */ + time.tm_mon = av_clip(time.tm_mon, 0, 11); + time.tm_mday = av_clip(time.tm_mday, 1, 31); + time.tm_hour = av_clip(time.tm_hour, 0, 23); + time.tm_min = av_clip(time.tm_min, 0, 59); + time.tm_sec = av_clip(time.tm_sec, 0, 59); *str = av_mallocz(32); if (!*str) @@ -1743,35 +1802,35 @@ static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag, } static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x02,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x03,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x04,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x01,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x02,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x03,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x02,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }, mxf_read_partition_pack }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x29,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* RGBA */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG 2 Video */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x02,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x03,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x04,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x01,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x02,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x03,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x02,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0f,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x29,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* RGBA */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG 2 Video */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, }; @@ -1860,10 +1919,14 @@ static int mxf_parse_handle_essence(MXFContext *mxf) if (mxf->parsing_backward) { return mxf_seek_to_previous_partition(mxf); - } else if (mxf->footer_partition || mxf->last_partition){ - uint64_t offset; + } else { + uint64_t offset = mxf->footer_partition ? mxf->footer_partition + : mxf->last_partition; - offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition; + if (!offset) { + av_dlog(mxf->fc, "no last partition\n"); + return 0; + } av_dlog(mxf->fc, "seeking to last partition\n"); @@ -1877,16 +1940,15 @@ static int mxf_parse_handle_essence(MXFContext *mxf) /* seek to last partition and parse backward */ if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) { - av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to last partition @ 0x%"PRIx64" (%"PRId64") - partial file?\n", + av_log(mxf->fc, AV_LOG_ERROR, + "failed to seek to last partition @ 0x%" PRIx64 + " (%"PRId64") - partial file?\n", mxf->run_in + offset, ret); return ret; } mxf->current_partition = NULL; mxf->parsing_backward = 1; - } else { - av_dlog(mxf->fc, "can't find last partition\n"); - return 0; } return 1; @@ -2011,6 +2073,8 @@ static int mxf_read_header(AVFormatContext *s) MXFContext *mxf = s->priv_data; KLVPacket klv; int64_t essence_offset = 0; + int64_t last_pos = -1; + uint64_t last_pos_index = 1; int ret; mxf->last_forward_tell = INT64_MAX; @@ -2028,7 +2092,12 @@ static int mxf_read_header(AVFormatContext *s) while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; - + if (avio_tell(s->pb) == last_pos) { + av_log(mxf->fc, AV_LOG_ERROR, "MXF structure loop detected\n"); + return AVERROR_INVALIDDATA; + } + if ((1ULL<<61) % last_pos_index++ == 0) + last_pos = avio_tell(s->pb); if (klv_read_packet(&klv, s->pb) < 0) { /* EOF - seek to previous partition or stop */ if(mxf_parse_handle_partition_or_eof(mxf) <= 0) @@ -2195,7 +2264,8 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset return next_ofs; } -static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, uint64_t *sample_count) +static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, + uint64_t *sample_count) { int i, total = 0, size = 0; AVStream *st = mxf->fc->streams[stream_index]; @@ -2207,13 +2277,16 @@ static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, uint64_t if ((sample_rate.num / sample_rate.den) == 48000) spf = ff_mxf_get_samples_per_frame(mxf->fc, time_base); if (!spf) { - int remainder = (sample_rate.num * time_base.num) % (time_base.den * sample_rate.den); + int remainder = (sample_rate.num * time_base.num) % + (time_base.den * sample_rate.den); *sample_count = av_q2d(av_mul_q((AVRational){mxf->current_edit_unit, 1}, av_mul_q(sample_rate, time_base))); if (remainder) av_log(mxf->fc, AV_LOG_WARNING, - "seeking detected on stream #%d with time base (%d/%d) and sample rate (%d/%d), audio pts won't be accurate.\n", - stream_index, time_base.num, time_base.den, sample_rate.num, sample_rate.den); + "seeking detected on stream #%d with time base (%d/%d) and " + "sample rate (%d/%d), audio pts won't be accurate.\n", + stream_index, time_base.num, time_base.den, + sample_rate.num, sample_rate.den); return 0; } @@ -2232,15 +2305,19 @@ static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, uint64_t return 0; } -static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, AVPacket *pkt) +static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, + AVPacket *pkt) { MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data; + int64_t bits_per_sample = av_get_bits_per_sample(codec->codec_id); + pkt->pts = track->sample_count; + if ( codec->channels <= 0 - || av_get_bits_per_sample(codec->codec_id) <= 0 - || codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) < 8) + || bits_per_sample <= 0 + || codec->channels * (int64_t)bits_per_sample < 8) return AVERROR(EINVAL); - track->sample_count += pkt->size / (codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) / 8); + track->sample_count += pkt->size / (codec->channels * (int64_t)bits_per_sample / 8); return 0; } @@ -2248,16 +2325,16 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; MXFContext *mxf = s->priv_data; + int ret; - while (klv_read_packet(&klv, s->pb) == 0) { - int ret; + while ((ret = klv_read_packet(&klv, s->pb)) == 0) { PRINT_KEY(s, "read packet", klv.key); av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { ret = mxf_decrypt_triplet(s, pkt, &klv); if (ret < 0) { av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return AVERROR_INVALIDDATA; + return ret; } return 0; } @@ -2270,7 +2347,9 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) AVCodecContext *codec; if (index < 0) { - av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12)); + av_log(s, AV_LOG_ERROR, + "error getting stream index %"PRIu32"\n", + AV_RB32(klv.key + 12)); goto skip; } @@ -2296,9 +2375,11 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) /* check for 8 channels AES3 element */ if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { - if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) { + ret = mxf_get_d10_aes3_packet(s->pb, s->streams[index], + pkt, klv.length); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); - return AVERROR_INVALIDDATA; + return ret; } } else { ret = av_get_packet(s->pb, pkt, klv.length); @@ -2309,8 +2390,10 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) pkt->pos = klv.offset; codec = s->streams[index]->codec; + if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) { - /* mxf->current_edit_unit good - see if we have an index table to derive timestamps from */ + /* mxf->current_edit_unit good - see if we have an + * index table to derive timestamps from */ MXFIndexTable *t = &mxf->index_tables[0]; if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) { @@ -2322,7 +2405,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) pkt->pts = mxf->current_edit_unit; } } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) { - int ret = mxf_set_audio_pts(mxf, codec, pkt); + ret = mxf_set_audio_pts(mxf, codec, pkt); if (ret < 0) return ret; } @@ -2335,7 +2418,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) skip: avio_skip(s->pb, klv.length); } - return url_feof(s->pb) ? AVERROR_EOF : -1; + return url_feof(s->pb) ? AVERROR_EOF : ret; } static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -2487,13 +2570,13 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti MXFContext* mxf = s->priv_data; int64_t seekpos; int i, ret; - int64_t ret64; MXFIndexTable *t; MXFTrack *source_track = st->priv_data; /* if audio then truncate sample_time to EditRate */ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) - sample_time = av_rescale_q(sample_time, st->time_base, av_inv_q(source_track->edit_rate)); + sample_time = av_rescale_q(sample_time, st->time_base, + av_inv_q(source_track->edit_rate)); if (mxf->nb_index_tables <= 0) { if (!s->bit_rate) @@ -2502,8 +2585,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti sample_time = 0; seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); - if ((ret64 = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0) - return ret64; + seekpos = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); + if (seekpos < 0) + return seekpos; + ff_update_cur_dts(s, st, sample_time); mxf->current_edit_unit = sample_time; } else { @@ -2523,7 +2608,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti sample_time = FFMIN(sample_time, source_track->original_duration - 1); } - if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) << 0) + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) < 0) return ret; ff_update_cur_dts(s, st, sample_time); diff --git a/chromium/third_party/ffmpeg/libavformat/mxfenc.c b/chromium/third_party/ffmpeg/libavformat/mxfenc.c index 5e77a3f0684..6f3226b968d 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mxfenc.c @@ -618,7 +618,7 @@ static void mxf_write_identification(AVFormatContext *s) mxf_write_metadata_key(pb, 0x013000); PRINT_KEY(s, "identification key", pb->buf_ptr - 16); - version = s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT ? + version = s->flags & AVFMT_FLAG_BITEXACT ? "0.0.0" : AV_STRINGIFY(LIBAVFORMAT_VERSION); length = 84 + (strlen(company)+strlen(product)+strlen(version))*2; // utf-16 klv_encode_ber_length(pb, length); @@ -1777,7 +1777,7 @@ static int mxf_write_header(AVFormatContext *s) mxf->essence_container_count = 1; } - if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) + if (!(s->flags & AVFMT_FLAG_BITEXACT)) mxf_gen_umid(s); for (i = 0; i < s->nb_streams; i++) { diff --git a/chromium/third_party/ffmpeg/libavformat/network.c b/chromium/third_party/ffmpeg/libavformat/network.c index 2ba435d4726..5e574e3bbe0 100644 --- a/chromium/third_party/ffmpeg/libavformat/network.c +++ b/chromium/third_party/ffmpeg/libavformat/network.c @@ -76,7 +76,7 @@ void ff_tls_init(void) #if HAVE_THREADS if (!CRYPTO_get_locking_callback()) { int i; - openssl_mutexes = av_malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); + openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); for (i = 0; i < CRYPTO_num_locks(); i++) pthread_mutex_init(&openssl_mutexes[i], NULL); CRYPTO_set_locking_callback(openssl_lock); @@ -281,7 +281,9 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, closesocket(fd); - ff_socket_nonblock(ret, 1); + if (ff_socket_nonblock(ret, 1) < 0) + av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); + return ret; } @@ -293,7 +295,8 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, int ret; socklen_t optlen; - ff_socket_nonblock(fd, 1); + if (ff_socket_nonblock(fd, 1) < 0) + av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); while ((ret = connect(fd, addr, addrlen))) { ret = ff_neterrno(); diff --git a/chromium/third_party/ffmpeg/libavformat/network.h b/chromium/third_party/ffmpeg/libavformat/network.h index c60e1424a1c..5ca906491ac 100644 --- a/chromium/third_party/ffmpeg/libavformat/network.h +++ b/chromium/third_party/ffmpeg/libavformat/network.h @@ -62,7 +62,7 @@ int ff_neterrno(void); #include <netdb.h> #define ff_neterrno() AVERROR(errno) -#endif +#endif /* HAVE_WINSOCK2_H */ #if HAVE_ARPA_INET_H #include <arpa/inet.h> @@ -104,12 +104,12 @@ struct sockaddr_storage { uint8_t ss_family; #else uint16_t ss_family; -#endif +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ char ss_pad1[6]; int64_t ss_align; char ss_pad2[112]; }; -#endif +#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ #if !HAVE_STRUCT_ADDRINFO struct addrinfo { @@ -122,7 +122,7 @@ struct addrinfo { char *ai_canonname; struct addrinfo *ai_next; }; -#endif +#endif /* !HAVE_STRUCT_ADDRINFO */ /* getaddrinfo constants */ #ifndef EAI_AGAIN @@ -195,12 +195,13 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen, #define getaddrinfo ff_getaddrinfo #define freeaddrinfo ff_freeaddrinfo #define getnameinfo ff_getnameinfo -#endif +#endif /* !HAVE_GETADDRINFO */ + #if !HAVE_GETADDRINFO || HAVE_WINSOCK2_H const char *ff_gai_strerror(int ecode); #undef gai_strerror #define gai_strerror ff_gai_strerror -#endif +#endif /* !HAVE_GETADDRINFO || HAVE_WINSOCK2_H */ #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 diff --git a/chromium/third_party/ffmpeg/libavformat/nistspheredec.c b/chromium/third_party/ffmpeg/libavformat/nistspheredec.c index c09df9ccc1a..2c966863422 100644 --- a/chromium/third_party/ffmpeg/libavformat/nistspheredec.c +++ b/chromium/third_party/ffmpeg/libavformat/nistspheredec.c @@ -36,7 +36,7 @@ static int nist_read_header(AVFormatContext *s) { char buffer[32], coding[32] = "pcm", format[32] = "01"; int bps = 0, be = 0; - int32_t header_size; + int32_t header_size = -1; AVStream *st; st = avformat_new_stream(s, NULL); @@ -108,8 +108,11 @@ static int nist_read_header(AVFormatContext *s) sscanf(buffer, "%*s %*s %"SCNd32, &st->codec->bits_per_coded_sample); } else { char key[32], value[32]; - sscanf(buffer, "%31s %*s %31s", key, value); - av_dict_set(&s->metadata, key, value, AV_DICT_APPEND); + if (sscanf(buffer, "%31s %*s %31s", key, value) == 3) { + av_dict_set(&s->metadata, key, value, AV_DICT_APPEND); + } else { + av_log(s, AV_LOG_ERROR, "Failed to parse '%s' as metadata\n", buffer); + } } } diff --git a/chromium/third_party/ffmpeg/libavformat/nut.c b/chromium/third_party/ffmpeg/libavformat/nut.c index 8b8a4cb8ac8..9224a963737 100644 --- a/chromium/third_party/ffmpeg/libavformat/nut.c +++ b/chromium/third_party/ffmpeg/libavformat/nut.c @@ -82,10 +82,10 @@ const AVCodecTag ff_nut_video_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 48 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'B', 'G', 'R') }, { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'R', 'A', 64 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'B', 'A', 64 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'R', 'A', 64 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'R', 'B', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 10 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '3', 'Y') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 10 ) }, @@ -157,10 +157,27 @@ const AVCodecTag ff_nut_video_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 16) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '3', 'G') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('X', 'Y', 'Z' , 36 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(36 , 'Z' , 'Y', 'X') }, + + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'B', 'G', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'B', 'G', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'G', 'B', 0xBA) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'R', 'G', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'R', 'G', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'G', 'R', 0xBA) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'B', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'B', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'B', 'G', 0xBA) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'R', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'R', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'R', 'G', 0xBA) }, + { AV_CODEC_ID_NONE, 0 } }; -static const AVCodecTag nut_audio_extra_tags[] = { +const AVCodecTag ff_nut_audio_extra_tags[] = { + { AV_CODEC_ID_COMFORT_NOISE, MKTAG('3', '3', '8', '9') }, { AV_CODEC_ID_PCM_ALAW, MKTAG('A', 'L', 'A', 'W') }, { AV_CODEC_ID_PCM_MULAW, MKTAG('U', 'L', 'A', 'W') }, { AV_CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') }, @@ -196,7 +213,7 @@ const AVCodecTag ff_nut_audio_tags[] = { const AVCodecTag * const ff_nut_codec_tags[] = { ff_nut_video_tags, ff_nut_audio_tags, ff_nut_subtitle_tags, - ff_codec_bmp_tags, ff_codec_wav_tags, nut_audio_extra_tags, ff_nut_data_tags, 0 + ff_codec_bmp_tags, ff_codec_wav_tags, ff_nut_audio_extra_tags, ff_nut_data_tags, 0 }; void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val) diff --git a/chromium/third_party/ffmpeg/libavformat/nut.h b/chromium/third_party/ffmpeg/libavformat/nut.h index da456ac5b08..a08d30b9350 100644 --- a/chromium/third_party/ffmpeg/libavformat/nut.h +++ b/chromium/third_party/ffmpeg/libavformat/nut.h @@ -46,6 +46,7 @@ typedef enum{ FLAG_SIZE_MSB = 32, ///<if set, data_size_msb is at frame header, otherwise data_size_msb is 0 FLAG_CHECKSUM = 64, ///<if set, the frame header contains a checksum FLAG_RESERVED = 128, ///<if set, reserved_count is coded in the frame header + FLAG_SM_DATA = 256, ///<if set, side / meta data is stored in the frame header. FLAG_HEADER_IDX =1024, ///<If set, header_idx is coded in the frame header. FLAG_MATCH_TIME =2048, ///<If set, match_time_delta is coded in the frame header FLAG_CODED =4096, ///<if set, coded_flags are stored in the frame header @@ -104,11 +105,14 @@ typedef struct NUTContext { int sp_count; int64_t max_pts; AVRational *max_pts_tb; + int version; + int minor_version; } NUTContext; extern const AVCodecTag ff_nut_subtitle_tags[]; extern const AVCodecTag ff_nut_video_tags[]; extern const AVCodecTag ff_nut_audio_tags[]; +extern const AVCodecTag ff_nut_audio_extra_tags[]; extern const AVCodecTag ff_nut_data_tags[]; extern const AVCodecTag * const ff_nut_codec_tags[]; diff --git a/chromium/third_party/ffmpeg/libavformat/nutdec.c b/chromium/third_party/ffmpeg/libavformat/nutdec.c index aa7ca676fb7..5d08a8e80b1 100644 --- a/chromium/third_party/ffmpeg/libavformat/nutdec.c +++ b/chromium/third_party/ffmpeg/libavformat/nutdec.c @@ -24,8 +24,10 @@ #include "libavutil/avassert.h" #include "libavutil/bswap.h" #include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/tree.h" +#include "libavcodec/bytestream.h" #include "avio_internal.h" #include "nut.h" #include "riff.h" @@ -227,11 +229,14 @@ static int decode_main_header(NUTContext *nut) end += avio_tell(bc); tmp = ffio_read_varlen(bc); - if (tmp < 2 && tmp > NUT_VERSION) { + if (tmp < 2 && tmp > 4) { av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n", tmp); return AVERROR(ENOSYS); } + nut->version = tmp; + if (nut->version > 3) + nut->minor_version = ffio_read_varlen(bc); GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS); @@ -385,6 +390,7 @@ static int decode_stream_header(NUTContext *nut) st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) { ff_nut_audio_tags, ff_codec_wav_tags, + ff_nut_audio_extra_tags, 0 }, tmp); @@ -415,9 +421,8 @@ static int decode_stream_header(NUTContext *nut) GET_V(st->codec->extradata_size, tmp < (1 << 30)); if (st->codec->extradata_size) { - if (ff_alloc_extradata(st->codec, st->codec->extradata_size)) + if (ff_get_extradata(st->codec, bc, st->codec->extradata_size) < 0) return AVERROR(ENOMEM); - avio_read(bc, st->codec->extradata, st->codec->extradata_size); } if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -774,6 +779,116 @@ static int nut_read_header(AVFormatContext *s) return 0; } +static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int is_meta, int64_t maxpos) +{ + int count = ffio_read_varlen(bc); + int skip_start = 0; + int skip_end = 0; + int channels = 0; + int64_t channel_layout = 0; + int sample_rate = 0; + int width = 0; + int height = 0; + int i; + + for (i=0; i<count; i++) { + uint8_t name[256], str_value[256], type_str[256]; + int value; + if (avio_tell(bc) >= maxpos) + return AVERROR_INVALIDDATA; + get_str(bc, name, sizeof(name)); + value = get_s(bc); + + if (value == -1) { + get_str(bc, str_value, sizeof(str_value)); + av_log(s, AV_LOG_WARNING, "Unknown string %s / %s\n", name, str_value); + } else if (value == -2) { + uint8_t *dst = NULL; + int64_t v64, value_len; + + get_str(bc, type_str, sizeof(type_str)); + value_len = ffio_read_varlen(bc); + if (avio_tell(bc) + value_len >= maxpos) + return AVERROR_INVALIDDATA; + if (!strcmp(name, "Palette")) { + dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, value_len); + } else if (!strcmp(name, "Extradata")) { + dst = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, value_len); + } else if (sscanf(name, "CodecSpecificSide%"SCNd64"", &v64) == 1) { + dst = av_packet_new_side_data(pkt, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, value_len + 8); + if(!dst) + return AVERROR(ENOMEM); + AV_WB64(dst, v64); + dst += 8; + } else if (!strcmp(name, "ChannelLayout") && value_len == 8) { + channel_layout = avio_rl64(bc); + continue; + } else { + av_log(s, AV_LOG_WARNING, "Unknown data %s / %s\n", name, type_str); + avio_skip(bc, value_len); + continue; + } + if(!dst) + return AVERROR(ENOMEM); + avio_read(bc, dst, value_len); + } else if (value == -3) { + value = get_s(bc); + } else if (value == -4) { + value = ffio_read_varlen(bc); + } else if (value < -4) { + get_s(bc); + } else { + if (!strcmp(name, "SkipStart")) { + skip_start = value; + } else if (!strcmp(name, "SkipEnd")) { + skip_end = value; + } else if (!strcmp(name, "Channels")) { + channels = value; + } else if (!strcmp(name, "SampleRate")) { + sample_rate = value; + } else if (!strcmp(name, "Width")) { + width = value; + } else if (!strcmp(name, "Height")) { + height = value; + } else { + av_log(s, AV_LOG_WARNING, "Unknown integer %s\n", name); + } + } + } + + if (channels || channel_layout || sample_rate || width || height) { + uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, 28); + if (!dst) + return AVERROR(ENOMEM); + bytestream_put_le32(&dst, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT*(!!channels) + + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT*(!!channel_layout) + + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE*(!!sample_rate) + + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS*(!!(width|height)) + ); + if (channels) + bytestream_put_le32(&dst, channels); + if (channel_layout) + bytestream_put_le64(&dst, channel_layout); + if (sample_rate) + bytestream_put_le32(&dst, sample_rate); + if (width || height){ + bytestream_put_le32(&dst, width); + bytestream_put_le32(&dst, height); + } + } + + if (skip_start || skip_end) { + uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!dst) + return AVERROR(ENOMEM); + AV_WL32(dst, skip_start); + AV_WL32(dst+4, skip_end); + } + + return 0; +} + static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, uint8_t *header_idx, int frame_code) { @@ -856,6 +971,7 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code) int64_t pts, last_IP_pts; StreamContext *stc; uint8_t header_idx; + int ret; size = decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code); if (size < 0) @@ -881,7 +997,23 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code) return AVERROR(ENOMEM); memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]); pkt->pos = avio_tell(bc); // FIXME - avio_read(bc, pkt->data + nut->header_len[header_idx], size); + if (stc->last_flags & FLAG_SM_DATA) { + int sm_size; + if (read_sm_data(s, bc, pkt, 0, pkt->pos + size) < 0) + return AVERROR_INVALIDDATA; + if (read_sm_data(s, bc, pkt, 1, pkt->pos + size) < 0) + return AVERROR_INVALIDDATA; + sm_size = avio_tell(bc) - pkt->pos; + size -= sm_size; + pkt->size -= sm_size; + } + + ret = avio_read(bc, pkt->data + nut->header_len[header_idx], size); + if (ret != size) { + if (ret < 0) + return ret; + } + av_shrink_packet(pkt, nut->header_len[header_idx] + ret); pkt->stream_index = stream_id; if (stc->last_flags & FLAG_KEY) diff --git a/chromium/third_party/ffmpeg/libavformat/nutenc.c b/chromium/third_party/ffmpeg/libavformat/nutenc.c index 10b8fc88eb7..604fe760b69 100644 --- a/chromium/third_party/ffmpeg/libavformat/nutenc.c +++ b/chromium/third_party/ffmpeg/libavformat/nutenc.c @@ -26,6 +26,7 @@ #include "libavutil/tree.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" +#include "libavcodec/bytestream.h" #include "libavcodec/mpegaudiodata.h" #include "nut.h" #include "internal.h" @@ -337,7 +338,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) tmp_head_idx; int64_t tmp_match; - ff_put_v(bc, NUT_VERSION); + ff_put_v(bc, nut->version = NUT_VERSION); + if (nut->version > 3) + ff_put_v(bc, nut->minor_version); ff_put_v(bc, nut->avf->nb_streams); ff_put_v(bc, nut->max_distance); ff_put_v(bc, nut->time_base_count); @@ -586,8 +589,15 @@ static int write_index(NUTContext *nut, AVIOContext *bc) { int64_t last_pts= -1; int j, k; for (j=0; j<nut->sp_count; j++) { - int flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count); + int flag; int n = 0; + + if (j && nus->keyframe_pts[j] == nus->keyframe_pts[j-1]) { + av_log(nut->avf, AV_LOG_WARNING, "Multiple keyframes with same PTS\n"); + nus->keyframe_pts[j] = AV_NOPTS_VALUE; + } + + flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count); for (; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++) n++; @@ -769,6 +779,8 @@ static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, flags |= FLAG_SIZE_MSB; if (pkt->pts - nus->last_pts != fc->pts_delta) flags |= FLAG_CODED_PTS; + if (pkt->side_data_elems && nut->version > 3) + flags |= FLAG_SM_DATA; if (pkt->size > 2 * nut->max_distance) flags |= FLAG_CHECKSUM; if (FFABS(pkt->pts - nus->last_pts) > nus->max_pts_distance) @@ -801,11 +813,129 @@ static int find_best_header_idx(NUTContext *nut, AVPacket *pkt) return best_i; } +static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int is_meta) +{ + AVStream *st = s->streams[pkt->stream_index]; + int ret, i, dyn_size; + unsigned flags; + AVIOContext *dyn_bc; + int sm_data_count = 0; + uint8_t tmp[256]; + uint8_t *dyn_buf; + + ret = avio_open_dyn_buf(&dyn_bc); + if (ret < 0) + return ret; + + for (i = 0; i<pkt->side_data_elems; i++) { + const uint8_t *data = pkt->side_data[i].data; + int size = pkt->side_data[i].size; + const uint8_t *data_end = data + size; + + if (is_meta) { + if ( pkt->side_data[i].type == AV_PKT_DATA_METADATA_UPDATE + || pkt->side_data[i].type == AV_PKT_DATA_STRINGS_METADATA) { + if (!size || data[size-1]) + return AVERROR(EINVAL); + while (data < data_end) { + const uint8_t *key = data; + const uint8_t *val = data + strlen(key) + 1; + + if(val >= data_end) + return AVERROR(EINVAL); + put_str(dyn_bc, key); + put_s(dyn_bc, -1); + put_str(dyn_bc, val); + data = val + strlen(val) + 1; + sm_data_count++; + } + } + } else { + switch (pkt->side_data[i].type) { + case AV_PKT_DATA_PALETTE: + case AV_PKT_DATA_NEW_EXTRADATA: + case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL: + default: + if (pkt->side_data[i].type == AV_PKT_DATA_PALETTE) { + put_str(dyn_bc, "Palette"); + } else if(pkt->side_data[i].type == AV_PKT_DATA_NEW_EXTRADATA) { + put_str(dyn_bc, "Extradata"); + } else if(pkt->side_data[i].type == AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL) { + snprintf(tmp, sizeof(tmp), "CodecSpecificSide%"PRId64"", AV_RB64(data)); + put_str(dyn_bc, tmp); + } else { + snprintf(tmp, sizeof(tmp), "UserData%s-SD-%d", + (st->codec->flags & CODEC_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT, + pkt->side_data[i].type); + put_str(dyn_bc, tmp); + } + put_s(dyn_bc, -2); + put_str(dyn_bc, "bin"); + ff_put_v(dyn_bc, pkt->side_data[i].size); + avio_write(dyn_bc, data, pkt->side_data[i].size); + sm_data_count++; + break; + case AV_PKT_DATA_PARAM_CHANGE: + flags = bytestream_get_le32(&data); + if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) { + put_str(dyn_bc, "Channels"); + put_s(dyn_bc, bytestream_get_le32(&data)); + sm_data_count++; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) { + put_str(dyn_bc, "ChannelLayout"); + put_s(dyn_bc, -2); + put_str(dyn_bc, "u64"); + ff_put_v(bc, 8); + avio_write(dyn_bc, data, 8); data+=8; + sm_data_count++; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) { + put_str(dyn_bc, "SampleRate"); + put_s(dyn_bc, bytestream_get_le32(&data)); + sm_data_count++; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) { + put_str(dyn_bc, "Width"); + put_s(dyn_bc, bytestream_get_le32(&data)); + put_str(dyn_bc, "Height"); + put_s(dyn_bc, bytestream_get_le32(&data)); + sm_data_count+=2; + } + break; + case AV_PKT_DATA_SKIP_SAMPLES: + if (AV_RL32(data)) { + put_str(dyn_bc, "SkipStart"); + put_s(dyn_bc, (unsigned)AV_RL32(data)); + sm_data_count++; + } + if (AV_RL32(data+4)) { + put_str(dyn_bc, "SkipEnd"); + put_s(dyn_bc, (unsigned)AV_RL32(data+4)); + sm_data_count++; + } + break; + case AV_PKT_DATA_METADATA_UPDATE: + case AV_PKT_DATA_STRINGS_METADATA: + // belongs into meta, not side data + break; + } + } + } + + ff_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); + + return 0; +} + static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) { NUTContext *nut = s->priv_data; StreamContext *nus = &nut->stream[pkt->stream_index]; - AVIOContext *bc = s->pb, *dyn_bc; + AVIOContext *bc = s->pb, *dyn_bc, *sm_bc = NULL; FrameCode *fc; int64_t coded_pts; int best_length, frame_code, flags, needed_flags, i, header_idx; @@ -813,6 +943,9 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) int key_frame = !!(pkt->flags & AV_PKT_FLAG_KEY); int store_sp = 0; int ret; + int sm_size = 0; + int data_size = pkt->size; + uint8_t *sm_buf; if (pkt->pts < 0) { av_log(s, AV_LOG_ERROR, @@ -821,13 +954,23 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EINVAL); } + if (pkt->side_data_elems && nut->version > 3) { + ret = avio_open_dyn_buf(&sm_bc); + if (ret < 0) + return ret; + write_sm_data(s, sm_bc, pkt, 0); + write_sm_data(s, sm_bc, pkt, 1); + sm_size = avio_close_dyn_buf(sm_bc, &sm_buf); + data_size += sm_size; + } + if (1LL << (20 + 3 * nut->header_count) <= avio_tell(bc)) write_headers(s, bc); if (key_frame && !(nus->last_flags & FLAG_KEY)) store_sp = 1; - if (pkt->size + 30 /*FIXME check*/ + avio_tell(bc) >= nut->last_syncpoint_pos + nut->max_distance) + if (data_size + 30 /*FIXME check*/ + avio_tell(bc) >= nut->last_syncpoint_pos + nut->max_distance) store_sp = 1; //FIXME: Ensure store_sp is 1 in the first place. @@ -907,10 +1050,10 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) if (flags & FLAG_STREAM_ID) length += ff_get_v_length(pkt->stream_index); - if (pkt->size % fc->size_mul != fc->size_lsb) + if (data_size % fc->size_mul != fc->size_lsb) continue; if (flags & FLAG_SIZE_MSB) - length += ff_get_v_length(pkt->size / fc->size_mul); + length += ff_get_v_length(data_size / fc->size_mul); if (flags & FLAG_CHECKSUM) length += 4; @@ -952,13 +1095,18 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) } 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, pkt->size / fc->size_mul); + 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_CHECKSUM) avio_wl32(bc, ffio_get_checksum(bc)); else ffio_get_checksum(bc); + if (flags & FLAG_SM_DATA) { + avio_write(bc, sm_buf, sm_size); + av_freep(&sm_buf); + } avio_write(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]); + nus->last_flags = flags; nus->last_pts = pkt->pts; diff --git a/chromium/third_party/ffmpeg/libavformat/nuv.c b/chromium/third_party/ffmpeg/libavformat/nuv.c index 32d0e02f68b..2c02de1c6f1 100644 --- a/chromium/third_party/ffmpeg/libavformat/nuv.c +++ b/chromium/third_party/ffmpeg/libavformat/nuv.c @@ -86,9 +86,8 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst, av_freep(&vst->codec->extradata); vst->codec->extradata_size = 0; } - if (ff_alloc_extradata(vst->codec, size)) + if (ff_get_extradata(vst->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, vst->codec->extradata, size); size = 0; if (!myth) return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/oggdec.c b/chromium/third_party/ffmpeg/libavformat/oggdec.c index 8639eaea8db..f7d00c1b4b1 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggdec.c +++ b/chromium/third_party/ffmpeg/libavformat/oggdec.c @@ -48,6 +48,7 @@ static const struct ogg_codec * const ogg_codecs[] = { &ff_flac_codec, &ff_celt_codec, &ff_opus_codec, + &ff_vp8_codec, &ff_old_dirac_codec, &ff_old_flac_codec, &ff_ogm_video_codec, @@ -77,6 +78,8 @@ static int ogg_save(AVFormatContext *s) struct ogg_stream *os = ogg->streams + i; os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE); memcpy(os->buf, ost->streams[i].buf, os->bufpos); + os->new_metadata = NULL; + os->new_metadata_size = 0; } ogg->state = ost; @@ -143,6 +146,8 @@ static int ogg_reset(AVFormatContext *s) os->lastpts = 0; } os->end_trimming = 0; + av_freep(&os->new_metadata); + os->new_metadata_size = 0; } ogg->page_pos = -1; @@ -640,7 +645,11 @@ static int ogg_read_close(AVFormatContext *s) ogg->streams[i].codec->cleanup(s, i); } av_freep(&ogg->streams[i].private); + av_freep(&ogg->streams[i].new_metadata); } + + ogg->nstreams = 0; + av_freep(&ogg->streams); return 0; } @@ -721,8 +730,16 @@ static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int p { struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; - if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) { - if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) { + int invalid = 0; + if (psize) { + switch (s->streams[idx]->codec->codec_id) { + case AV_CODEC_ID_THEORA: + invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40); + break; + case AV_CODEC_ID_VP8: + invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1); + } + if (invalid) { os->pflags ^= AV_PKT_FLAG_KEY; av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n", (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-"); @@ -779,16 +796,29 @@ retry: uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); - if(side_data == NULL) { - av_free_packet(pkt); - av_free(pkt); - return AVERROR(ENOMEM); - } + if(side_data == NULL) + goto fail; AV_WL32(side_data + 4, os->end_trimming); 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 == NULL) + goto fail; + + memcpy(side_data, os->new_metadata, os->new_metadata_size); + av_freep(&os->new_metadata); + os->new_metadata_size = 0; + } + return psize; +fail: + av_free_packet(pkt); + av_free(pkt); + return AVERROR(ENOMEM); } static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index, @@ -807,6 +837,11 @@ static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index, && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) { if (i == stream_index) { struct ogg_stream *os = ogg->streams + stream_index; + // Do not trust the last timestamps of a ogm video + if ( (os->flags & OGG_FLAG_EOS) + && !(os->flags & OGG_FLAG_BOS) + && os->codec == &ff_ogm_video_codec) + continue; pts = ogg_calc_pts(s, i, NULL); ogg_validate_keyframe(s, i, pstart, psize); if (os->pflags & AV_PKT_FLAG_KEY) { diff --git a/chromium/third_party/ffmpeg/libavformat/oggdec.h b/chromium/third_party/ffmpeg/libavformat/oggdec.h index c31859fecd7..231b5837704 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggdec.h +++ b/chromium/third_party/ffmpeg/libavformat/oggdec.h @@ -85,6 +85,8 @@ struct ogg_stream { 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 end_trimming; ///< set the number of packets to drop from the end + uint8_t *new_metadata; + unsigned int new_metadata_size; void *private; }; @@ -125,6 +127,7 @@ extern const struct ogg_codec ff_skeleton_codec; extern const struct ogg_codec ff_speex_codec; extern const struct ogg_codec ff_theora_codec; extern const struct ogg_codec ff_vorbis_codec; +extern const struct ogg_codec ff_vp8_codec; int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m, const uint8_t *buf, int size); diff --git a/chromium/third_party/ffmpeg/libavformat/oggenc.c b/chromium/third_party/ffmpeg/libavformat/oggenc.c index d9ef23c445c..375abadd445 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggenc.c +++ b/chromium/third_party/ffmpeg/libavformat/oggenc.c @@ -427,9 +427,12 @@ static int ogg_write_header(AVFormatContext *s) return -1; } oggstream = av_mallocz(sizeof(*oggstream)); + if (!oggstream) + return AVERROR(ENOMEM); + oggstream->page.stream_index = i; - if (!(st->codec->flags & CODEC_FLAG_BITEXACT)) + if (!(s->flags & AVFMT_FLAG_BITEXACT)) do { serial_num = av_get_random_seed(); for (j = 0; j < i; j++) { @@ -445,7 +448,7 @@ static int ogg_write_header(AVFormatContext *s) st->priv_data = oggstream; if (st->codec->codec_id == AV_CODEC_ID_FLAC) { int err = ogg_build_flac_headers(st->codec, oggstream, - st->codec->flags & CODEC_FLAG_BITEXACT, + s->flags & AVFMT_FLAG_BITEXACT, &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n"); @@ -454,7 +457,7 @@ static int ogg_write_header(AVFormatContext *s) } } else if (st->codec->codec_id == AV_CODEC_ID_SPEEX) { int err = ogg_build_speex_headers(st->codec, oggstream, - st->codec->flags & CODEC_FLAG_BITEXACT, + s->flags & AVFMT_FLAG_BITEXACT, &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n"); @@ -463,7 +466,7 @@ static int ogg_write_header(AVFormatContext *s) } } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) { int err = ogg_build_opus_headers(st->codec, oggstream, - st->codec->flags & CODEC_FLAG_BITEXACT, + s->flags & AVFMT_FLAG_BITEXACT, &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n"); @@ -484,7 +487,7 @@ static int ogg_write_header(AVFormatContext *s) return -1; } - p = ogg_write_vorbiscomment(7, st->codec->flags & CODEC_FLAG_BITEXACT, + p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT, &oggstream->header_len[1], &st->metadata, framing_bit); oggstream->header[1] = p; @@ -637,7 +640,8 @@ AVOutputFormat ff_ogg_muxer = { #endif , .priv_data_size = sizeof(OGGContext), - .audio_codec = AV_CODEC_ID_FLAC, + .audio_codec = CONFIG_LIBVORBIS_ENCODER ? + AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC, .video_codec = AV_CODEC_ID_THEORA, .write_header = ogg_write_header, .write_packet = ogg_write_packet, @@ -647,6 +651,30 @@ AVOutputFormat ff_ogg_muxer = { }; #endif +#if CONFIG_OGA_MUXER +static const AVClass oga_muxer_class = { + .class_name = "Ogg audio muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVOutputFormat ff_oga_muxer = { + .name = "oga", + .long_name = NULL_IF_CONFIG_SMALL("Ogg audio"), + .mime_type = "audio/ogg", + .extensions = "oga", + .priv_data_size = sizeof(OGGContext), + .audio_codec = AV_CODEC_ID_VORBIS, + .video_codec = AV_CODEC_ID_NONE, + .write_header = ogg_write_header, + .write_packet = ogg_write_packet, + .write_trailer = ogg_write_trailer, + .flags = AVFMT_TS_NEGATIVE, + .priv_class = &oga_muxer_class, +}; +#endif + #if CONFIG_SPEEX_MUXER static const AVClass speex_muxer_class = { .class_name = "Speex muxer", diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsecelt.c b/chromium/third_party/ffmpeg/libavformat/oggparsecelt.c index f3c2c1a632f..d6e99626509 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsecelt.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsecelt.c @@ -48,8 +48,10 @@ static int celt_header(AVFormatContext *s, int idx) priv = av_malloc(sizeof(struct oggcelt_private)); if (!priv) return AVERROR(ENOMEM); - if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0) + if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0) { + av_free(priv); return AVERROR(ENOMEM); + } version = AV_RL32(p + 28); /* unused header size field skipped */ sample_rate = AV_RL32(p + 36); diff --git a/chromium/third_party/ffmpeg/libavformat/oggparseogm.c b/chromium/third_party/ffmpeg/libavformat/oggparseogm.c index b8c502a5ffd..95369df89ea 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparseogm.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparseogm.c @@ -79,6 +79,11 @@ ogm_header(AVFormatContext *s, int idx) size = FFMIN(size, os->psize); time_unit = bytestream2_get_le64(&p); spu = bytestream2_get_le64(&p); + if (!time_unit || !spu) { + av_log(s, AV_LOG_ERROR, "Invalid timing values.\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skip(&p, 4); /* default_len */ bytestream2_skip(&p, 8); /* buffersize + bits_per_sample */ @@ -90,7 +95,7 @@ ogm_header(AVFormatContext *s, int idx) st->codec->channels = bytestream2_get_le16(&p); bytestream2_skip(&p, 2); /* block_align */ st->codec->bit_rate = bytestream2_get_le32(&p) * 8; - st->codec->sample_rate = time_unit ? spu * 10000000 / time_unit : 0; + st->codec->sample_rate = spu * 10000000 / time_unit; avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) { bytestream2_skip(&p, 4); @@ -126,15 +131,23 @@ ogm_dshow_header(AVFormatContext *s, int idx) if(*p != 1) return 1; + if (os->psize < 100) + return AVERROR_INVALIDDATA; t = AV_RL32(p + 96); if(t == 0x05589f80){ + if (os->psize < 184) + return AVERROR_INVALIDDATA; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68)); avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000); st->codec->width = AV_RL32(p + 176); st->codec->height = AV_RL32(p + 180); } else if(t == 0x05589f81){ + if (os->psize < 136) + return AVERROR_INVALIDDATA; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124)); st->codec->channels = AV_RL16(p + 126); diff --git a/chromium/third_party/ffmpeg/libavformat/oggparseopus.c b/chromium/third_party/ffmpeg/libavformat/oggparseopus.c index aafefbbe65b..75c611413ec 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparseopus.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparseopus.c @@ -32,6 +32,7 @@ struct oggopus_private { int64_t cur_dts; }; +#define OPUS_SEEK_PREROLL_MS 80 #define OPUS_HEAD_SIZE 19 static int opus_header(AVFormatContext *avf, int idx) @@ -66,6 +67,9 @@ static int opus_header(AVFormatContext *avf, int idx) memcpy(st->codec->extradata, packet, os->psize); st->codec->sample_rate = 48000; + av_codec_set_seek_preroll(st->codec, + av_rescale(OPUS_SEEK_PREROLL_MS, + st->codec->sample_rate, 1000)); avpriv_set_pts_info(st, 64, 1, 48000); priv->need_comments = 1; return 1; @@ -130,16 +134,13 @@ static int opus_packet(AVFormatContext *avf, int idx) duration += d; last_pkt = next_pkt = next_pkt + os->psize; for (; seg < os->nsegs; seg++) { - if (os->segments[seg] < 255) { - int d = opus_duration(last_pkt, os->segments[seg]); - if (d < 0) { - duration = os->granule; - break; - } - duration += d; - last_pkt = next_pkt + os->segments[seg]; - } next_pkt += os->segments[seg]; + if (os->segments[seg] < 255 && next_pkt != last_pkt) { + int d = opus_duration(last_pkt, next_pkt - last_pkt); + if (d > 0) + duration += d; + last_pkt = next_pkt; + } } os->lastpts = os->lastdts = os->granule - duration; diff --git a/chromium/third_party/ffmpeg/libavformat/oggparseskeleton.c b/chromium/third_party/ffmpeg/libavformat/oggparseskeleton.c index d94b0c2e07b..6c2105f324f 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparseskeleton.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparseskeleton.c @@ -34,7 +34,6 @@ static int skeleton_header(AVFormatContext *s, int idx) uint64_t start_granule; int target_idx, start_time; - strcpy(st->codec->codec_name, "skeleton"); st->codec->codec_type = AVMEDIA_TYPE_DATA; if ((os->flags & OGG_FLAG_EOS) && os->psize == 0) diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c b/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c index 6458b97bc0a..59df17efba1 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsetheora.c @@ -131,6 +131,8 @@ static int theora_header(AVFormatContext *s, int idx) st->codec->extradata_size = 0; return err; } + memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE); + cdp = st->codec->extradata + st->codec->extradata_size; *cdp++ = os->psize >> 8; *cdp++ = os->psize & 0xff; diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c index 36ad7384ea4..2d8cb15af9a 100644 --- a/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c +++ b/chromium/third_party/ffmpeg/libavformat/oggparsevorbis.c @@ -36,6 +36,7 @@ #include "internal.h" #include "oggdec.h" #include "vorbiscomment.h" +#include "replaygain.h" static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) { @@ -155,16 +156,21 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); continue; } - } else if (!ogm_chapter(as, tt, ct)) + } else if (!ogm_chapter(as, tt, ct)) { + if (av_dict_get(*m, tt, NULL, 0)) { + av_dict_set(m, tt, ";", AV_DICT_APPEND); + } av_dict_set(m, tt, ct, AV_DICT_DONT_STRDUP_KEY | - AV_DICT_DONT_STRDUP_VAL); + AV_DICT_APPEND); + av_freep(&ct); + } } } if (p != end) av_log(as, AV_LOG_INFO, - "%ti bytes of comment header remain\n", end - p); + "%"PTRDIFF_SPECIFIER" bytes of comment header remain\n", end - p); if (n > 0) av_log(as, AV_LOG_INFO, "truncated comment header, %i comments not found\n", n); @@ -237,6 +243,36 @@ static void vorbis_cleanup(AVFormatContext *s, int idx) av_freep(&priv->packet[i]); } +static int vorbis_update_metadata(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + AVStream *st = s->streams[idx]; + int ret; + + if (os->psize <= 8) + return 0; + + /* New metadata packet; release old data. */ + av_dict_free(&st->metadata); + ret = ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, + os->psize - 8); + if (ret < 0) + return ret; + + /* Update the metadata if possible. */ + av_freep(&os->new_metadata); + if (st->metadata) { + 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_size = 0; + } + + return ret; +} + static int vorbis_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; @@ -312,11 +348,15 @@ static int vorbis_header(AVFormatContext *s, int idx) avpriv_set_pts_info(st, 64, 1, srate); } } else if (os->buf[os->pstart] == 3) { - if (os->psize > 8 && - ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, - os->psize - 8) >= 0) { + if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) { + unsigned new_len; + + int ret = ff_replaygain_export(st, st->metadata); + if (ret < 0) + return ret; + // drop all metadata we parsed and which is not required by libvorbis - unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; + new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; if (new_len >= 16 && new_len < os->psize) { AV_WL32(priv->packet[1] + new_len - 5, 0); priv->packet[1][new_len - 1] = 1; @@ -345,13 +385,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; struct oggvorbis_private *priv = os->private; - int duration; + int duration, flags = 0; /* 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)) { + if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule>=0) { int seg, d; uint8_t *last_pkt = os->buf + os->pstart; uint8_t *next_pkt = last_pkt; @@ -359,19 +399,25 @@ static int vorbis_packet(AVFormatContext *s, int idx) avpriv_vorbis_parse_reset(&priv->vp); duration = 0; seg = os->segp; - d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); + d = avpriv_vorbis_parse_frame_flags(&priv->vp, last_pkt, 1, &flags); if (d < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } duration += d; last_pkt = next_pkt = next_pkt + os->psize; for (; seg < os->nsegs; seg++) { if (os->segments[seg] < 255) { - int d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); + int d = avpriv_vorbis_parse_frame_flags(&priv->vp, last_pkt, 1, &flags); if (d < 0) { duration = os->granule; break; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } duration += d; last_pkt = next_pkt + os->segments[seg]; @@ -380,9 +426,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) } os->lastpts = os->lastdts = os->granule - duration; + + if (!os->granule && duration) //hack to deal with broken files (Ticket3710) + os->lastpts = os->lastdts = AV_NOPTS_VALUE; + if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = FFMAX(os->lastpts, 0); - if (s->streams[idx]->duration) + if (s->streams[idx]->duration != AV_NOPTS_VALUE) s->streams[idx]->duration -= s->streams[idx]->start_time; } priv->final_pts = AV_NOPTS_VALUE; @@ -391,10 +441,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) /* parse packet duration */ if (os->psize > 0) { - duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1); + duration = avpriv_vorbis_parse_frame_flags(&priv->vp, os->buf + os->pstart, 1, &flags); if (duration < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } os->pduration = duration; } diff --git a/chromium/third_party/ffmpeg/libavformat/oggparsevp8.c b/chromium/third_party/ffmpeg/libavformat/oggparsevp8.c new file mode 100644 index 00000000000..89295c86a68 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/oggparsevp8.c @@ -0,0 +1,137 @@ +/* + * On2 VP8 parser for Ogg + * Copyright (C) 2013 James Almer + * + * 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/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "oggdec.h" + +#define VP8_HEADER_SIZE 26 + +static int vp8_header(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + uint8_t *p = os->buf + os->pstart; + AVStream *st = s->streams[idx]; + AVRational framerate; + + if (os->psize < 7 || p[0] != 0x4f) + return 0; + + switch (p[5]){ + case 0x01: + if (os->psize < VP8_HEADER_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid OggVP8 header packet"); + return AVERROR_INVALIDDATA; + } + + if (p[6] != 1) { + av_log(s, AV_LOG_WARNING, "Unknown OggVP8 version %d.%d\n", p[6], p[7]); + return AVERROR_INVALIDDATA; + } + + st->codec->width = AV_RB16(p + 8); + st->codec->height = AV_RB16(p + 10); + st->sample_aspect_ratio.num = AV_RB24(p + 12); + st->sample_aspect_ratio.den = AV_RB24(p + 15); + framerate.den = AV_RB32(p + 18); + framerate.num = AV_RB32(p + 22); + + avpriv_set_pts_info(st, 64, framerate.num, framerate.den); + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_VP8; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + break; + case 0x02: + if (p[6] != 0x20) + return AVERROR_INVALIDDATA; + ff_vorbis_comment(s, &st->metadata, p + 7, os->psize - 7); + break; + default: + av_log(s, AV_LOG_ERROR, "Unknown VP8 header type 0x%02X\n", p[5]); + return AVERROR_INVALIDDATA; + } + + return 1; +} + +static uint64_t vp8_gptopts(AVFormatContext *s, int idx, uint64_t granule, int64_t *dts) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + + uint64_t pts = (granule >> 32); + uint32_t dist = (granule >> 3) & 0x07ffffff; + + if (!dist) + os->pflags |= AV_PKT_FLAG_KEY; + + if (dts) + *dts = pts; + + return pts; +} + +static int vp8_packet(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + uint8_t *p = os->buf + os->pstart; + + if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { + int seg; + int duration; + uint8_t *last_pkt = p; + uint8_t *next_pkt; + + seg = os->segp; + duration = (last_pkt[0] >> 4) & 1; + next_pkt = last_pkt += os->psize; + for (; seg < os->nsegs; seg++) { + if (os->segments[seg] < 255) { + duration += (last_pkt[0] >> 4) & 1; + last_pkt = next_pkt + os->segments[seg]; + } + next_pkt += os->segments[seg]; + } + os->lastpts = os->lastdts = vp8_gptopts(s, idx, os->granule, NULL) - duration; + if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { + s->streams[idx]->start_time = os->lastpts; + if (s->streams[idx]->duration) + s->streams[idx]->duration -= s->streams[idx]->start_time; + } + } + + if (os->psize > 0) + os->pduration = (p[0] >> 4) & 1; + + return 0; +} + +const struct ogg_codec ff_vp8_codec = { + .magic = "OVP80", + .magicsize = 5, + .header = vp8_header, + .packet = vp8_packet, + .gptopts = vp8_gptopts, + .nb_header = 1, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/omadec.c b/chromium/third_party/ffmpeg/libavformat/omadec.c index 6a08076f473..9f3d3aa860f 100644 --- a/chromium/third_party/ffmpeg/libavformat/omadec.c +++ b/chromium/third_party/ffmpeg/libavformat/omadec.c @@ -37,8 +37,11 @@ * - Sound data organized in packets follow the EA3 header * (can be encrypted using the Sony DRM!). * + * Supported decoders: ATRAC3, ATRAC3+, MP3, LPCM */ +#include <inttypes.h> + #include "libavutil/channel_layout.h" #include "avformat.h" #include "internal.h" @@ -214,7 +217,7 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) if (geob->datasize < 64) { av_log(s, AV_LOG_ERROR, - "Invalid GEOB data size: %u\n", geob->datasize); + "Invalid GEOB data size: %"PRIu32"\n", geob->datasize); return AVERROR_INVALIDDATA; } @@ -238,7 +241,7 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) return AVERROR_INVALIDDATA; } oc->rid = AV_RB32(&gdata[OMA_ENC_HEADER_SIZE + 28]); - av_log(s, AV_LOG_DEBUG, "RID: %.8x\n", oc->rid); + av_log(s, AV_LOG_DEBUG, "RID: %.8"PRIx32"\n", oc->rid); memcpy(oc->iv, &header[0x58], 8); hex_log(s, AV_LOG_DEBUG, "IV", oc->iv, 8); @@ -292,7 +295,7 @@ static int oma_read_header(AVFormatContext *s) ID3v2ExtraMeta *extra_meta = NULL; OMAContext *oc = s->priv_data; - ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta); + ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0); ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); if (ret < EA3_HEADER_SIZE) return -1; @@ -365,7 +368,7 @@ static int oma_read_header(AVFormatContext *s) channel_id = (codec_params >> 10) & 7; if (!channel_id) { av_log(s, AV_LOG_ERROR, - "Invalid ATRAC-X channel id: %d\n", channel_id); + "Invalid ATRAC-X channel id: %"PRIu32"\n", channel_id); return AVERROR_INVALIDDATA; } st->codec->channel_layout = ff_oma_chid_to_native_layout[channel_id - 1]; @@ -379,7 +382,6 @@ static int oma_read_header(AVFormatContext *s) st->codec->sample_rate = samplerate; st->codec->bit_rate = samplerate * framesize * 8 / 2048; avpriv_set_pts_info(st, 64, 1, samplerate); - av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n"); break; case OMA_CODECID_MP3: st->need_parsing = AVSTREAM_PARSE_FULL_RAW; @@ -448,7 +450,7 @@ static int oma_read_probe(AVProbeData *p) /* This check cannot overflow as tag_len has at most 28 bits */ if (p->buf_size < tag_len + 5) /* EA3 header comes late, might be outside of the probe buffer */ - return tag_len ? AVPROBE_SCORE_EXTENSION : 0; + return tag_len ? AVPROBE_SCORE_EXTENSION/2 : 0; buf += tag_len; diff --git a/chromium/third_party/ffmpeg/libavformat/options.c b/chromium/third_party/ffmpeg/libavformat/options.c index 5218e5b92a4..e0d6df6fbde 100644 --- a/chromium/third_party/ffmpeg/libavformat/options.c +++ b/chromium/third_party/ffmpeg/libavformat/options.c @@ -19,6 +19,7 @@ */ #include "avformat.h" #include "avio_internal.h" +#include "internal.h" #include "libavutil/opt.h" /** @@ -109,6 +110,13 @@ AVFormatContext *avformat_alloc_context(void) ic = av_malloc(sizeof(AVFormatContext)); if (!ic) return ic; avformat_get_context_defaults(ic); + + ic->internal = av_mallocz(sizeof(*ic->internal)); + if (!ic->internal) { + avformat_free_context(ic); + return NULL; + } + return ic; } diff --git a/chromium/third_party/ffmpeg/libavformat/options_table.h b/chromium/third_party/ffmpeg/libavformat/options_table.h index 8145325c1c7..359b38483aa 100644 --- a/chromium/third_party/ffmpeg/libavformat/options_table.h +++ b/chromium/third_party/ffmpeg/libavformat/options_table.h @@ -50,6 +50,7 @@ static const AVOption avformat_options[] = { {"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D}, +{"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 5*AV_TIME_BASE }, 0, INT_MAX, D}, {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, @@ -57,6 +58,7 @@ static const AVOption avformat_options[] = { {"fdebug", "print specific debug info", OFFSET(debug), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, E|D, "fdebug"}, {"ts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_FDEBUG_TS }, INT_MIN, INT_MAX, E|D, "fdebug"}, {"max_delay", "maximum muxing or demuxing delay in microseconds", OFFSET(max_delay), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, E|D}, +{"start_time_realtime", "wall-clock time when stream begins (PTS==0)", OFFSET(start_time_realtime), AV_OPT_TYPE_INT64, {.i64 = AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX, E}, {"fpsprobesize", "number of frames used to probe fps", OFFSET(fps_probe_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX-1, D}, {"audio_preload", "microseconds by which audio packets should be interleaved earlier", OFFSET(audio_preload), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E}, {"chunk_duration", "microseconds for each chunk", OFFSET(max_chunk_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E}, @@ -69,14 +71,22 @@ static const AVOption avformat_options[] = { {"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, D, "err_detect"}, {"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, D, "err_detect"}, {"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, D, "err_detect"}, +{"ignore_err", "ignore errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_IGNORE_ERR }, INT_MIN, INT_MAX, D, "err_detect"}, {"careful", "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"}, {"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, D, "err_detect"}, {"aggressive", "consider things that a sane encoder shouldn't do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"}, {"use_wallclock_as_timestamps", "use wallclock as timestamps", OFFSET(use_wallclock_as_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D}, -{"avoid_negative_ts", "shift timestamps to make them non-negative. 1 enables, 0 disables, default of -1 enables when required by target format.", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E}, +{"avoid_negative_ts", "shift timestamps so they start at 0", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, E, "avoid_negative_ts"}, +{"auto", "enabled when required by target format", 0, AV_OPT_TYPE_CONST, {.i64 = -1 }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, +{"disabled", "do not change timestamps", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, +{"make_zero", "shift timestamps so they start at 0", 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, +{"make_non_negative", "shift timestamps so they are non negative", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, {"skip_initial_bytes", "set number of bytes to skip before reading header and frames", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D}, {"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D}, {"flush_packets", "enable flushing of the I/O context after each packet", OFFSET(flush_packets), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E}, +{"metadata_header_padding", "set number of bytes to be written as padding in a metadata header", OFFSET(metadata_header_padding), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, E}, +{"output_ts_offset", "set output timestamp offset", OFFSET(output_ts_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E}, +{"max_interleave_delta", "maximum buffering duration for interleaving", OFFSET(max_interleave_delta), AV_OPT_TYPE_INT64, { .i64 = 10000000 }, 0, INT64_MAX, E }, {NULL}, }; diff --git a/chromium/third_party/ffmpeg/libavformat/paf.c b/chromium/third_party/ffmpeg/libavformat/paf.c index 09aefe6770b..88a274fe156 100644 --- a/chromium/third_party/ffmpeg/libavformat/paf.c +++ b/chromium/third_party/ffmpeg/libavformat/paf.c @@ -44,13 +44,13 @@ typedef struct { uint32_t *blocks_offset_table; uint8_t *video_frame; - int video_size; + int video_size; uint8_t *audio_frame; uint8_t *temp_audio_frame; - int audio_size; + int audio_size; - int got_audio; + int got_audio; } PAFDemuxContext; static int read_probe(AVProbeData *p) @@ -87,10 +87,10 @@ static void read_table(AVFormatContext *s, uint32_t *table, uint32_t count) static int read_header(AVFormatContext *s) { - PAFDemuxContext *p = s->priv_data; + PAFDemuxContext *p = s->priv_data; AVIOContext *pb = s->pb; AVStream *ast, *vst; - int ret = 0; + int ret = 0; avio_skip(pb, 132); @@ -101,11 +101,13 @@ static int read_header(AVFormatContext *s) vst->start_time = 0; vst->nb_frames = vst->duration = - p->nb_frames = avio_rl32(pb); + p->nb_frames = avio_rl32(pb); avio_skip(pb, 4); + vst->codec->width = avio_rl32(pb); vst->codec->height = avio_rl32(pb); avio_skip(pb, 4); + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_tag = 0; vst->codec->codec_id = AV_CODEC_ID_PAF_VIDEO; @@ -115,13 +117,13 @@ static int read_header(AVFormatContext *s) if (!ast) return AVERROR(ENOMEM); - ast->start_time = 0; - ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->codec->codec_tag = 0; - ast->codec->codec_id = AV_CODEC_ID_PAF_AUDIO; - ast->codec->channels = 2; + ast->start_time = 0; + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + ast->codec->codec_tag = 0; + ast->codec->codec_id = AV_CODEC_ID_PAF_AUDIO; + ast->codec->channels = 2; ast->codec->channel_layout = AV_CH_LAYOUT_STEREO; - ast->codec->sample_rate = 22050; + ast->codec->sample_rate = 22050; avpriv_set_pts_info(ast, 64, 1, 22050); p->buffer_size = avio_rl32(pb); @@ -143,16 +145,19 @@ static int read_header(AVFormatContext *s) p->frame_blks > INT_MAX / sizeof(uint32_t)) return AVERROR_INVALIDDATA; - p->blocks_count_table = av_mallocz(p->nb_frames * sizeof(uint32_t)); - p->frames_offset_table = av_mallocz(p->nb_frames * sizeof(uint32_t)); - p->blocks_offset_table = av_mallocz(p->frame_blks * sizeof(uint32_t)); + p->blocks_count_table = av_mallocz(p->nb_frames * + sizeof(*p->blocks_count_table)); + p->frames_offset_table = av_mallocz(p->nb_frames * + sizeof(*p->frames_offset_table)); + p->blocks_offset_table = av_mallocz(p->frame_blks * + sizeof(*p->blocks_offset_table)); - p->video_size = p->max_video_blks * p->buffer_size; - p->video_frame = av_mallocz(p->video_size); + p->video_size = p->max_video_blks * p->buffer_size; + p->video_frame = av_mallocz(p->video_size); - p->audio_size = p->max_audio_blks * p->buffer_size; - p->audio_frame = av_mallocz(p->audio_size); - p->temp_audio_frame = av_mallocz(p->audio_size); + p->audio_size = p->max_audio_blks * p->buffer_size; + p->audio_frame = av_mallocz(p->audio_size); + p->temp_audio_frame = av_mallocz(p->audio_size); if (!p->blocks_count_table || !p->frames_offset_table || @@ -186,7 +191,7 @@ fail: static int read_packet(AVFormatContext *s, AVPacket *pkt) { - PAFDemuxContext *p = s->priv_data; + PAFDemuxContext *p = s->priv_data; AVIOContext *pb = s->pb; uint32_t count, offset; int size, i; @@ -209,7 +214,8 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return pkt->size; } - count = (p->current_frame == 0) ? p->preload_count : p->blocks_count_table[p->current_frame - 1]; + count = (p->current_frame == 0) ? p->preload_count + : p->blocks_count_table[p->current_frame - 1]; for (i = 0; i < count; i++) { if (p->current_frame_block >= p->frame_blks) return AVERROR_INVALIDDATA; @@ -245,7 +251,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) pkt->duration = 1; memcpy(pkt->data, p->video_frame + p->frames_offset_table[p->current_frame], size); if (pkt->data[0] & 0x20) - pkt->flags |= AV_PKT_FLAG_KEY; + pkt->flags |= AV_PKT_FLAG_KEY; p->current_frame++; return pkt->size; diff --git a/chromium/third_party/ffmpeg/libavformat/pcm.c b/chromium/third_party/ffmpeg/libavformat/pcm.c index 2fe44dcb407..a57a4b62493 100644 --- a/chromium/third_party/ffmpeg/libavformat/pcm.c +++ b/chromium/third_party/ffmpeg/libavformat/pcm.c @@ -37,8 +37,6 @@ int ff_pcm_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->flags &= ~AV_PKT_FLAG_CORRUPT; pkt->stream_index = 0; - if (ret < 0) - return ret; return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/pjsdec.c b/chromium/third_party/ffmpeg/libavformat/pjsdec.c index a69a31660da..6f5db378866 100644 --- a/chromium/third_party/ffmpeg/libavformat/pjsdec.c +++ b/chromium/third_party/ffmpeg/libavformat/pjsdec.c @@ -53,7 +53,8 @@ static int64_t read_ts(char **line, int *duration) int64_t start, end; if (sscanf(*line, "%"SCNd64",%"SCNd64, &start, &end) == 2) { - *line += strcspn(*line, "\"") + 1; + *line += strcspn(*line, "\""); + *line += !!**line; *duration = end - start; return start; } diff --git a/chromium/third_party/ffmpeg/libavformat/pmpdec.c b/chromium/third_party/ffmpeg/libavformat/pmpdec.c index 71f450e9d37..d03283722a3 100644 --- a/chromium/third_party/ffmpeg/libavformat/pmpdec.c +++ b/chromium/third_party/ffmpeg/libavformat/pmpdec.c @@ -138,10 +138,12 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt) if (pmp->cur_stream == 0) { int num_packets; pmp->audio_packets = avio_r8(pb); + if (!pmp->audio_packets) { - avpriv_request_sample(s, "0 audio packets"); - return AVERROR_PATCHWELCOME; + av_log(s, AV_LOG_ERROR, "No audio packets.\n"); + return AVERROR_INVALIDDATA; } + num_packets = (pmp->num_streams - 1) * pmp->audio_packets + 1; avio_skip(pb, 8); pmp->current_packet = 0; @@ -158,10 +160,6 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt) ret = av_get_packet(pb, pkt, pmp->packet_sizes[pmp->current_packet]); if (ret >= 0) { ret = 0; - // FIXME: this is a hack that should be removed once - // compute_pkt_fields() can handle timestamps properly - if (pmp->cur_stream == 0) - pkt->dts = s->streams[0]->cur_dts++; pkt->stream_index = pmp->cur_stream; } if (pmp->current_packet % pmp->audio_packets == 0) diff --git a/chromium/third_party/ffmpeg/libavformat/psxstr.c b/chromium/third_party/ffmpeg/libavformat/psxstr.c index 3409d6a5af8..5efcadf64e6 100644 --- a/chromium/third_party/ffmpeg/libavformat/psxstr.c +++ b/chromium/third_party/ffmpeg/libavformat/psxstr.c @@ -221,6 +221,7 @@ static int str_read_packet(AVFormatContext *s, av_free_packet(pkt); if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE)) return AVERROR(EIO); + memset(pkt->data, 0, sector_count*VIDEO_DATA_CHUNK_SIZE); pkt->pos= avio_tell(pb) - RAW_CD_SECTOR_SIZE; pkt->stream_index = diff --git a/chromium/third_party/ffmpeg/libavformat/pva.c b/chromium/third_party/ffmpeg/libavformat/pva.c index 9b7a40a0682..18ab1cd3fc0 100644 --- a/chromium/third_party/ffmpeg/libavformat/pva.c +++ b/chromium/third_party/ffmpeg/libavformat/pva.c @@ -85,6 +85,7 @@ static int read_part_of_packet(AVFormatContext *s, int64_t *pts, PVAContext *pvactx = s->priv_data; int syncword, streamid, reserved, flags, length, pts_flag; int64_t pva_pts = AV_NOPTS_VALUE, startpos; + int ret; recover: startpos = avio_tell(pb); @@ -133,8 +134,8 @@ recover: pes_flags = avio_rb16(pb); pes_header_data_length = avio_r8(pb); - if (pes_signal != 1) { - pva_log(s, AV_LOG_WARNING, "expected signaled PES packet, " + if (pes_signal != 1 || pes_header_data_length == 0) { + pva_log(s, AV_LOG_WARNING, "expected non empty signaled PES packet, " "trying to recover\n"); avio_skip(pb, length - 9); if (!read_packet) @@ -142,15 +143,23 @@ recover: goto recover; } - avio_read(pb, pes_header_data, pes_header_data_length); + ret = avio_read(pb, pes_header_data, pes_header_data_length); + if (ret != pes_header_data_length) + return ret < 0 ? ret : AVERROR_INVALIDDATA; length -= 9 + pes_header_data_length; pes_packet_length -= 3 + pes_header_data_length; pvactx->continue_pes = pes_packet_length; - if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) + if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) { + if (pes_header_data_length < 5) { + pva_log(s, AV_LOG_ERROR, "header too short\n"); + avio_skip(pb, length); + return AVERROR_INVALIDDATA; + } pva_pts = ff_parse_pes_pts(pes_header_data); + } } pvactx->continue_pes -= length; diff --git a/chromium/third_party/ffmpeg/libavformat/rawdec.c b/chromium/third_party/ffmpeg/libavformat/rawdec.c index a9ff22ae182..9b2aa3551e4 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rawdec.c @@ -28,6 +28,7 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" #define RAW_PACKET_SIZE 1024 @@ -121,6 +122,7 @@ AVInputFormat ff_data_demuxer = { #endif #if CONFIG_LATM_DEMUXER + AVInputFormat ff_latm_demuxer = { .name = "latm", .long_name = NULL_IF_CONFIG_SMALL("raw LOAS/LATM"), diff --git a/chromium/third_party/ffmpeg/libavformat/rawenc.c b/chromium/third_party/ffmpeg/libavformat/rawenc.c index 7a1fa93e8ba..abd7e66978e 100644 --- a/chromium/third_party/ffmpeg/libavformat/rawenc.c +++ b/chromium/third_party/ffmpeg/libavformat/rawenc.c @@ -29,6 +29,16 @@ int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt) return 0; } +static int force_one_stream(AVFormatContext *s) +{ + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "%s files have exactly one stream\n", + s->oformat->name); + return AVERROR(EINVAL); + } + return 0; +} + /* Note: Do not forget to add new entries to the Makefile as well. */ #if CONFIG_AC3_MUXER @@ -39,6 +49,7 @@ AVOutputFormat ff_ac3_muxer = { .extensions = "ac3", .audio_codec = AV_CODEC_ID_AC3, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -51,6 +62,7 @@ AVOutputFormat ff_adx_muxer = { .extensions = "adx", .audio_codec = AV_CODEC_ID_ADPCM_ADX, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -63,6 +75,7 @@ AVOutputFormat ff_cavsvideo_muxer = { .extensions = "cavs", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_CAVS, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -72,6 +85,7 @@ AVOutputFormat ff_cavsvideo_muxer = { AVOutputFormat ff_data_muxer = { .name = "data", .long_name = NULL_IF_CONFIG_SMALL("raw data"), + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -84,6 +98,7 @@ AVOutputFormat ff_dirac_muxer = { .extensions = "drc", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_DIRAC, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -96,6 +111,7 @@ AVOutputFormat ff_dnxhd_muxer = { .extensions = "dnxhd", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_DNXHD, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -109,6 +125,7 @@ AVOutputFormat ff_dts_muxer = { .extensions = "dts", .audio_codec = AV_CODEC_ID_DTS, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -122,6 +139,7 @@ AVOutputFormat ff_eac3_muxer = { .extensions = "eac3", .audio_codec = AV_CODEC_ID_EAC3, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -135,6 +153,7 @@ AVOutputFormat ff_g722_muxer = { .extensions = "g722", .audio_codec = AV_CODEC_ID_ADPCM_G722, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -148,6 +167,7 @@ AVOutputFormat ff_g723_1_muxer = { .extensions = "tco,rco", .audio_codec = AV_CODEC_ID_G723_1, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -161,6 +181,7 @@ AVOutputFormat ff_h261_muxer = { .extensions = "h261", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H261, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -174,6 +195,7 @@ AVOutputFormat ff_h263_muxer = { .extensions = "h263", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H263, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -186,6 +208,19 @@ AVOutputFormat ff_h264_muxer = { .extensions = "h264", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H264, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + +#if CONFIG_HEVC_MUXER +AVOutputFormat ff_hevc_muxer = { + .name = "hevc", + .long_name = NULL_IF_CONFIG_SMALL("raw HEVC video"), + .extensions = "hevc", + .audio_codec = AV_CODEC_ID_NONE, + .video_codec = AV_CODEC_ID_HEVC, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -211,6 +246,7 @@ AVOutputFormat ff_mjpeg_muxer = { .extensions = "mjpg,mjpeg", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MJPEG, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -223,6 +259,7 @@ AVOutputFormat ff_mlp_muxer = { .extensions = "mlp", .audio_codec = AV_CODEC_ID_MLP, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -236,6 +273,7 @@ AVOutputFormat ff_mpeg1video_muxer = { .extensions = "mpg,mpeg,m1v", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MPEG1VIDEO, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -248,6 +286,7 @@ AVOutputFormat ff_mpeg2video_muxer = { .extensions = "m2v", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MPEG2VIDEO, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -272,6 +311,7 @@ AVOutputFormat ff_truehd_muxer = { .extensions = "thd", .audio_codec = AV_CODEC_ID_TRUEHD, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -284,6 +324,7 @@ AVOutputFormat ff_vc1_muxer = { .extensions = "vc1", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_VC1, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; diff --git a/chromium/third_party/ffmpeg/libavformat/replaygain.c b/chromium/third_party/ffmpeg/libavformat/replaygain.c new file mode 100644 index 00000000000..8b8c81a0c3a --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/replaygain.c @@ -0,0 +1,125 @@ +/* + * 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 + */ + +/** + * @file + * replaygain tags parsing + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "libavutil/avstring.h" +#include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" +#include "libavutil/replaygain.h" + +#include "avformat.h" +#include "replaygain.h" + +static int32_t parse_value(const char *value, int32_t min) +{ + char *fraction; + int scale = 10000; + int32_t mb = 0; + int sign = 1; + int db; + + if (!value) + return min; + + value += strspn(value, " \t"); + + if (*value == '-') + sign = -1; + + db = strtol(value, &fraction, 0); + if (*fraction++ == '.') { + while (av_isdigit(*fraction) && scale) { + mb += scale * (*fraction - '0'); + scale /= 10; + fraction++; + } + } + + if (abs(db) > (INT32_MAX - mb) / 100000) + return min; + + return db * 100000 + sign * mb; +} + +int ff_replaygain_export_raw(AVStream *st, int32_t tg, uint32_t tp, + int32_t ag, uint32_t ap) +{ + AVPacketSideData *sd, *tmp; + AVReplayGain *replaygain; + int i; + + if (tg == INT32_MIN && ag == INT32_MIN) + return 0; + + for (i = 0; i < st->nb_side_data; i++) { + AVPacketSideData *src_sd = &st->side_data[i]; + + if (src_sd->type == AV_PKT_DATA_REPLAYGAIN) + return 0; + } + + replaygain = av_mallocz(sizeof(*replaygain)); + if (!replaygain) + return AVERROR(ENOMEM); + + tmp = av_realloc_array(st->side_data, st->nb_side_data + 1, sizeof(*tmp)); + if (!tmp) { + av_freep(&replaygain); + return AVERROR(ENOMEM); + } + st->side_data = tmp; + st->nb_side_data++; + + sd = &st->side_data[st->nb_side_data - 1]; + sd->type = AV_PKT_DATA_REPLAYGAIN; + sd->data = (uint8_t*)replaygain; + sd->size = sizeof(*replaygain); + + replaygain->track_gain = tg; + replaygain->track_peak = tp; + replaygain->album_gain = ag; + replaygain->album_peak = ap; + + return 0; +} + +int ff_replaygain_export(AVStream *st, AVDictionary *metadata) +{ + const AVDictionaryEntry *tg, *tp, *ag, *ap; + + tg = av_dict_get(metadata, "REPLAYGAIN_TRACK_GAIN", NULL, 0); + tp = av_dict_get(metadata, "REPLAYGAIN_TRACK_PEAK", NULL, 0); + ag = av_dict_get(metadata, "REPLAYGAIN_ALBUM_GAIN", NULL, 0); + ap = av_dict_get(metadata, "REPLAYGAIN_ALBUM_PEAK", NULL, 0); + + return ff_replaygain_export_raw(st, + parse_value(tg ? tg->value : NULL, INT32_MIN), + parse_value(tp ? tp->value : NULL, 0), + parse_value(ag ? ag->value : NULL, INT32_MIN), + parse_value(ap ? ap->value : NULL, 0)); +} diff --git a/chromium/third_party/ffmpeg/libavformat/replaygain.h b/chromium/third_party/ffmpeg/libavformat/replaygain.h new file mode 100644 index 00000000000..ceacb21421e --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/replaygain.h @@ -0,0 +1,38 @@ +/* + * 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_REPLAYGAIN_H +#define AVFORMAT_REPLAYGAIN_H + +#include "libavutil/dict.h" + +#include "avformat.h" + +/** + * Parse replaygain tags and export them as per-stream side data. + */ +int ff_replaygain_export(AVStream *st, AVDictionary *metadata); + + +/** + * Export already decoded replaygain values as per-stream side data. + */ +int ff_replaygain_export_raw(AVStream *st, int32_t tg, uint32_t tp, + int32_t ag, uint32_t ap); + +#endif /* AVFORMAT_REPLAYGAIN_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/riff.c b/chromium/third_party/ffmpeg/libavformat/riff.c index 52640d12411..735dea0eaf9 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.c +++ b/chromium/third_party/ffmpeg/libavformat/riff.c @@ -39,9 +39,10 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_H264, MKTAG('S', 'M', 'V', '2') }, { AV_CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') }, { AV_CODEC_ID_H264, MKTAG('Q', '2', '6', '4') }, /* QNAP surveillance system */ - { AV_CODEC_ID_H264, MKTAG('V', '2', '6', '4') }, + { AV_CODEC_ID_H264, MKTAG('V', '2', '6', '4') }, /* CCTV recordings */ { AV_CODEC_ID_H264, MKTAG('G', 'A', 'V', 'C') }, /* GeoVision camera */ { AV_CODEC_ID_H264, MKTAG('U', 'M', 'S', 'V') }, + { AV_CODEC_ID_H264, MKTAG('I', 'N', 'M', 'C') }, { AV_CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, { AV_CODEC_ID_H263, MKTAG('X', '2', '6', '3') }, { AV_CODEC_ID_H263, MKTAG('T', '2', '6', '3') }, @@ -92,7 +93,6 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG4, MKTAG('D', 'M', 'K', '2') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'Y', 'M', '4') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'G', 'I') }, - { AV_CODEC_ID_MPEG4, MKTAG('I', 'N', 'M', 'C') }, /* Ephv MPEG-4 */ { AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') }, { AV_CODEC_ID_MPEG4, MKTAG('E', 'M', '4', 'A') }, @@ -258,6 +258,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_VP6A, MKTAG('V', 'P', '6', 'A') }, { AV_CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') }, { AV_CODEC_ID_VP6F, MKTAG('F', 'L', 'V', '4') }, + { AV_CODEC_ID_VP7, MKTAG('V', 'P', '7', '0') }, + { AV_CODEC_ID_VP7, MKTAG('V', 'P', '7', '1') }, { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, { AV_CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') }, @@ -300,7 +302,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') }, { AV_CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') }, { AV_CODEC_ID_WNV1, MKTAG('Y', 'U', 'V', '8') }, - { AV_CODEC_ID_AASC, MKTAG('A', 'A', 'S', '4') }, + { AV_CODEC_ID_AASC, MKTAG('A', 'A', 'S', '4') }, /* Autodesk 24 bit RLE compressor */ { AV_CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') }, { AV_CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') }, { AV_CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') }, @@ -356,6 +358,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') }, { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') }, { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') }, + { AV_CODEC_ID_FIC, MKTAG('F', 'I', 'C', 'V') }, { AV_CODEC_ID_NONE, 0 } }; @@ -407,12 +410,16 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_ADPCM_G722, 0x028F }, { AV_CODEC_ID_IMC, 0x0401 }, { AV_CODEC_ID_IAC, 0x0402 }, + { AV_CODEC_ID_ON2AVC, 0x0500 }, + { AV_CODEC_ID_ON2AVC, 0x0501 }, { AV_CODEC_ID_GSM_MS, 0x1500 }, { AV_CODEC_ID_TRUESPEECH, 0x1501 }, /* ADTS AAC */ { AV_CODEC_ID_AAC, 0x1600 }, { AV_CODEC_ID_AAC_LATM, 0x1602 }, { AV_CODEC_ID_AC3, 0x2000 }, + /* There is no Microsoft Format Tag for E-AC3, the GUID has to be used */ + { AV_CODEC_ID_EAC3, 0x2000 }, { AV_CODEC_ID_DTS, 0x2001 }, { AV_CODEC_ID_SONIC, 0x2048 }, { AV_CODEC_ID_SONIC_LS, 0x2048 }, @@ -420,7 +427,7 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_AAC, 0x706d }, { AV_CODEC_ID_AAC, 0x4143 }, { AV_CODEC_ID_XAN_DPCM, 0x594a }, - { AV_CODEC_ID_G723_1, 0xA100 }, + { AV_CODEC_ID_G723_1, 0xA100 }, /* Comverse Infosys Ltd. G723 1 */ { AV_CODEC_ID_AAC, 0xA106 }, { AV_CODEC_ID_SPEEX, 0xA109 }, { AV_CODEC_ID_FLAC, 0xF1AC }, @@ -456,3 +463,11 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void) { return ff_codec_wav_tags; } + +const AVCodecGuid ff_codec_wav_guids[] = { + { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, + { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } }, + { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } }, + { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, + { AV_CODEC_ID_NONE } +}; diff --git a/chromium/third_party/ffmpeg/libavformat/riff.h b/chromium/third_party/ffmpeg/libavformat/riff.h index 1bf437e06c8..6f07179b2ae 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.h +++ b/chromium/third_party/ffmpeg/libavformat/riff.h @@ -45,8 +45,22 @@ void ff_end_tag(AVIOContext *pb, int64_t start); */ int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize); -void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf); -int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc); +void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf, int ignore_extradata); + +/** + * Tell ff_put_wav_header() to use WAVEFORMATEX even for PCM codecs. + */ +#define FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX 0x00000001 + +/** + * Write WAVEFORMAT header structure. + * + * @param flags a combination of FF_PUT_WAV_HEADER_* constants + * + * @return the size or -1 on error + */ +int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags); + enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps); int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size); @@ -91,7 +105,9 @@ static av_always_inline int ff_guidcmp(const void *g1, const void *g2) return memcmp(g1, g2, sizeof(ff_asf_guid)); } -void ff_get_guid(AVIOContext *s, ff_asf_guid *g); +int ff_get_guid(AVIOContext *s, ff_asf_guid *g); +void ff_put_guid(AVIOContext *s, const ff_asf_guid *g); +const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid); enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid); diff --git a/chromium/third_party/ffmpeg/libavformat/riffdec.c b/chromium/third_party/ffmpeg/libavformat/riffdec.c index de8eb5f5885..48c9a941b70 100644 --- a/chromium/third_party/ffmpeg/libavformat/riffdec.c +++ b/chromium/third_party/ffmpeg/libavformat/riffdec.c @@ -29,19 +29,14 @@ #include "avio_internal.h" #include "riff.h" -const AVCodecGuid ff_codec_wav_guids[] = { - { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, - { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } }, - { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } }, - { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, - { AV_CODEC_ID_NONE } -}; - -void ff_get_guid(AVIOContext *s, ff_asf_guid *g) +int ff_get_guid(AVIOContext *s, ff_asf_guid *g) { av_assert0(sizeof(*g) == 16); //compiler will optimize this out - if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) + if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) { memset(*g, 0, sizeof(*g)); + return AVERROR_INVALIDDATA; + } + return 0; } enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) @@ -117,9 +112,8 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) } if (cbSize > 0) { av_free(codec->extradata); - if (ff_alloc_extradata(codec, cbSize)) + if (ff_get_extradata(codec, pb, cbSize) < 0) return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); size -= cbSize; } diff --git a/chromium/third_party/ffmpeg/libavformat/riffenc.c b/chromium/third_party/ffmpeg/libavformat/riffenc.c index bcfe018f74e..66c0ff29d63 100644 --- a/chromium/third_party/ffmpeg/libavformat/riffenc.c +++ b/chromium/third_party/ffmpeg/libavformat/riffenc.c @@ -31,7 +31,7 @@ int64_t ff_start_tag(AVIOContext *pb, const char *tag) { ffio_wfourcc(pb, tag); - avio_wl32(pb, 0); + avio_wl32(pb, -1); return avio_tell(pb); } @@ -51,10 +51,11 @@ void ff_end_tag(AVIOContext *pb, int64_t start) /* WAVEFORMATEX header */ /* returns the size or -1 on error */ -int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) +int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags) { int bps, blkalign, bytespersec, frame_size; - int hdrsize = 18; + int hdrsize; + int64_t hdrstart = avio_tell(pb); int waveformatextensible; uint8_t temp[256]; uint8_t *riff_extradata = temp; @@ -72,6 +73,7 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) waveformatextensible = (enc->channels > 2 && enc->channel_layout) || enc->sample_rate > 48000 || + enc->codec_id == AV_CODEC_ID_EAC3 || av_get_bits_per_sample(enc->codec_id) > 16; if (waveformatextensible) @@ -134,14 +136,12 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) avio_wl16(pb, blkalign); /* block align */ avio_wl16(pb, bps); /* bits per sample */ if (enc->codec_id == AV_CODEC_ID_MP3) { - hdrsize += 12; bytestream_put_le16(&riff_extradata, 1); /* wID */ bytestream_put_le32(&riff_extradata, 2); /* fdwFlags */ bytestream_put_le16(&riff_extradata, 1152); /* nBlockSize */ bytestream_put_le16(&riff_extradata, 1); /* nFramesPerBlock */ bytestream_put_le16(&riff_extradata, 1393); /* nCodecDelay */ } else if (enc->codec_id == AV_CODEC_ID_MP2) { - hdrsize += 22; /* fwHeadLayer */ bytestream_put_le16(&riff_extradata, 2); /* dwHeadBitrate */ @@ -159,38 +159,44 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) /* dwPTSHigh */ bytestream_put_le32(&riff_extradata, 0); } else if (enc->codec_id == AV_CODEC_ID_G723_1) { - hdrsize += 20; bytestream_put_le32(&riff_extradata, 0x9ace0002); /* extradata needed for msacm g723.1 codec */ bytestream_put_le32(&riff_extradata, 0xaea2f732); bytestream_put_le16(&riff_extradata, 0xacde); } else if (enc->codec_id == AV_CODEC_ID_GSM_MS || enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) { - hdrsize += 2; /* wSamplesPerBlock */ bytestream_put_le16(&riff_extradata, frame_size); } else if (enc->extradata_size) { riff_extradata_start = enc->extradata; riff_extradata = enc->extradata + enc->extradata_size; - hdrsize += enc->extradata_size; } /* write WAVEFORMATEXTENSIBLE extensions */ if (waveformatextensible) { - hdrsize += 22; + int write_channel_mask = enc->strict_std_compliance < FF_COMPLIANCE_NORMAL || + enc->channel_layout < 0x40000; /* 22 is WAVEFORMATEXTENSIBLE size */ avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ avio_wl16(pb, bps); /* dwChannelMask */ - avio_wl32(pb, enc->channel_layout); + avio_wl32(pb, write_channel_mask ? enc->channel_layout : 0); /* GUID + next 3 */ + if (enc->codec_id == AV_CODEC_ID_EAC3) { + ff_put_guid(pb, get_codec_guid(enc->codec_id, ff_codec_wav_guids)); + } else { avio_wl32(pb, enc->codec_tag); avio_wl32(pb, 0x00100000); avio_wl32(pb, 0xAA000080); avio_wl32(pb, 0x719B3800); - } else { + } + } else if ((flags & FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX) || + enc->codec_tag != 0x0001 /* PCM */ || + riff_extradata - riff_extradata_start) { + /* WAVEFORMATEX */ avio_wl16(pb, riff_extradata - riff_extradata_start); /* cbSize */ - } + } /* else PCMWAVEFORMAT */ avio_write(pb, riff_extradata_start, riff_extradata - riff_extradata_start); + hdrsize = avio_tell(pb) - hdrstart; if (hdrsize & 1) { hdrsize++; avio_w8(pb, 0); @@ -201,10 +207,10 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) /* BITMAPINFOHEADER header */ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, - const AVCodecTag *tags, int for_asf) + const AVCodecTag *tags, int for_asf, int ignore_extradata) { /* size */ - avio_wl32(pb, 40 + enc->extradata_size); + avio_wl32(pb, 40 + (ignore_extradata ? 0 : enc->extradata_size)); avio_wl32(pb, enc->width); //We always store RGB TopDown avio_wl32(pb, enc->codec_tag ? enc->height : -enc->height); @@ -220,10 +226,12 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, avio_wl32(pb, 0); avio_wl32(pb, 0); - avio_write(pb, enc->extradata, enc->extradata_size); + if (!ignore_extradata) { + avio_write(pb, enc->extradata, enc->extradata_size); - if (!for_asf && enc->extradata_size & 1) - avio_w8(pb, 0); + if (!for_asf && enc->extradata_size & 1) + avio_w8(pb, 0); + } } void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, @@ -310,3 +318,19 @@ void ff_riff_write_info(AVFormatContext *s) ff_riff_write_info_tag(s->pb, t->key, t->value); ff_end_tag(pb, list_pos); } + +void ff_put_guid(AVIOContext *s, const ff_asf_guid *g) +{ + av_assert0(sizeof(*g) == 16); + avio_write(s, *g, sizeof(*g)); +} + +const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid) +{ + int i; + for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) { + if (id == av_guid[i].id) + return &(av_guid[i].guid); + } + return NULL; +} diff --git a/chromium/third_party/ffmpeg/libavformat/rl2.c b/chromium/third_party/ffmpeg/libavformat/rl2.c index 56f4cf29ff6..d354339ea31 100644 --- a/chromium/third_party/ffmpeg/libavformat/rl2.c +++ b/chromium/third_party/ffmpeg/libavformat/rl2.c @@ -127,13 +127,9 @@ static av_cold int rl2_read_header(AVFormatContext *s) if(signature == RLV3_TAG && back_size > 0) st->codec->extradata_size += back_size; - if(ff_alloc_extradata(st->codec, st->codec->extradata_size)) + if(ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0) return AVERROR(ENOMEM); - if(avio_read(pb,st->codec->extradata,st->codec->extradata_size) != - st->codec->extradata_size) - return AVERROR(EIO); - /** setup audio stream if present */ if(sound_rate){ if (!channels || channels > 42) { diff --git a/chromium/third_party/ffmpeg/libavformat/rmdec.c b/chromium/third_party/ffmpeg/libavformat/rmdec.c index b0876fe5bd5..36764ee9b22 100644 --- a/chromium/third_party/ffmpeg/libavformat/rmdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rmdec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <inttypes.h> + #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" @@ -86,11 +88,8 @@ static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned si { if (size >= 1<<24) return -1; - if (ff_alloc_extradata(avctx, size)) + if (ff_get_extradata(avctx, pb, size) < 0) return AVERROR(ENOMEM); - avctx->extradata_size = avio_read(pb, avctx->extradata, size); - if (avctx->extradata_size != size) - return AVERROR(EIO); return 0; } @@ -185,6 +184,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, avio_read(pb, buf, 4); buf[4] = 0; } else { + AV_WL32(buf, 0); get_str8(pb, buf, sizeof(buf)); /* desc */ ast->deint_id = AV_RL32(buf); get_str8(pb, buf, sizeof(buf)); /* desc */ @@ -254,18 +254,6 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, return ret; } break; - default: - av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); - } - if (ast->deint_id == DEINT_ID_INT4 || - ast->deint_id == DEINT_ID_GENR || - ast->deint_id == DEINT_ID_SIPR) { - if (st->codec->block_align <= 0 || - ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || - ast->audio_framesize * sub_packet_h < st->codec->block_align) - return AVERROR_INVALIDDATA; - if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) - return AVERROR(ENOMEM); } switch (ast->deint_id) { case DEINT_ID_INT4: @@ -273,11 +261,17 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, sub_packet_h <= 1 || ast->coded_framesize * sub_packet_h > (2 + (sub_packet_h & 1)) * ast->audio_framesize) return AVERROR_INVALIDDATA; + if (ast->coded_framesize * sub_packet_h != 2*ast->audio_framesize) { + avpriv_request_sample(s, "mismatching interleaver parameters"); + return AVERROR_INVALIDDATA; + } break; case DEINT_ID_GENR: if (ast->sub_packet_size <= 0 || ast->sub_packet_size > ast->audio_framesize) return AVERROR_INVALIDDATA; + if (ast->audio_framesize % ast->sub_packet_size) + return AVERROR_INVALIDDATA; break; case DEINT_ID_SIPR: case DEINT_ID_INT0: @@ -285,9 +279,19 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, case DEINT_ID_VBRF: break; default: - av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\n", ast->deint_id); + av_log(s, AV_LOG_ERROR ,"Unknown interleaver %"PRIX32"\n", ast->deint_id); return AVERROR_INVALIDDATA; } + if (ast->deint_id == DEINT_ID_INT4 || + ast->deint_id == DEINT_ID_GENR || + ast->deint_id == DEINT_ID_SIPR) { + if (st->codec->block_align <= 0 || + ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || + ast->audio_framesize * sub_packet_h < st->codec->block_align) + return AVERROR_INVALIDDATA; + if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) + return AVERROR(ENOMEM); + } if (read_all) { avio_r8(pb); @@ -785,6 +789,16 @@ rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) } } +static int readfull(AVFormatContext *s, AVIOContext *pb, uint8_t *dst, int n) { + int ret = avio_read(pb, dst, n); + if (ret != n) { + if (ret >= 0) memset(dst + ret, 0, n - ret); + else memset(dst , 0, n); + av_log(s, AV_LOG_ERROR, "Failed to fully read block\n"); + } + return ret; +} + int ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, AVStream *st, RMStream *ast, int len, AVPacket *pkt, @@ -817,14 +831,14 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, switch (ast->deint_id) { case DEINT_ID_INT4: for (x = 0; x < h/2; x++) - avio_read(pb, ast->pkt.data+x*2*w+y*cfs, cfs); + readfull(s, pb, ast->pkt.data+x*2*w+y*cfs, cfs); break; case DEINT_ID_GENR: for (x = 0; x < w/sps; x++) - avio_read(pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); + readfull(s, pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); break; case DEINT_ID_SIPR: - avio_read(pb, ast->pkt.data + y * w, w); + readfull(s, pb, ast->pkt.data + y * w, w); break; } diff --git a/chromium/third_party/ffmpeg/libavformat/rpl.c b/chromium/third_party/ffmpeg/libavformat/rpl.c index 85b573ea1f0..46a5796414e 100644 --- a/chromium/third_party/ffmpeg/libavformat/rpl.c +++ b/chromium/third_party/ffmpeg/libavformat/rpl.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdint.h> +#include <inttypes.h> #include <stdlib.h> #include "libavutil/avstring.h" @@ -222,7 +222,8 @@ static int rpl_read_header(AVFormatContext *s) break; } if (ast->codec->codec_id == AV_CODEC_ID_NONE) - avpriv_request_sample(s, "Audio format %i", audio_format); + avpriv_request_sample(s, "Audio format %"PRId32, + audio_format); avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate); } else { for (i = 0; i < 3; i++) @@ -254,8 +255,10 @@ static int rpl_read_header(AVFormatContext *s) int64_t offset, video_size, audio_size; error |= read_line(pb, line, sizeof(line)); if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64, - &offset, &video_size, &audio_size)) + &offset, &video_size, &audio_size)) { error = -1; + continue; + } av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, video_size, rpl->frames_per_chunk, 0); if (ast) diff --git a/chromium/third_party/ffmpeg/libavformat/rsd.c b/chromium/third_party/ffmpeg/libavformat/rsd.c index 341f638c77c..b6f168633b1 100644 --- a/chromium/third_party/ffmpeg/libavformat/rsd.c +++ b/chromium/third_party/ffmpeg/libavformat/rsd.c @@ -104,13 +104,10 @@ static int rsd_read_header(AVFormatContext *s) /* RSD3GADP is mono, so only alloc enough memory to store the coeff table for a single channel. */ - if (ff_alloc_extradata(codec, 32)) - return AVERROR(ENOMEM); - start = avio_rl32(pb); - if (avio_read(s->pb, codec->extradata, 32) != 32) - return AVERROR_INVALIDDATA; + if (ff_get_extradata(codec, s->pb, 32) < 0) + return AVERROR(ENOMEM); for (i = 0; i < 16; i++) AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2)); diff --git a/chromium/third_party/ffmpeg/libavformat/rtmppkt.c b/chromium/third_party/ffmpeg/libavformat/rtmppkt.c index 375ae2fcb13..65d5dd9d570 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmppkt.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmppkt.c @@ -169,6 +169,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, uint8_t buf[16]; int channel_id, timestamp, size; + uint32_t ts_field; // non-extended timestamp or delta field uint32_t extra = 0; enum RTMPPacketType type; int written = 0; @@ -193,14 +194,14 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, type = prev_pkt[channel_id].type; extra = prev_pkt[channel_id].extra; - hdr >>= 6; + hdr >>= 6; // header size indicator if (hdr == RTMP_PS_ONEBYTE) { - timestamp = prev_pkt[channel_id].ts_delta; + ts_field = prev_pkt[channel_id].ts_field; } else { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); written += 3; - timestamp = AV_RB24(buf); + ts_field = AV_RB24(buf); if (hdr != RTMP_PS_FOURBYTES) { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); @@ -217,11 +218,13 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, extra = AV_RL32(buf); } } - if (timestamp == 0xFFFFFF) { - if (ffurl_read_complete(h, buf, 4) != 4) - return AVERROR(EIO); - timestamp = AV_RB32(buf); - } + } + if (ts_field == 0xFFFFFF) { + if (ffurl_read_complete(h, buf, 4) != 4) + return AVERROR(EIO); + timestamp = AV_RB32(buf); + } else { + timestamp = ts_field; } if (hdr != RTMP_PS_TWELVEBYTES) timestamp += prev_pkt[channel_id].timestamp; @@ -232,8 +235,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, return ret; p->read = written; p->offset = 0; - prev_pkt[channel_id].ts_delta = timestamp - - prev_pkt[channel_id].timestamp; + prev_pkt[channel_id].ts_field = ts_field; prev_pkt[channel_id].timestamp = timestamp; } else { // previous packet in this channel hasn't completed reading @@ -242,7 +244,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, p->size = prev->size; p->channel_id = prev->channel_id; p->type = prev->type; - p->ts_delta = prev->ts_delta; + p->ts_field = prev->ts_field; p->extra = prev->extra; p->offset = prev->offset; p->read = prev->read + written; @@ -271,6 +273,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, prev->data = p->data; prev->read = p->read; prev->offset = p->offset; + p->data = NULL; return AVERROR(EAGAIN); } @@ -303,21 +306,34 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int written = 0; int ret; RTMPPacket *prev_pkt; + int use_delta; // flag if using timestamp delta, not RTMP_PS_TWELVEBYTES + uint32_t timestamp; // full 32-bit timestamp or delta value if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt, pkt->channel_id)) < 0) return ret; prev_pkt = *prev_pkt_ptr; - pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; - //if channel_id = 0, this is first presentation of prev_pkt, send full hdr. - if (prev_pkt[pkt->channel_id].channel_id && - pkt->extra == prev_pkt[pkt->channel_id].extra) { + use_delta = prev_pkt[pkt->channel_id].channel_id && + pkt->extra == prev_pkt[pkt->channel_id].extra && + pkt->timestamp >= prev_pkt[pkt->channel_id].timestamp; + + timestamp = pkt->timestamp; + if (use_delta) { + timestamp -= prev_pkt[pkt->channel_id].timestamp; + } + if (timestamp >= 0xFFFFFF) { + pkt->ts_field = 0xFFFFFF; + } else { + pkt->ts_field = timestamp; + } + + if (use_delta) { if (pkt->type == prev_pkt[pkt->channel_id].type && pkt->size == prev_pkt[pkt->channel_id].size) { mode = RTMP_PS_FOURBYTES; - if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) + if (pkt->ts_field == prev_pkt[pkt->channel_id].ts_field) mode = RTMP_PS_ONEBYTE; } else { mode = RTMP_PS_EIGHTBYTES; @@ -334,29 +350,22 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, bytestream_put_le16(&p, pkt->channel_id - 64); } if (mode != RTMP_PS_ONEBYTE) { - uint32_t timestamp = pkt->timestamp; - if (mode != RTMP_PS_TWELVEBYTES) - timestamp = pkt->ts_delta; - bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); + bytestream_put_be24(&p, pkt->ts_field); if (mode != RTMP_PS_FOURBYTES) { bytestream_put_be24(&p, pkt->size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); } - if (timestamp >= 0xFFFFFF) - bytestream_put_be32(&p, timestamp); } + if (pkt->ts_field == 0xFFFFFF) + bytestream_put_be32(&p, timestamp); // save history prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; prev_pkt[pkt->channel_id].type = pkt->type; prev_pkt[pkt->channel_id].size = pkt->size; prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; - if (mode != RTMP_PS_TWELVEBYTES) { - prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; - } else { - prev_pkt[pkt->channel_id].ts_delta = pkt->timestamp; - } + prev_pkt[pkt->channel_id].ts_field = pkt->ts_field; prev_pkt[pkt->channel_id].extra = pkt->extra; if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0) @@ -390,7 +399,7 @@ int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, pkt->type = type; pkt->timestamp = timestamp; pkt->extra = 0; - pkt->ts_delta = 0; + pkt->ts_field = 0; return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtmppkt.h b/chromium/third_party/ffmpeg/libavformat/rtmppkt.h index fb79fedac64..0d98f60981e 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmppkt.h +++ b/chromium/third_party/ffmpeg/libavformat/rtmppkt.h @@ -78,7 +78,7 @@ typedef struct RTMPPacket { int channel_id; ///< RTMP channel ID (nothing to do with audio/video channels though) RTMPPacketType type; ///< packet payload type uint32_t timestamp; ///< packet full timestamp - uint32_t ts_delta; ///< timestamp increment to the previous one in milliseconds (latter only for media packets) + uint32_t ts_field; ///< 24-bit timestamp or increment to the previous one, in milliseconds (latter only for media packets). Clipped to a maximum of 0xFFFFFF, indicating an extended timestamp field. uint32_t extra; ///< probably an additional channel ID used during streaming data uint8_t *data; ///< packet payload int size; ///< packet payload size diff --git a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c index a4d7f0ee73d..308110b9c1b 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmpproto.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmpproto.c @@ -150,6 +150,8 @@ static const uint8_t rtmp_server_key[] = { 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE }; +static int handle_chunk_size(URLContext *s, RTMPPacket *pkt); + static int add_tracked_method(RTMPContext *rt, const char *name, int id) { int err; @@ -408,6 +410,17 @@ static int read_connect(URLContext *s, RTMPContext *rt) if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size, &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0) return ret; + + if (pkt.type == RTMP_PT_CHUNK_SIZE) { + if ((ret = handle_chunk_size(s, &pkt)) < 0) + return ret; + + ff_rtmp_packet_destroy(&pkt); + if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size, + &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0) + return ret; + } + cp = pkt.data; bytestream2_init(&gbc, cp, pkt.size); if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) { @@ -2367,7 +2380,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) { RTMPContext *rt = s->priv_data; char proto[8], hostname[256], path[1024], auth[100], *fname; - char *old_app; + char *old_app, *qmark, fname_buffer[1024]; uint8_t buf[2048]; int port; AVDictionary *opts = NULL; @@ -2465,7 +2478,20 @@ reconnect: } //extract "app" part from path - if (!strncmp(path, "/ondemand/", 10)) { + qmark = strchr(path, '?'); + if (qmark && strstr(qmark, "slist=")) { + char* amp; + // After slist we have the playpath, before the params, the app + av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH)); + fname = strstr(path, "slist=") + 6; + // Strip any further query parameters from fname + amp = strchr(fname, '&'); + if (amp) { + av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1, + sizeof(fname_buffer))); + fname = fname_buffer; + } + } else if (!strncmp(path, "/ondemand/", 10)) { fname = path + 10; memcpy(rt->app, "ondemand", 9); } else { @@ -2511,9 +2537,9 @@ reconnect: (!strcmp(fname + len - 4, ".f4v") || !strcmp(fname + len - 4, ".mp4"))) { memcpy(rt->playpath, "mp4:", 5); - } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) { - fname[len - 4] = '\0'; } else { + if (len >= 4 && !strcmp(fname + len - 4, ".flv")) + fname[len - 4] = '\0'; rt->playpath[0] = 0; } av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH); @@ -2556,7 +2582,7 @@ reconnect: if ((ret = gen_connect(s, rt)) < 0) goto fail; } else { - if (read_connect(s, s->priv_data) < 0) + if ((ret = read_connect(s, s->priv_data)) < 0) goto fail; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec.h b/chromium/third_party/ffmpeg/libavformat/rtpdec.h index 9321066ba78..7e356c048d5 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec.h +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec.h @@ -173,9 +173,9 @@ struct RTPDemuxContext { /*@}*/ /* rtcp sender statistics receive */ - int64_t last_rtcp_ntp_time; + uint64_t last_rtcp_ntp_time; int64_t last_rtcp_reception_time; - int64_t first_rtcp_ntp_time; + uint64_t first_rtcp_ntp_time; uint32_t last_rtcp_timestamp; int64_t rtcp_ts_offset; diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_asf.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_asf.c index 123894f2756..541b86fe41b 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_asf.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_asf.c @@ -144,6 +144,8 @@ static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index, if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) { *s->streams[stream_index]->codec = *rt->asf_ctx->streams[i]->codec; + s->streams[stream_index]->need_parsing = + rt->asf_ctx->streams[i]->need_parsing; rt->asf_ctx->streams[i]->codec->extradata_size = 0; rt->asf_ctx->streams[i]->codec->extradata = NULL; avpriv_set_pts_info(s->streams[stream_index], 32, 1, 1000); diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c index be657c0ccc7..1ca78bc81c2 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_h264.c @@ -190,7 +190,8 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, switch (type) { case 0: // undefined, but pass them through case 1: - av_new_packet(pkt, len + sizeof(start_sequence)); + if ((result = av_new_packet(pkt, len + sizeof(start_sequence))) < 0) + return result; memcpy(pkt->data, start_sequence, sizeof(start_sequence)); memcpy(pkt->data + sizeof(start_sequence), buf, len); COUNT_NAL_TYPE(data, nal); @@ -247,7 +248,8 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, if (pass == 0) { /* now we know the total size of the packet (with the * start sequences added) */ - av_new_packet(pkt, total_length); + if ((result = av_new_packet(pkt, total_length)) < 0) + return result; dst = pkt->data; } else { assert(dst - pkt->data == total_length); @@ -292,12 +294,14 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, COUNT_NAL_TYPE(data, nal_type); if (start_bit) { /* copy in the start sequence, and the reconstructed nal */ - av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len); + if ((result = av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len)) < 0) + return result; memcpy(pkt->data, start_sequence, sizeof(start_sequence)); pkt->data[sizeof(start_sequence)] = reconstructed_nal; memcpy(pkt->data + sizeof(start_sequence) + sizeof(nal), buf, len); } else { - av_new_packet(pkt, len); + if ((result = av_new_packet(pkt, len)) < 0) + return result; memcpy(pkt->data, buf, len); } } else { diff --git a/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c b/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c index 887a65ed651..43f72a2305d 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpdec_xiph.c @@ -256,7 +256,7 @@ parse_packed_headers(const uint8_t * packed_headers, if (packed_headers_end - packed_headers < 9) { av_log(codec, AV_LOG_ERROR, - "Invalid %td byte packed header.", + "Invalid %"PTRDIFF_SPECIFIER" byte packed header.", packed_headers_end - packed_headers); return AVERROR_INVALIDDATA; } @@ -278,7 +278,7 @@ parse_packed_headers(const uint8_t * packed_headers, if (packed_headers_end - packed_headers != length || length1 > length || length2 > length - length1) { av_log(codec, AV_LOG_ERROR, - "Bad packed header lengths (%d,%d,%td,%d)\n", length1, + "Bad packed header lengths (%d,%d,%"PTRDIFF_SPECIFIER",%d)\n", length1, length2, packed_headers_end - packed_headers, length); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtpenc.c b/chromium/third_party/ffmpeg/libavformat/rtpenc.c index 6fdc908d0f9..457fef0cfcb 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtpenc.c +++ b/chromium/third_party/ffmpeg/libavformat/rtpenc.c @@ -119,7 +119,7 @@ static int rtp_write_header(AVFormatContext *s1) s->ssrc = av_get_random_seed(); s->first_packet = 1; s->first_rtcp_ntp_time = ff_ntp_time(); - if (s1->start_time_realtime) + if (s1->start_time_realtime != 0 && s1->start_time_realtime != AV_NOPTS_VALUE) /* Round the NTP time to whole milliseconds. */ s->first_rtcp_ntp_time = (s1->start_time_realtime / 1000) * 1000 + NTP_OFFSET_US; @@ -557,6 +557,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) const uint8_t *mb_info = av_packet_get_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, &mb_info_size); + if (!mb_info) { + av_log(s1, AV_LOG_ERROR, "failed to allocate side data\n"); + return AVERROR(ENOMEM); + } ff_rtp_send_h263_rfc2190(s1, pkt->data, size, mb_info, mb_info_size); break; } diff --git a/chromium/third_party/ffmpeg/libavformat/rtsp.c b/chromium/third_party/ffmpeg/libavformat/rtsp.c index 3b88fc72715..fcf9eca0d49 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtsp.c +++ b/chromium/third_party/ffmpeg/libavformat/rtsp.c @@ -65,7 +65,7 @@ #define RTSP_FLAG_OPTS(name, longname) \ { name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \ - { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" } + { "filter_src", "only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" } #define RTSP_MEDIATYPE_OPTS(name, longname) \ { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \ @@ -74,23 +74,24 @@ { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" } #define RTSP_REORDERING_OPTS() \ - { "reorder_queue_size", "Number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC } + { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC } const AVOption ff_rtsp_options[] = { - { "initial_pause", "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, + { "initial_pause", "do not start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags), - { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \ + { "rtsp_transport", "set RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \ { "udp", "UDP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ { "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ { "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" }, { "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" }, - RTSP_FLAG_OPTS("rtsp_flags", "RTSP flags"), - { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }, - RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"), - { "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC }, - { "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC }, - { "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, - { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, + RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"), + { "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }, + { "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" }, + RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), + { "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC }, + { "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC }, + { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, + { "stimeout", "set timeout (in micro seconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, RTSP_REORDERING_OPTS(), { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, { NULL }, @@ -98,15 +99,15 @@ const AVOption ff_rtsp_options[] = { static const AVOption sdp_options[] = { RTSP_FLAG_OPTS("sdp_flags", "SDP flags"), - { "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, - { "rtcp_to_source", "Send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" }, - RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"), + { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, + { "rtcp_to_source", "send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" }, + RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), RTSP_REORDERING_OPTS(), { NULL }, }; static const AVOption rtp_options[] = { - RTSP_FLAG_OPTS("rtp_flags", "RTP flags"), + RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"), RTSP_REORDERING_OPTS(), { NULL }, }; @@ -729,8 +730,8 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) s->ctx_flags |= AVFMTCTX_NOHEADER; if (s->oformat && CONFIG_RTSP_MUXER) { - int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st, - rtsp_st->rtp_handle, + int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, + s, st, rtsp_st->rtp_handle, RTSP_TCP_MAX_PACKET_SIZE, rtsp_st->stream_index); /* Ownership of rtp_handle is passed to the rtp mux context */ @@ -1766,6 +1767,10 @@ redirect: int lower_transport = ff_log2_tab[lower_transport_mask & ~(lower_transport_mask - 1)]; + if ((lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) + && (rt->rtsp_flags & RTSP_FLAG_PREFER_TCP)) + lower_transport = RTSP_LOWER_TRANSPORT_TCP; + err = ff_rtsp_make_setup_request(s, host, port, lower_transport, rt->server_type == RTSP_SERVER_REAL ? real_challenge : NULL); @@ -2066,6 +2071,16 @@ redo: st2->time_base); } } + // Make real NTP start time available in AVFormatContext + if (s->start_time_realtime == AV_NOPTS_VALUE) { + s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32); + if (rtpctx->st) { + s->start_time_realtime -= + av_rescale (rtpctx->rtcp_ts_offset, + (uint64_t) rtpctx->st->time_base.num * 1000000, + rtpctx->st->time_base.den); + } + } } if (ret == -RTCP_BYE) { rt->nb_byes++; diff --git a/chromium/third_party/ffmpeg/libavformat/rtsp.h b/chromium/third_party/ffmpeg/libavformat/rtsp.h index 76c7f181cf7..d1597938351 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtsp.h +++ b/chromium/third_party/ffmpeg/libavformat/rtsp.h @@ -413,6 +413,7 @@ typedef struct RTSPState { #define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */ #define RTSP_FLAG_RTCP_TO_SOURCE 0x8 /**< Send RTCP packets to the source address of received packets. */ +#define RTSP_FLAG_PREFER_TCP 0x10 /**< Try RTP via TCP first if possible. */ typedef struct RTSPSource { char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */ diff --git a/chromium/third_party/ffmpeg/libavformat/rtspcodes.h b/chromium/third_party/ffmpeg/libavformat/rtspcodes.h index 4245e48642d..d4f762b00c3 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtspcodes.h +++ b/chromium/third_party/ffmpeg/libavformat/rtspcodes.h @@ -1,6 +1,8 @@ /* * RTSP definitions * copyright (c) 2002 Fabrice Bellard + * copyright (c) 2014 Samsung Electronics. All rights reserved. + * @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com> * * This file is part of FFmpeg. * @@ -22,21 +24,107 @@ #ifndef AVFORMAT_RTSPCODES_H #define AVFORMAT_RTSPCODES_H +#include "libavutil/common.h" + /** RTSP handling */ enum RTSPStatusCode { -RTSP_STATUS_OK =200, /**< OK */ -RTSP_STATUS_METHOD =405, /**< Method Not Allowed */ -RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */ -RTSP_STATUS_SESSION =454, /**< Session Not Found */ -RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */ -RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */ -RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */ -RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */ -RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */ -RTSP_STATUS_SERVICE =503, /**< Service Unavailable */ -RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */ +RTSP_STATUS_CONTINUE =100, +RTSP_STATUS_OK =200, +RTSP_STATUS_CREATED =201, +RTSP_STATUS_LOW_ON_STORAGE_SPACE =250, +RTSP_STATUS_MULTIPLE_CHOICES =300, +RTSP_STATUS_MOVED_PERMANENTLY =301, +RTSP_STATUS_MOVED_TEMPORARILY =302, +RTSP_STATUS_SEE_OTHER =303, +RTSP_STATUS_NOT_MODIFIED =304, +RTSP_STATUS_USE_PROXY =305, +RTSP_STATUS_BAD_REQUEST =400, +RTSP_STATUS_UNAUTHORIZED =401, +RTSP_STATUS_PAYMENT_REQUIRED =402, +RTSP_STATUS_FORBIDDEN =403, +RTSP_STATUS_NOT_FOUND =404, +RTSP_STATUS_METHOD =405, +RTSP_STATUS_NOT_ACCEPTABLE =406, +RTSP_STATUS_PROXY_AUTH_REQUIRED =407, +RTSP_STATUS_REQ_TIME_OUT =408, +RTSP_STATUS_GONE =410, +RTSP_STATUS_LENGTH_REQUIRED =411, +RTSP_STATUS_PRECONDITION_FAILED =412, +RTSP_STATUS_REQ_ENTITY_2LARGE =413, +RTSP_STATUS_REQ_URI_2LARGE =414, +RTSP_STATUS_UNSUPPORTED_MTYPE =415, +RTSP_STATUS_PARAM_NOT_UNDERSTOOD =451, +RTSP_STATUS_CONFERENCE_NOT_FOUND =452, +RTSP_STATUS_BANDWIDTH =453, +RTSP_STATUS_SESSION =454, +RTSP_STATUS_STATE =455, +RTSP_STATUS_INVALID_HEADER_FIELD =456, +RTSP_STATUS_INVALID_RANGE =457, +RTSP_STATUS_RONLY_PARAMETER =458, +RTSP_STATUS_AGGREGATE =459, +RTSP_STATUS_ONLY_AGGREGATE =460, +RTSP_STATUS_TRANSPORT =461, +RTSP_STATUS_UNREACHABLE =462, +RTSP_STATUS_INTERNAL =500, +RTSP_STATUS_NOT_IMPLEMENTED =501, +RTSP_STATUS_BAD_GATEWAY =502, +RTSP_STATUS_SERVICE =503, +RTSP_STATUS_GATEWAY_TIME_OUT =504, +RTSP_STATUS_VERSION =505, +RTSP_STATUS_UNSUPPORTED_OPTION =551, +}; + +static const av_unused char *rtsp_status_strings[] = { +[RTSP_STATUS_CONTINUE] ="Continue", +[RTSP_STATUS_OK] ="OK", +[RTSP_STATUS_CREATED] ="Created", +[RTSP_STATUS_LOW_ON_STORAGE_SPACE] ="Low on Storage Space", +[RTSP_STATUS_MULTIPLE_CHOICES] ="Multiple Choices", +[RTSP_STATUS_MOVED_PERMANENTLY] ="Moved Permanently", +[RTSP_STATUS_MOVED_TEMPORARILY] ="Moved Temporarily", +[RTSP_STATUS_SEE_OTHER] ="See Other", +[RTSP_STATUS_NOT_MODIFIED] ="Not Modified", +[RTSP_STATUS_USE_PROXY] ="Use Proxy", +[RTSP_STATUS_BAD_REQUEST] ="Bad Request", +[RTSP_STATUS_UNAUTHORIZED] ="Unauthorized", +[RTSP_STATUS_PAYMENT_REQUIRED] ="Payment Required", +[RTSP_STATUS_FORBIDDEN] ="Forbidden", +[RTSP_STATUS_NOT_FOUND] ="Not Found", +[RTSP_STATUS_METHOD] ="Method Not Allowed", +[RTSP_STATUS_NOT_ACCEPTABLE] ="Not Acceptable", +[RTSP_STATUS_PROXY_AUTH_REQUIRED] ="Proxy Authentication Required", +[RTSP_STATUS_REQ_TIME_OUT] ="Request Time-out", +[RTSP_STATUS_GONE] ="Gone", +[RTSP_STATUS_LENGTH_REQUIRED] ="Length Required", +[RTSP_STATUS_PRECONDITION_FAILED] ="Precondition Failed", +[RTSP_STATUS_REQ_ENTITY_2LARGE] ="Request Entity Too Large", +[RTSP_STATUS_REQ_URI_2LARGE] ="Request URI Too Large", +[RTSP_STATUS_UNSUPPORTED_MTYPE] ="Unsupported Media Type", +[RTSP_STATUS_PARAM_NOT_UNDERSTOOD] ="Parameter Not Understood", +[RTSP_STATUS_CONFERENCE_NOT_FOUND] ="Conference Not Found", +[RTSP_STATUS_BANDWIDTH] ="Not Enough Bandwidth", +[RTSP_STATUS_SESSION] ="Session Not Found", +[RTSP_STATUS_STATE] ="Method Not Valid in This State", +[RTSP_STATUS_INVALID_HEADER_FIELD] ="Header Field Not Valid for Resource", +[RTSP_STATUS_INVALID_RANGE] ="Invalid Range", +[RTSP_STATUS_RONLY_PARAMETER] ="Parameter Is Read-Only", +[RTSP_STATUS_AGGREGATE] ="Aggregate Operation no Allowed", +[RTSP_STATUS_ONLY_AGGREGATE] ="Only Aggregate Operation Allowed", +[RTSP_STATUS_TRANSPORT] ="Unsupported Transport", +[RTSP_STATUS_UNREACHABLE] ="Destination Unreachable", +[RTSP_STATUS_INTERNAL] ="Internal Server Error", +[RTSP_STATUS_NOT_IMPLEMENTED] ="Not Implemented", +[RTSP_STATUS_BAD_GATEWAY] ="Bad Gateway", +[RTSP_STATUS_SERVICE] ="Service Unavailable", +[RTSP_STATUS_GATEWAY_TIME_OUT] ="Gateway Time-out", +[RTSP_STATUS_VERSION] ="RTSP Version not Supported", +[RTSP_STATUS_UNSUPPORTED_OPTION] ="Option not supported", }; +#define RTSP_STATUS_CODE2STRING(x) (\ +x >= 100 && x < FF_ARRAY_ELEMS(rtsp_status_strings) && rtsp_status_strings[x] \ +)? rtsp_status_strings[x] : NULL + enum RTSPMethod { DESCRIBE, ANNOUNCE, diff --git a/chromium/third_party/ffmpeg/libavformat/rtspdec.c b/chromium/third_party/ffmpeg/libavformat/rtspdec.c index eb650ff42a1..af20465783c 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtspdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rtspdec.c @@ -360,6 +360,10 @@ static inline int parse_command_line(AVFormatContext *s, const char *line, RTSPState *rt = s->priv_data; const char *linept, *searchlinept; linept = strchr(line, ' '); + if (!linept) { + av_log(s, AV_LOG_ERROR, "Error parsing method string\n"); + return AVERROR_INVALIDDATA; + } if (linept - line > methodsize - 1) { av_log(s, AV_LOG_ERROR, "Method string too long\n"); return AVERROR(EIO); @@ -877,7 +881,7 @@ retry: rt->get_parameter_supported)) { ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL); } else { - ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL); + ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL); } /* The stale flag should be reset when creating the auth response in * ff_rtsp_send_cmd_async, but reset it here just in case we never diff --git a/chromium/third_party/ffmpeg/libavformat/rtspenc.c b/chromium/third_party/ffmpeg/libavformat/rtspenc.c index d76ae872eb4..cc6e729e8cd 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtspenc.c +++ b/chromium/third_party/ffmpeg/libavformat/rtspenc.c @@ -51,7 +51,8 @@ int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr) char *sdp; AVFormatContext sdp_ctx, *ctx_array[1]; - s->start_time_realtime = av_gettime(); + if (s->start_time_realtime == 0 || s->start_time_realtime == AV_NOPTS_VALUE) + s->start_time_realtime = av_gettime(); /* Announce the stream */ sdp = av_mallocz(SDP_MAX_SIZE); diff --git a/chromium/third_party/ffmpeg/libavformat/sapenc.c b/chromium/third_party/ffmpeg/libavformat/sapenc.c index 9fc78a83af8..738e8b8f911 100644 --- a/chromium/third_party/ffmpeg/libavformat/sapenc.c +++ b/chromium/third_party/ffmpeg/libavformat/sapenc.c @@ -140,7 +140,8 @@ static int sap_write_header(AVFormatContext *s) goto fail; } - s->start_time_realtime = av_gettime(); + if (s->start_time_realtime == 0 || s->start_time_realtime == AV_NOPTS_VALUE) + s->start_time_realtime = av_gettime(); for (i = 0; i < s->nb_streams; i++) { URLContext *fd; diff --git a/chromium/third_party/ffmpeg/libavformat/sdp.c b/chromium/third_party/ffmpeg/libavformat/sdp.c index 01242184958..c53de905171 100644 --- a/chromium/third_party/ffmpeg/libavformat/sdp.c +++ b/chromium/third_party/ffmpeg/libavformat/sdp.c @@ -217,7 +217,7 @@ static char *extradata2psets(AVCodecContext *c) sps_end = r1; } if (av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r) == NULL) { - av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %td %td!\n", MAX_PSET_SIZE - (p - psets), r1 - r); + av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"!\n", MAX_PSET_SIZE - (p - psets), r1 - r); av_free(psets); return NULL; @@ -402,7 +402,7 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, switch (c->codec_id) { case AV_CODEC_ID_H264: { int mode = 1; - if (fmt && fmt->oformat->priv_class && + if (fmt && fmt->oformat && fmt->oformat->priv_class && av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0")) mode = 0; if (c->extradata_size) { @@ -513,13 +513,6 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, break; case AV_CODEC_ID_THEORA: { const char *pix_fmt; - if (c->extradata_size) - config = xiph_extradata2config(c); - else - av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n"); - if (!config) - return NULL; - switch (c->pix_fmt) { case AV_PIX_FMT_YUV420P: pix_fmt = "YCbCr-4:2:0"; @@ -535,6 +528,13 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, return NULL; } + if (c->extradata_size) + config = xiph_extradata2config(c); + else + av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n"); + if (!config) + return NULL; + av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" "a=fmtp:%d delivery-method=inline; " "width=%d; height=%d; sampling=%s; " diff --git a/chromium/third_party/ffmpeg/libavformat/sdr2.c b/chromium/third_party/ffmpeg/libavformat/sdr2.c new file mode 100644 index 00000000000..82405f69d18 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/sdr2.c @@ -0,0 +1,121 @@ +/* + * SDR2 demuxer + * Copyright (c) 2014 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 "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" + +static int sdr2_probe(AVProbeData *p) +{ + if (AV_RL32(p->buf) != MKTAG('S', 'R', 'A', 1)) + return 0; + + return AVPROBE_SCORE_EXTENSION; +} + +#define FIRST 0xA8 + +static int sdr2_read_header(AVFormatContext *s) +{ + AVStream *st, *ast; + + ast = avformat_new_stream(s, 0); + if (!ast) + return AVERROR(ENOMEM); + + st = avformat_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(s->pb, 20); + avpriv_set_pts_info(st, 64, 1, avio_rl32(s->pb)); + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->width = avio_rl32(s->pb); + st->codec->height = avio_rl32(s->pb); + st->codec->codec_id = AV_CODEC_ID_H264; + st->need_parsing = AVSTREAM_PARSE_FULL; + + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + ast->codec->channels = 1; + ast->codec->sample_rate = 8000; + ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE; + avpriv_set_pts_info(ast, 64, 1, 8000); + + avio_seek(s->pb, FIRST, SEEK_SET); + + return 0; +} + +static const uint8_t header[24] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0xa6, 0x80, 0xb0, 0x7e, 0x40, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xce, 0x38, 0x80, 0x00, 0x00, 0x00 +}; + +static int sdr2_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int64_t pos; + unsigned next; + int flags, ret = 0, is_video; + + pos = avio_tell(s->pb); + + flags = avio_rl32(s->pb); + avio_skip(s->pb, 4); + + next = avio_rl32(s->pb); + if (next <= 52) + return AVERROR_INVALIDDATA; + + avio_skip(s->pb, 6); + is_video = avio_rl32(s->pb); + avio_skip(s->pb, 30); + + if (pos == FIRST) { + if (av_new_packet(pkt, next - 52 + 24) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, header, 24); + ret = avio_read(s->pb, pkt->data + 24, next - 52); + if (ret < 0) { + av_free_packet(pkt); + return ret; + } + av_shrink_packet(pkt, ret + 24); + } else { + ret = av_get_packet(s->pb, pkt, next - 52); + } + pkt->stream_index = !!is_video; + pkt->pos = pos; + if (flags & (1 << 12)) + pkt->flags |= AV_PKT_FLAG_KEY; + + return ret; +} + +AVInputFormat ff_sdr2_demuxer = { + .name = "sdr2", + .long_name = NULL_IF_CONFIG_SMALL("SDR2"), + .read_probe = sdr2_probe, + .read_header = sdr2_read_header, + .read_packet = sdr2_read_packet, + .extensions = "sdr2", + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/segafilm.c b/chromium/third_party/ffmpeg/libavformat/segafilm.c index 8a0e8bc3c6b..6b3ad52446a 100644 --- a/chromium/third_party/ffmpeg/libavformat/segafilm.c +++ b/chromium/third_party/ffmpeg/libavformat/segafilm.c @@ -75,13 +75,22 @@ static int film_probe(AVProbeData *p) return AVPROBE_SCORE_MAX; } +static int film_read_close(AVFormatContext *s) +{ + FilmDemuxContext *film = s->priv_data; + + av_freep(&film->sample_table); + + return 0; +} + static int film_read_header(AVFormatContext *s) { FilmDemuxContext *film = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; unsigned char scratch[256]; - int i; + int i, ret; unsigned int data_offset; unsigned int audio_frame_counter; @@ -206,14 +215,16 @@ static int film_read_header(AVFormatContext *s) for (i = 0; i < film->sample_count; i++) { /* load the next sample record and transfer it to an internal struct */ if (avio_read(pb, scratch, 16) != 16) { - av_freep(&film->sample_table); - return AVERROR(EIO); + ret = AVERROR(EIO); + goto fail; } film->sample_table[i].sample_offset = data_offset + AV_RB32(&scratch[0]); film->sample_table[i].sample_size = AV_RB32(&scratch[4]); - if (film->sample_table[i].sample_size > INT_MAX / 4) - return AVERROR_INVALIDDATA; + if (film->sample_table[i].sample_size > INT_MAX / 4) { + ret = AVERROR_INVALIDDATA; + goto fail; + } if (AV_RB32(&scratch[8]) == 0xFFFFFFFF) { film->sample_table[i].stream = film->audio_stream_index; film->sample_table[i].pts = audio_frame_counter; @@ -234,6 +245,9 @@ static int film_read_header(AVFormatContext *s) film->current_sample = 0; return 0; +fail: + film_read_close(s); + return ret; } static int film_read_packet(AVFormatContext *s, @@ -252,18 +266,10 @@ static int film_read_packet(AVFormatContext *s, /* position the stream (will probably be there anyway) */ avio_seek(pb, sample->sample_offset, SEEK_SET); - /* do a special song and dance when loading FILM Cinepak chunks */ - if ((sample->stream == film->video_stream_index) && - (film->video_type == AV_CODEC_ID_CINEPAK)) { - pkt->pos= avio_tell(pb); - if (av_new_packet(pkt, sample->sample_size)) - return AVERROR(ENOMEM); - avio_read(pb, pkt->data, sample->sample_size); - } else { - ret= av_get_packet(pb, pkt, sample->sample_size); - if (ret != sample->sample_size) - ret = AVERROR(EIO); - } + + ret= av_get_packet(pb, pkt, sample->sample_size); + if (ret != sample->sample_size) + ret = AVERROR(EIO); pkt->stream_index = sample->stream; pkt->pts = sample->pts; @@ -273,15 +279,6 @@ static int film_read_packet(AVFormatContext *s, return ret; } -static int film_read_close(AVFormatContext *s) -{ - FilmDemuxContext *film = s->priv_data; - - av_freep(&film->sample_table); - - return 0; -} - AVInputFormat ff_segafilm_demuxer = { .name = "film_cpk", .long_name = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"), diff --git a/chromium/third_party/ffmpeg/libavformat/segment.c b/chromium/third_party/ffmpeg/libavformat/segment.c index f07f464f71c..fe84f2710da 100644 --- a/chromium/third_party/ffmpeg/libavformat/segment.c +++ b/chromium/third_party/ffmpeg/libavformat/segment.c @@ -65,6 +65,7 @@ typedef struct { const AVClass *class; /**< Class for private options. */ int segment_idx; ///< index of the segment file to write, starting from 0 int segment_idx_wrap; ///< number after which the index wraps + int segment_idx_wrap_nb; ///< number of time the index has wraped int segment_count; ///< number of segment files already written AVOutputFormat *oformat; AVFormatContext *avf; @@ -72,7 +73,7 @@ typedef struct { char *list; ///< filename for the segment list file int list_flags; ///< flags affecting list generation int list_size; ///< number of entries for the segment list file - char *list_entry_prefix; ///< prefix to add to list entry filenames + char *entry_prefix; ///< prefix to add to list entry filenames ListType list_type; ///< set the list type AVIOContext *list_pb; ///< list file put-byte context char *time_str; ///< segment duration specification string @@ -171,14 +172,14 @@ static int set_segment_filename(AVFormatContext *s) /* copy modified name in list entry */ size = strlen(av_basename(oc->filename)) + 1; - if (seg->list_entry_prefix) - size += strlen(seg->list_entry_prefix); + if (seg->entry_prefix) + size += strlen(seg->entry_prefix); seg->cur_entry.filename = av_mallocz(size); if (!seg->cur_entry.filename) return AVERROR(ENOMEM); snprintf(seg->cur_entry.filename, size, "%s%s", - seg->list_entry_prefix ? seg->list_entry_prefix : "", + seg->entry_prefix ? seg->entry_prefix : "", av_basename(oc->filename)); return 0; @@ -199,6 +200,9 @@ static int segment_start(AVFormatContext *s, int write_header) } seg->segment_idx++; + if ((seg->segment_idx_wrap) && (seg->segment_idx%seg->segment_idx_wrap == 0)) + seg->segment_idx_wrap_nb++; + if ((err = set_segment_filename(s)) < 0) return err; @@ -242,6 +246,9 @@ static int segment_list_open(AVFormatContext *s) avio_printf(seg->list_pb, "#EXT-X-ALLOW-CACHE:%s\n", seg->list_flags & SEGMENT_LIST_FLAG_CACHE ? "YES" : "NO"); + av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n", + seg->segment_list_entries->index); + for (entry = seg->segment_list_entries; entry; entry = entry->next) max_duration = FFMAX(max_duration, entry->end_time - entry->start_time); avio_printf(seg->list_pb, "#EXT-X-TARGETDURATION:%"PRId64"\n", (int64_t)ceil(max_duration)); @@ -366,7 +373,7 @@ static int parse_times(void *log_ctx, int64_t **times, int *nb_times, if (*p == ',') (*nb_times)++; - *times = av_malloc(sizeof(**times) * *nb_times); + *times = av_malloc_array(*nb_times, sizeof(**times)); if (!*times) { av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced times array\n"); FAIL(AVERROR(ENOMEM)); @@ -424,7 +431,7 @@ static int parse_frames(void *log_ctx, int **frames, int *nb_frames, if (*p == ',') (*nb_frames)++; - *frames = av_malloc(sizeof(**frames) * *nb_frames); + *frames = av_malloc_array(*nb_frames, sizeof(**frames)); if (!*frames) { av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced frames array\n"); FAIL(AVERROR(ENOMEM)); @@ -657,7 +664,6 @@ fail: static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) { SegmentContext *seg = s->priv_data; - AVFormatContext *oc = seg->avf; AVStream *st = s->streams[pkt->stream_index]; int64_t end_pts = INT64_MAX, offset; int start_frame = INT_MAX; @@ -690,9 +696,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) if ((ret = segment_start(s, seg->individual_header_trailer)) < 0) goto fail; - oc = seg->avf; - - seg->cur_entry.index = seg->segment_idx; + seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap*seg->segment_idx_wrap_nb; seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base); seg->cur_entry.start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q); } else if (pkt->pts != AV_NOPTS_VALUE) { @@ -701,7 +705,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) } if (seg->is_first_pkt) { - av_log(s, AV_LOG_DEBUG, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", + av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", seg->avf->filename, pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count); seg->is_first_pkt = 0; @@ -725,18 +729,12 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - ret = ff_write_chained(oc, pkt->stream_index, pkt, s); + ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s); fail: if (pkt->stream_index == seg->reference_stream_index) seg->frame_count++; - if (ret < 0) { - if (seg->list) - avio_close(seg->list_pb); - avformat_free_context(oc); - } - return ret; } @@ -788,7 +786,6 @@ static const AVOption options[] = { { "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"}, { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, - { "segment_list_entry_prefix", "set prefix to prepend to each list entry filename", OFFSET(list_entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_TYPE_UNDEFINED}, -1, LIST_TYPE_NB-1, E, "list_type" }, { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, E, "list_type" }, @@ -803,7 +800,9 @@ static const AVOption options[] = { { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "segment_list_entry_prefix", "set base url prefix for segments", OFFSET(entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "segment_wrap_number", "set the number of wrap before the first segment", OFFSET(segment_idx_wrap_nb), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, { "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, diff --git a/chromium/third_party/ffmpeg/libavformat/sierravmd.c b/chromium/third_party/ffmpeg/libavformat/sierravmd.c index 8749ec1640c..9bd42b4e78a 100644 --- a/chromium/third_party/ffmpeg/libavformat/sierravmd.c +++ b/chromium/third_party/ffmpeg/libavformat/sierravmd.c @@ -204,7 +204,12 @@ static int vmd_read_header(AVFormatContext *s) int type; uint32_t size; - avio_read(pb, chunk, BYTES_PER_FRAME_RECORD); + if ((ret = avio_read(pb, chunk, BYTES_PER_FRAME_RECORD)) != BYTES_PER_FRAME_RECORD) { + av_log(s, AV_LOG_ERROR, "Failed to read frame record\n"); + if (ret >= 0) + ret = AVERROR_INVALIDDATA; + goto error; + } type = chunk[0]; size = AV_RL32(&chunk[2]); if (size > INT_MAX / 2) { diff --git a/chromium/third_party/ffmpeg/libavformat/siff.c b/chromium/third_party/ffmpeg/libavformat/siff.c index c8b68abe301..8da6c2f67a7 100644 --- a/chromium/third_party/ffmpeg/libavformat/siff.c +++ b/chromium/third_party/ffmpeg/libavformat/siff.c @@ -216,7 +216,10 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt) AV_WL16(pkt->data, c->flags); if (c->gmcsize) memcpy(pkt->data + 2, c->gmc, c->gmcsize); - avio_read(s->pb, pkt->data + 2 + c->gmcsize, size); + if (avio_read(s->pb, pkt->data + 2 + c->gmcsize, size) != size) { + av_free_packet(pkt); + return AVERROR_INVALIDDATA; + } pkt->stream_index = 0; c->curstrm = -1; }else{ diff --git a/chromium/third_party/ffmpeg/libavformat/smacker.c b/chromium/third_party/ffmpeg/libavformat/smacker.c index 0d38588e21f..46215ee73d3 100644 --- a/chromium/third_party/ffmpeg/libavformat/smacker.c +++ b/chromium/third_party/ffmpeg/libavformat/smacker.c @@ -23,6 +23,8 @@ * Based on http://wiki.multimedia.cx/index.php?title=Smacker */ +#include <inttypes.h> + #include "libavutil/bswap.h" #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" @@ -142,7 +144,7 @@ static int smacker_read_header(AVFormatContext *s) smk->pad = avio_rl32(pb); /* setup data */ if(smk->frames > 0xFFFFFF) { - av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames); + av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n", smk->frames); return AVERROR_INVALIDDATA; } smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size)); @@ -221,7 +223,9 @@ static int smacker_read_header(AVFormatContext *s) /* load trees to extradata, they will be unpacked by decoder */ if(ff_alloc_extradata(st->codec, smk->treesize + 16)){ - av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); + av_log(s, AV_LOG_ERROR, + "Cannot allocate %"PRIu32" bytes of extradata\n", + smk->treesize + 16); av_freep(&smk->frm_size); av_freep(&smk->frm_flags); return AVERROR(ENOMEM); diff --git a/chromium/third_party/ffmpeg/libavformat/smjpegdec.c b/chromium/third_party/ffmpeg/libavformat/smjpegdec.c index 38ac2fb0861..e4c7a9b890f 100644 --- a/chromium/third_party/ffmpeg/libavformat/smjpegdec.c +++ b/chromium/third_party/ffmpeg/libavformat/smjpegdec.c @@ -24,6 +24,8 @@ * This is a demuxer for Loki SDL Motion JPEG files */ +#include <inttypes.h> + #include "avformat.h" #include "internal.h" #include "riff.h" @@ -52,7 +54,7 @@ static int smjpeg_read_header(AVFormatContext *s) avio_skip(pb, 8); // magic version = avio_rb32(pb); if (version) - avpriv_request_sample(s, "Unknown version %d", version); + avpriv_request_sample(s, "Unknown version %"PRIu32, version); duration = avio_rb32(pb); // in msec @@ -124,7 +126,7 @@ static int smjpeg_read_header(AVFormatContext *s) case SMJPEG_HEND: return 0; default: - av_log(s, AV_LOG_ERROR, "unknown header %x\n", htype); + av_log(s, AV_LOG_ERROR, "unknown header %"PRIx32"\n", htype); return AVERROR_INVALIDDATA; } } @@ -164,7 +166,7 @@ static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) ret = AVERROR_EOF; break; default: - av_log(s, AV_LOG_ERROR, "unknown chunk %x\n", dtype); + av_log(s, AV_LOG_ERROR, "unknown chunk %"PRIx32"\n", dtype); ret = AVERROR_INVALIDDATA; break; } diff --git a/chromium/third_party/ffmpeg/libavformat/smush.c b/chromium/third_party/ffmpeg/libavformat/smush.c index e9c1937398d..a33d50915a7 100644 --- a/chromium/third_party/ffmpeg/libavformat/smush.c +++ b/chromium/third_party/ffmpeg/libavformat/smush.c @@ -20,11 +20,12 @@ */ #include "libavutil/intreadwrite.h" + #include "avformat.h" -#include "internal.h" #include "avio.h" +#include "internal.h" -typedef struct { +typedef struct SMUSHContext { int version; int audio_stream_index; int video_stream_index; @@ -32,9 +33,9 @@ typedef struct { static int smush_read_probe(AVProbeData *p) { - if (((AV_RL32(p->buf) == MKTAG('S', 'A', 'N', 'M') && + if (((AV_RL32(p->buf) == MKTAG('S', 'A', 'N', 'M') && AV_RL32(p->buf + 8) == MKTAG('S', 'H', 'D', 'R')) || - (AV_RL32(p->buf) == MKTAG('A', 'N', 'I', 'M') && + (AV_RL32(p->buf) == MKTAG('A', 'N', 'I', 'M') && AV_RL32(p->buf + 8) == MKTAG('A', 'H', 'D', 'R')))) { return AVPROBE_SCORE_MAX; } @@ -65,6 +66,8 @@ static int smush_read_header(AVFormatContext *ctx) smush->version = 0; subversion = avio_rl16(pb); nframes = avio_rl16(pb); + if (!nframes) + return AVERROR_INVALIDDATA; avio_skip(pb, 2); // skip pad @@ -72,7 +75,7 @@ static int smush_read_header(AVFormatContext *ctx) palette[i] = avio_rb24(pb); avio_skip(pb, size - (3 * 256 + 6)); - } else if (magic == MKBETAG('S', 'A', 'N', 'M') ) { + } else if (magic == MKBETAG('S', 'A', 'N', 'M')) { if (avio_rb32(pb) != MKBETAG('S', 'H', 'D', 'R')) return AVERROR_INVALIDDATA; @@ -81,8 +84,11 @@ static int smush_read_header(AVFormatContext *ctx) return AVERROR_INVALIDDATA; smush->version = 1; - subversion = avio_rl16(pb); + subversion = avio_rl16(pb); nframes = avio_rl32(pb); + if (!nframes) + return AVERROR_INVALIDDATA; + avio_skip(pb, 2); // skip pad width = avio_rl16(pb); height = avio_rl16(pb); @@ -101,12 +107,18 @@ static int smush_read_header(AVFormatContext *ctx) sig = avio_rb32(pb); chunk_size = avio_rb32(pb); - read += 8; + read += 8; switch (sig) { case MKBETAG('W', 'a', 'v', 'e'): got_audio = 1; sample_rate = avio_rl32(pb); - channels = avio_rl32(pb); + if (!sample_rate) + return AVERROR_INVALIDDATA; + + channels = avio_rl32(pb); + if (!channels) + return AVERROR_INVALIDDATA; + avio_skip(pb, chunk_size - 8); read += chunk_size; break; @@ -133,17 +145,18 @@ static int smush_read_header(AVFormatContext *ctx) smush->video_stream_index = vst->index; + avpriv_set_pts_info(vst, 64, 1, 15); + vst->start_time = 0; vst->duration = vst->nb_frames = nframes; + vst->avg_frame_rate = av_inv_q(vst->time_base); vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_id = AV_CODEC_ID_SANM; vst->codec->codec_tag = 0; vst->codec->width = width; vst->codec->height = height; - avpriv_set_pts_info(vst, 64, 66667, 1000000); - if (!smush->version) { if (ff_alloc_extradata(vst->codec, 1024 + 2)) return AVERROR(ENOMEM); @@ -162,7 +175,7 @@ static int smush_read_header(AVFormatContext *ctx) ast->start_time = 0; ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->codec->codec_id = AV_CODEC_ID_VIMA; + ast->codec->codec_id = AV_CODEC_ID_ADPCM_VIMA; ast->codec->codec_tag = 0; ast->codec->sample_rate = sample_rate; ast->codec->channels = channels; @@ -178,6 +191,7 @@ static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt) SMUSHContext *smush = ctx->priv_data; AVIOContext *pb = ctx->pb; int done = 0; + int ret; while (!done) { uint32_t sig, size; @@ -185,22 +199,22 @@ static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt) if (url_feof(pb)) return AVERROR_EOF; - sig = avio_rb32(pb); - size = avio_rb32(pb); + sig = avio_rb32(pb); + size = avio_rb32(pb); switch (sig) { case MKBETAG('F', 'R', 'M', 'E'): if (smush->version) break; - if (av_get_packet(pb, pkt, size) < 0) - return AVERROR(EIO); + if ((ret = av_get_packet(pb, pkt, size)) < 0) + return ret; pkt->stream_index = smush->video_stream_index; done = 1; break; case MKBETAG('B', 'l', '1', '6'): - if (av_get_packet(pb, pkt, size) < 0) - return AVERROR(EIO); + if ((ret = av_get_packet(pb, pkt, size)) < 0) + return ret; pkt->stream_index = smush->video_stream_index; pkt->duration = 1; @@ -214,7 +228,7 @@ static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt) pkt->stream_index = smush->audio_stream_index; pkt->flags |= AV_PKT_FLAG_KEY; - pkt->duration = AV_RB32(pkt->data); + pkt->duration = AV_RB32(pkt->data); if (pkt->duration == 0xFFFFFFFFu) pkt->duration = AV_RB32(pkt->data + 8); done = 1; diff --git a/chromium/third_party/ffmpeg/libavformat/spdifenc.c b/chromium/third_party/ffmpeg/libavformat/spdifenc.c index 210d63f39cd..18afd428019 100644 --- a/chromium/third_party/ffmpeg/libavformat/spdifenc.c +++ b/chromium/third_party/ffmpeg/libavformat/spdifenc.c @@ -44,6 +44,8 @@ * dependent from data-type (spaces between packets are filled by zeros) */ +#include <inttypes.h> + #include "avformat.h" #include "avio_internal.h" #include "spdif.h" @@ -274,7 +276,7 @@ static int spdif_header_dts(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "stray DTS-HD frame\n"); return AVERROR_INVALIDDATA; default: - av_log(s, AV_LOG_ERROR, "bad DTS syncword 0x%x\n", syncword_dts); + av_log(s, AV_LOG_ERROR, "bad DTS syncword 0x%"PRIx32"\n", syncword_dts); return AVERROR_INVALIDDATA; } blocks++; @@ -369,8 +371,8 @@ static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) ctx->data_type = IEC61937_MPEG2_AAC_LSF_4096; break; default: - av_log(s, AV_LOG_ERROR, "%i samples in AAC frame not supported\n", - hdr.samples); + av_log(s, AV_LOG_ERROR, + "%"PRIu32" samples in AAC frame not supported\n", hdr.samples); return AVERROR(EINVAL); } //TODO Data type dependent info (LC profile/SBR) diff --git a/chromium/third_party/ffmpeg/libavformat/subfile.c b/chromium/third_party/ffmpeg/libavformat/subfile.c new file mode 100644 index 00000000000..0e84384600b --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/subfile.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2014 Nicolas George + * + * 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/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "avformat.h" +#include "url.h" + +typedef struct SubfileContext { + const AVClass *class; + URLContext *h; + int64_t start; + int64_t end; + int64_t pos; +} SubfileContext; + +#define OFFSET(field) offsetof(SubfileContext, field) +#define D AV_OPT_FLAG_DECODING_PARAM + +static const AVOption subfile_options[] = { + { "start", "start offset", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, + { "end", "end offset", OFFSET(end), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D }, + { NULL } +}; + +#undef OFFSET +#undef D + +static const AVClass subfile_class = { + .class_name = "subfile", + .item_name = av_default_item_name, + .option = subfile_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static int slave_seek(URLContext *h) +{ + SubfileContext *c = h->priv_data; + int64_t ret; + + if ((ret = ffurl_seek(c->h, c->pos, SEEK_SET)) != c->pos) { + if (ret >= 0) + ret = AVERROR_BUG; + av_log(h, AV_LOG_ERROR, "Impossible to seek in file: %s\n", + av_err2str(ret)); + return ret; + } + return 0; +} + +static int subfile_open(URLContext *h, const char *filename, int flags, + AVDictionary **options) +{ + SubfileContext *c = h->priv_data; + int ret; + + if (c->end <= c->start) { + av_log(h, AV_LOG_ERROR, "end before start\n"); + return AVERROR(EINVAL); + } + av_strstart(filename, "subfile:", &filename); + ret = ffurl_open(&c->h, filename, flags, &h->interrupt_callback, options); + if (ret < 0) + return ret; + c->pos = c->start; + if ((ret = slave_seek(h)) < 0) { + ffurl_close(c->h); + return ret; + } + return 0; +} + +static int subfile_close(URLContext *h) +{ + SubfileContext *c = h->priv_data; + return ffurl_close(c->h); +} + +static int subfile_read(URLContext *h, unsigned char *buf, int size) +{ + SubfileContext *c = h->priv_data; + int64_t rest = c->end - c->pos; + int ret; + + if (rest <= 0) + return 0; + size = FFMIN(size, rest); + ret = ffurl_read(c->h, buf, size); + if (ret >= 0) + c->pos += ret; + return ret; +} + +static int64_t subfile_seek(URLContext *h, int64_t pos, int whence) +{ + SubfileContext *c = h->priv_data; + int64_t new_pos = -1; + int ret; + + if (whence == AVSEEK_SIZE) + return c->end - c->start; + switch (whence) { + case SEEK_SET: + new_pos = c->start + pos; + break; + case SEEK_CUR: + new_pos += pos; + break; + case SEEK_END: + new_pos = c->end + c->pos; + break; + } + if (new_pos < c->start) + return AVERROR(EINVAL); + c->pos = new_pos; + if ((ret = slave_seek(h)) < 0) + return ret; + return c->pos - c->start; +} + +URLProtocol ff_subfile_protocol = { + .name = "subfile", + .url_open2 = subfile_open, + .url_read = subfile_read, + .url_seek = subfile_seek, + .url_close = subfile_close, + .priv_data_size = sizeof(SubfileContext), + .priv_data_class = &subfile_class, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/swfdec.c b/chromium/third_party/ffmpeg/libavformat/swfdec.c index e6ceec818af..c95b18ec6cb 100644 --- a/chromium/third_party/ffmpeg/libavformat/swfdec.c +++ b/chromium/third_party/ffmpeg/libavformat/swfdec.c @@ -446,16 +446,30 @@ bitmap_end_skip: goto skip; if ((res = av_new_packet(pkt, len)) < 0) return res; - avio_read(pb, pkt->data, 4); + if (avio_read(pb, pkt->data, 4) != 4) { + av_free_packet(pkt); + return AVERROR_INVALIDDATA; + } if (AV_RB32(pkt->data) == 0xffd8ffd9 || AV_RB32(pkt->data) == 0xffd9ffd8) { /* old SWF files containing SOI/EOI as data start */ /* files created by swink have reversed tag */ pkt->size -= 4; - avio_read(pb, pkt->data, pkt->size); + memset(pkt->data+pkt->size, 0, 4); + res = avio_read(pb, pkt->data, pkt->size); } else { - avio_read(pb, pkt->data + 4, pkt->size - 4); + res = avio_read(pb, pkt->data + 4, pkt->size - 4); + if (res >= 0) + res += 4; + } + if (res != pkt->size) { + if (res < 0) { + av_free_packet(pkt); + return res; + } + av_shrink_packet(pkt, res); } + pkt->pos = pos; pkt->stream_index = st->index; return pkt->size; diff --git a/chromium/third_party/ffmpeg/libavformat/swfenc.c b/chromium/third_party/ffmpeg/libavformat/swfenc.c index 8d9cf0c246c..402f21ef40a 100644 --- a/chromium/third_party/ffmpeg/libavformat/swfenc.c +++ b/chromium/third_party/ffmpeg/libavformat/swfenc.c @@ -490,8 +490,7 @@ static int swf_write_trailer(AVFormatContext *s) if (enc->codec_type == AVMEDIA_TYPE_VIDEO) video_enc = enc; else { - av_fifo_free(swf->audio_fifo); - swf->audio_fifo = NULL; + av_fifo_freep(&swf->audio_fifo); } } diff --git a/chromium/third_party/ffmpeg/libavformat/takdec.c b/chromium/third_party/ffmpeg/libavformat/takdec.c index 2ed8a1e3b71..4888a776305 100644 --- a/chromium/third_party/ffmpeg/libavformat/takdec.c +++ b/chromium/third_party/ffmpeg/libavformat/takdec.c @@ -85,6 +85,7 @@ static int tak_read_header(AVFormatContext *s) buffer = av_malloc(size - 3 + FF_INPUT_BUFFER_PADDING_SIZE); if (!buffer) return AVERROR(ENOMEM); + memset(buffer + size - 3, 0, FF_INPUT_BUFFER_PADDING_SIZE); ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U); if (avio_read(pb, buffer, size - 3) != size - 3) { diff --git a/chromium/third_party/ffmpeg/libavformat/tcp.c b/chromium/third_party/ffmpeg/libavformat/tcp.c index 634d99d0d02..e457fba94fa 100644 --- a/chromium/third_party/ffmpeg/libavformat/tcp.c +++ b/chromium/third_party/ffmpeg/libavformat/tcp.c @@ -44,8 +44,8 @@ typedef struct TCPContext { #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { {"listen", "listen on port instead of connecting", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, -{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, -{"listen_timeout", "connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, +{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, +{"listen_timeout", "set connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, {NULL} }; @@ -79,8 +79,13 @@ static int tcp_open(URLContext *h, const char *uri, int flags) } p = strchr(uri, '?'); if (p) { - if (av_find_info_tag(buf, sizeof(buf), "listen", p)) - s->listen = 1; + if (av_find_info_tag(buf, sizeof(buf), "listen", p)) { + char *endptr = NULL; + s->listen = strtol(buf, &endptr, 10); + /* assume if no digits were found it is a request to enable it */ + if (buf == endptr) + s->listen = 1; + } if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { s->rw_timeout = strtol(buf, NULL, 10); } diff --git a/chromium/third_party/ffmpeg/libavformat/tee.c b/chromium/third_party/ffmpeg/libavformat/tee.c index 12ea0ea27d6..f26e15742a5 100644 --- a/chromium/third_party/ffmpeg/libavformat/tee.c +++ b/chromium/third_party/ffmpeg/libavformat/tee.c @@ -410,18 +410,17 @@ static int filter_packet(void *log_ctx, AVPacket *pkt, if (!new_pkt.buf) break; } + if (ret < 0) { + av_log(log_ctx, AV_LOG_ERROR, + "Failed to filter bitstream with filter %s for stream %d in file '%s' with codec %s\n", + bsf_ctx->filter->name, pkt->stream_index, fmt_ctx->filename, + avcodec_get_name(enc_ctx->codec_id)); + } *pkt = new_pkt; bsf_ctx = bsf_ctx->next; } - if (ret < 0) { - av_log(log_ctx, AV_LOG_ERROR, - "Failed to filter bitstream with filter %s for stream %d in file '%s' with codec %s\n", - bsf_ctx->filter->name, pkt->stream_index, fmt_ctx->filename, - avcodec_get_name(enc_ctx->codec_id)); - } - return ret; } diff --git a/chromium/third_party/ffmpeg/libavformat/tls.c b/chromium/third_party/ffmpeg/libavformat/tls.c index 5da82db7967..7fd18cfce0c 100644 --- a/chromium/third_party/ffmpeg/libavformat/tls.c +++ b/chromium/third_party/ffmpeg/libavformat/tls.c @@ -24,6 +24,9 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" +#include "network.h" +#include "os_support.h" +#include "internal.h" #if CONFIG_GNUTLS #include <gnutls/gnutls.h> #include <gnutls/x509.h> @@ -50,9 +53,6 @@ SSL_CTX_free(c->ctx); \ } while (0) #endif -#include "network.h" -#include "os_support.h" -#include "internal.h" #if HAVE_POLL_H #include <poll.h> #endif diff --git a/chromium/third_party/ffmpeg/libavformat/txd.c b/chromium/third_party/ffmpeg/libavformat/txd.c index 194945bbc8f..400f2cc54bd 100644 --- a/chromium/third_party/ffmpeg/libavformat/txd.c +++ b/chromium/third_party/ffmpeg/libavformat/txd.c @@ -21,6 +21,7 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" +#include "internal.h" #define TXD_FILE 0x16 #define TXD_INFO 0x01 @@ -45,8 +46,8 @@ static int txd_read_header(AVFormatContext *s) { return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_TXD; - st->codec->time_base.den = 5; - st->codec->time_base.num = 1; + avpriv_set_pts_info(st, 64, 1, 5); + st->avg_frame_rate = av_inv_q(st->time_base); /* the parameters will be extracted from the compressed bitstream */ return 0; diff --git a/chromium/third_party/ffmpeg/libavformat/udp.c b/chromium/third_party/ffmpeg/libavformat/udp.c index 3c0d6bf0123..91b411e679a 100644 --- a/chromium/third_party/ffmpeg/libavformat/udp.c +++ b/chromium/third_party/ffmpeg/libavformat/udp.c @@ -62,6 +62,7 @@ typedef struct { int ttl; int buffer_size; int is_multicast; + int is_broadcast; int local_port; int reuse_socket; int overrun_nonfatal; @@ -84,23 +85,25 @@ typedef struct { char *local_addr; int packet_size; int timeout; + struct sockaddr_storage local_addr_storage; } UDPContext; #define OFFSET(x) offsetof(UDPContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { -{"buffer_size", "Socket buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, -{"localport", "Set local port to bind to", OFFSET(local_port), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, -{"localaddr", "Choose local IP address", OFFSET(local_addr), AV_OPT_TYPE_STRING, {.str = ""}, 0, 0, D|E }, -{"pkt_size", "Set size of UDP packets", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = 1472}, 0, INT_MAX, D|E }, -{"reuse", "Explicitly allow or disallow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, -{"ttl", "Set the time to live value (for multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, {.i64 = 16}, 0, INT_MAX, E }, -{"connect", "Should connect() be called on socket", OFFSET(is_connected), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, +{"buffer_size", "set packet buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, +{"localport", "set local port to bind to", OFFSET(local_port), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, +{"localaddr", "choose local IP address", OFFSET(local_addr), AV_OPT_TYPE_STRING, {.str = ""}, 0, 0, D|E }, +{"pkt_size", "set size of UDP packets", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = 1472}, 0, INT_MAX, D|E }, +{"reuse", "explicitly allow or disallow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, +{"broadcast", "explicitly allow or disallow broadcast destination", OFFSET(is_broadcast), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E }, +{"ttl", "set the time to live value (for multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, {.i64 = 16}, 0, INT_MAX, E }, +{"connect", "set if connect() should be called on socket", OFFSET(is_connected), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, /* TODO 'sources', 'block' option */ -{"fifo_size", "Set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes", OFFSET(circular_buffer_size), AV_OPT_TYPE_INT, {.i64 = 7*4096}, 0, INT_MAX, D }, -{"overrun_nonfatal", "Survive in case of UDP receiving circular buffer overrun", OFFSET(overrun_nonfatal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, -{"timeout", "In read mode: if no data arrived in more than this time interval, raise error", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, +{"fifo_size", "set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes", OFFSET(circular_buffer_size), AV_OPT_TYPE_INT, {.i64 = 7*4096}, 0, INT_MAX, D }, +{"overrun_nonfatal", "survive in case of UDP receiving circular buffer overrun", OFFSET(overrun_nonfatal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, +{"timeout", "set raise error timeout (only in read mode)", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, {NULL} }; @@ -140,14 +143,17 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL, return 0; } -static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) +static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr) { #ifdef IP_ADD_MEMBERSHIP if (addr->sa_family == AF_INET) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - mreq.imr_interface.s_addr= INADDR_ANY; + if (local_addr) + mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr; + else + mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)"); return -1; @@ -169,14 +175,17 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) return 0; } -static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) +static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr) { #ifdef IP_DROP_MEMBERSHIP if (addr->sa_family == AF_INET) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - mreq.imr_interface.s_addr= INADDR_ANY; + if (local_addr) + mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr; + else + mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)"); return -1; @@ -595,6 +604,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) s->timeout = strtol(buf, NULL, 10); + if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p)) + s->is_broadcast = strtol(buf, NULL, 10); } /* handling needed to support options picking from both AVOption and URL */ s->circular_buffer_size *= 188; @@ -624,6 +635,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_fd < 0) goto fail; + s->local_addr_storage=my_addr; //store for future multicast join + /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ @@ -633,6 +646,11 @@ static int udp_open(URLContext *h, const char *uri, int flags) goto fail; } + if (s->is_broadcast) { + if (setsockopt (udp_fd, SOL_SOCKET, SO_BROADCAST, &(s->is_broadcast), sizeof(s->is_broadcast)) != 0) + goto fail; + } + /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address @@ -668,7 +686,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { - if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) + if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) goto fail; } if (num_exclude_sources) { @@ -686,12 +704,20 @@ static int udp_open(URLContext *h, const char *uri, int flags) goto fail; } } else { - /* set udp recv buffer size to the largest possible udp packet size to - * avoid losing data on OSes that set this too low by default. */ + /* set udp recv buffer size to the requested value (default 64K) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } + len = sizeof(tmp); + if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { + log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); + } else { + av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp); + if(tmp < s->buffer_size) + av_log(h, AV_LOG_WARNING, "attempted to set receive buffer to size %d but it only ended up set as %d", s->buffer_size, tmp); + } + /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } @@ -744,7 +770,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) fail: if (udp_fd >= 0) closesocket(udp_fd); - av_fifo_free(s->fifo); + av_fifo_freep(&s->fifo); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) @@ -838,7 +864,7 @@ static int udp_close(URLContext *h) int ret; if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) - udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); + udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage); closesocket(s->udp_fd); #if HAVE_PTHREAD_CANCEL if (s->thread_started) { @@ -850,7 +876,7 @@ static int udp_close(URLContext *h) pthread_cond_destroy(&s->cond); } #endif - av_fifo_free(s->fifo); + av_fifo_freep(&s->fifo); return 0; } diff --git a/chromium/third_party/ffmpeg/libavformat/uncodedframecrcenc.c b/chromium/third_party/ffmpeg/libavformat/uncodedframecrcenc.c new file mode 100644 index 00000000000..414683fe23c --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/uncodedframecrcenc.c @@ -0,0 +1,172 @@ +/* +* Copyright (c) 2013 Nicolas George +* +* 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/adler32.h" +#include "libavutil/avassert.h" +#include "libavutil/bprint.h" +#include "libavutil/imgutils.h" +#include "libavutil/pixdesc.h" +#include "avformat.h" +#include "internal.h" + +/* Identical to Adler32 when the type is uint8_t. */ +#define DEFINE_CKSUM_LINE(name, type, conv) \ +static void cksum_line_ ## name(unsigned *cksum, void *data, unsigned size) \ +{ \ + type *p = data; \ + unsigned a = *cksum & 0xFFFF, b = *cksum >> 16; \ + for (; size > 0; size--, p++) { \ + a = (a + (unsigned)(conv)) % 65521; \ + b = (b + a) % 65521; \ + } \ + *cksum = a | (b << 16); \ +} + +DEFINE_CKSUM_LINE(u8, uint8_t, *p) +DEFINE_CKSUM_LINE(s16, int16_t, *p + 0x8000) +DEFINE_CKSUM_LINE(s32, int32_t, *p + 0x80000000) +DEFINE_CKSUM_LINE(flt, float, *p * 0x80000000 + 0x80000000) +DEFINE_CKSUM_LINE(dbl, double, *p * 0x80000000 + 0x80000000) + +static void video_frame_cksum(AVBPrint *bp, AVFrame *frame) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int i, y; + uint8_t *data; + int linesize[5] = { 0 }; + + av_bprintf(bp, ", %d x %d", frame->width, frame->height); + if (!desc) { + av_bprintf(bp, ", unknown"); + return; + } + if (av_image_fill_linesizes(linesize, frame->format, frame->width) < 0) + return; + av_bprintf(bp, ", %s", desc->name); + for (i = 0; linesize[i]; i++) { + unsigned cksum = 0; + int h = frame->height; + if ((i == 1 || i == 2) && desc->nb_components >= 3) + h = -((-h) >> desc->log2_chroma_h); + data = frame->data[i]; + for (y = 0; y < h; y++) { + cksum = av_adler32_update(cksum, data, linesize[i]); + data += frame->linesize[i]; + } + av_bprintf(bp, ", 0x%08x", cksum); + } +} + +static void audio_frame_cksum(AVBPrint *bp, AVFrame *frame) +{ + int nb_planes, nb_samples, p; + const char *name; + + nb_planes = av_frame_get_channels(frame); + nb_samples = frame->nb_samples; + if (!av_sample_fmt_is_planar(frame->format)) { + nb_samples *= nb_planes; + nb_planes = 1; + } + name = av_get_sample_fmt_name(frame->format); + av_bprintf(bp, ", %d samples", frame->nb_samples); + av_bprintf(bp, ", %s", name ? name : "unknown"); + for (p = 0; p < nb_planes; p++) { + uint32_t cksum = 0; + void *d = frame->extended_data[p]; + switch (frame->format) { + case AV_SAMPLE_FMT_U8: + case AV_SAMPLE_FMT_U8P: + cksum_line_u8(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S16P: + cksum_line_s16(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_S32P: + cksum_line_s32(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_FLTP: + cksum_line_flt(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_DBLP: + cksum_line_dbl(&cksum, d, nb_samples); + break; + default: + av_assert0(!"reached"); + } + av_bprintf(bp, ", 0x%08x", cksum); + } +} + +static int write_frame(struct AVFormatContext *s, int stream_index, + AVFrame **frame, unsigned flags) +{ + AVBPrint bp; + int ret = 0; + enum AVMediaType type; + const char *type_name; + + if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) + return 0; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&bp, "%d, %10"PRId64"", + stream_index, (*frame)->pts); + type = s->streams[stream_index]->codec->codec_type; + type_name = av_get_media_type_string(type); + av_bprintf(&bp, ", %s", type_name ? type_name : "unknown"); + switch (type) { + case AVMEDIA_TYPE_VIDEO: + video_frame_cksum(&bp, *frame); + break; + case AVMEDIA_TYPE_AUDIO: + audio_frame_cksum(&bp, *frame); + break; + } + + av_bprint_chars(&bp, '\n', 1); + if (av_bprint_is_complete(&bp)) + avio_write(s->pb, bp.str, bp.len); + else + ret = AVERROR(ENOMEM); + av_bprint_finalize(&bp, NULL); + return ret; +} + +static int write_packet(struct AVFormatContext *s, AVPacket *pkt) +{ + return AVERROR(ENOSYS); +} + +AVOutputFormat ff_uncodedframecrc_muxer = { + .name = "uncodedframecrc", + .long_name = NULL_IF_CONFIG_SMALL("uncoded framecrc testing"), + .audio_codec = AV_CODEC_ID_PCM_S16LE, + .video_codec = AV_CODEC_ID_RAWVIDEO, + .write_header = ff_framehash_write_header, + .write_packet = write_packet, + .write_uncoded_frame = write_frame, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/utils.c b/chromium/third_party/ffmpeg/libavformat/utils.c index fc4de4c34eb..d84d6053ffa 100644 --- a/chromium/third_party/ffmpeg/libavformat/utils.c +++ b/chromium/third_party/ffmpeg/libavformat/utils.c @@ -19,36 +19,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#undef NDEBUG +#include <assert.h> +#include <stdarg.h> #include <stdint.h> -#include "avformat.h" -#include "avio_internal.h" -#include "internal.h" -#include "libavcodec/internal.h" -#include "libavcodec/raw.h" -#include "libavcodec/bytestream.h" -#include "libavutil/opt.h" -#include "libavutil/dict.h" -#include "libavutil/internal.h" -#include "libavutil/pixdesc.h" -#include "metadata.h" -#include "id3v2.h" +#include "config.h" + #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/dict.h" +#include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" #include "libavutil/parseutils.h" +#include "libavutil/pixdesc.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" -#include "riff.h" + +#include "libavcodec/bytestream.h" +#include "libavcodec/internal.h" +#include "libavcodec/raw.h" + #include "audiointerleave.h" -#include "url.h" -#include <stdarg.h> +#include "avformat.h" +#include "avio_internal.h" +#include "id3v2.h" +#include "internal.h" +#include "metadata.h" #if CONFIG_NETWORK #include "network.h" #endif - -#undef NDEBUG -#include <assert.h> +#include "riff.h" +#include "url.h" /** * @file @@ -91,10 +94,10 @@ static int64_t wrap_timestamp(AVStream *st, int64_t timestamp) st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) { if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET && timestamp < st->pts_wrap_reference) - return timestamp + (1ULL<<st->pts_wrap_bits); + return timestamp + (1ULL << st->pts_wrap_bits); else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET && timestamp >= st->pts_wrap_reference) - return timestamp - (1ULL<<st->pts_wrap_bits); + return timestamp - (1ULL << st->pts_wrap_bits); } return timestamp; } @@ -103,21 +106,34 @@ MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec) +MAKE_ACCESSORS(AVFormatContext, format, int, metadata_header_padding) +MAKE_ACCESSORS(AVFormatContext, format, void *, opaque) +MAKE_ACCESSORS(AVFormatContext, format, av_format_control_message, control_message_cb) -static AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id) +void av_format_inject_global_side_data(AVFormatContext *s) +{ + int i; + s->internal->inject_global_side_data = 1; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + st->inject_global_side_data = 1; + } +} + +static const AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id) { if (st->codec->codec) return st->codec->codec; - switch(st->codec->codec_type){ + switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: - if(s->video_codec) return s->video_codec; + if (s->video_codec) return s->video_codec; break; case AVMEDIA_TYPE_AUDIO: - if(s->audio_codec) return s->audio_codec; + if (s->audio_codec) return s->audio_codec; break; case AVMEDIA_TYPE_SUBTITLE: - if(s->subtitle_codec) return s->subtitle_codec; + if (s->subtitle_codec) return s->subtitle_codec; break; } @@ -134,28 +150,26 @@ int av_format_get_probe_score(const AVFormatContext *s) int ffio_limit(AVIOContext *s, int size) { - if(s->maxsize>=0){ + if (s->maxsize>= 0) { int64_t remaining= s->maxsize - avio_tell(s); - if(remaining < size){ - int64_t newsize= avio_size(s); - if(!s->maxsize || s->maxsize<newsize) - s->maxsize= newsize - !newsize; + if (remaining < size) { + int64_t newsize = avio_size(s); + if (!s->maxsize || s->maxsize<newsize) + s->maxsize = newsize - !newsize; remaining= s->maxsize - avio_tell(s); remaining= FFMAX(remaining, 0); } - if(s->maxsize>=0 && remaining+1 < size){ + if (s->maxsize>= 0 && remaining+1 < size) { av_log(NULL, remaining ? AV_LOG_ERROR : AV_LOG_DEBUG, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1); - size= remaining+1; + size = remaining+1; } } return size; } -/* - * Read the data in sane-sized chunks and append to pkt. - * Return the number of bytes read or an error. - */ +/* Read the data in sane-sized chunks and append to pkt. + * Return the number of bytes read or an error. */ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) { int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos @@ -166,10 +180,8 @@ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) int prev_size = pkt->size; int read_size; - /* - * When the caller requests a lot of data, limit it to the amount left - * in file or SANE_CHUNK_SIZE when it is not known - */ + /* When the caller requests a lot of data, limit it to the amount + * left in file or SANE_CHUNK_SIZE when it is not known. */ read_size = size; if (read_size > SANE_CHUNK_SIZE/10) { read_size = ffio_limit(s, read_size); @@ -216,18 +228,19 @@ int av_append_packet(AVIOContext *s, AVPacket *pkt, int size) return append_packet_chunked(s, pkt, size); } - int av_filename_number_test(const char *filename) { char buf[1024]; - return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0); + return filename && + (av_get_frame_filename(buf, sizeof(buf), filename, 1) >= 0); } -AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret) +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, + int *score_ret) { AVProbeData lpd = *pd; AVInputFormat *fmt1 = NULL, *fmt; - int score, nodat = 0, score_max=0; + int score, nodat = 0, score_max = 0; const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE]; if (!lpd.buf) @@ -236,9 +249,11 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { int id3len = ff_id3v2_tag_len(lpd.buf); if (lpd.buf_size > id3len + 16) { - lpd.buf += id3len; + lpd.buf += id3len; lpd.buf_size -= id3len; - }else + } else if (id3len >= PROBE_BUF_MAX) { + nodat = 2; + } else nodat = 1; } @@ -249,22 +264,24 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score score = 0; if (fmt1->read_probe) { score = fmt1->read_probe(&lpd); - if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) - score = FFMAX(score, nodat ? AVPROBE_SCORE_EXTENSION / 2 - 1 : 1); + if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) { + if (nodat == 0) score = FFMAX(score, 1); + else if (nodat == 1) score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1); + else score = FFMAX(score, AVPROBE_SCORE_EXTENSION); + } } else if (fmt1->extensions) { - if (av_match_ext(lpd.filename, fmt1->extensions)) { + if (av_match_ext(lpd.filename, fmt1->extensions)) score = AVPROBE_SCORE_EXTENSION; - } } if (score > score_max) { score_max = score; - fmt = fmt1; - }else if (score == score_max) + fmt = fmt1; + } else if (score == score_max) fmt = NULL; } - if(nodat) + if (nodat == 1) score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max); - *score_ret= score_max; + *score_ret = score_max; return fmt; } @@ -272,32 +289,37 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) { int score_ret; - AVInputFormat *fmt= av_probe_input_format3(pd, is_opened, &score_ret); - if(score_ret > *score_max){ - *score_max= score_ret; + AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret); + if (score_ret > *score_max) { + *score_max = score_ret; return fmt; - }else + } else return NULL; } -AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened){ - int score=0; +AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) +{ + int score = 0; return av_probe_input_format2(pd, is_opened, &score); } -static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd) +static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, + AVProbeData *pd) { static const struct { - const char *name; enum AVCodecID id; enum AVMediaType type; + const char *name; + enum AVCodecID id; + enum AVMediaType type; } fmt_id_type[] = { - { "aac" , AV_CODEC_ID_AAC , AVMEDIA_TYPE_AUDIO }, - { "ac3" , AV_CODEC_ID_AC3 , AVMEDIA_TYPE_AUDIO }, - { "dts" , AV_CODEC_ID_DTS , AVMEDIA_TYPE_AUDIO }, - { "eac3" , AV_CODEC_ID_EAC3 , AVMEDIA_TYPE_AUDIO }, - { "h264" , AV_CODEC_ID_H264 , AVMEDIA_TYPE_VIDEO }, - { "loas" , AV_CODEC_ID_AAC_LATM , AVMEDIA_TYPE_AUDIO }, - { "m4v" , AV_CODEC_ID_MPEG4 , AVMEDIA_TYPE_VIDEO }, - { "mp3" , AV_CODEC_ID_MP3 , AVMEDIA_TYPE_AUDIO }, + { "aac", AV_CODEC_ID_AAC, AVMEDIA_TYPE_AUDIO }, + { "ac3", AV_CODEC_ID_AC3, AVMEDIA_TYPE_AUDIO }, + { "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO }, + { "eac3", AV_CODEC_ID_EAC3, AVMEDIA_TYPE_AUDIO }, + { "h264", AV_CODEC_ID_H264, AVMEDIA_TYPE_VIDEO }, + { "hevc", AV_CODEC_ID_HEVC, AVMEDIA_TYPE_VIDEO }, + { "loas", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO }, + { "m4v", AV_CODEC_ID_MPEG4, AVMEDIA_TYPE_VIDEO }, + { "mp3", AV_CODEC_ID_MP3, AVMEDIA_TYPE_AUDIO }, { "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO }, { 0 } }; @@ -306,8 +328,10 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa if (fmt && st->request_probe <= score) { int i; - av_log(s, AV_LOG_DEBUG, "Probe with size=%d, packets=%d detected %s with score=%d\n", - pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets, fmt->name, score); + av_log(s, AV_LOG_DEBUG, + "Probe with size=%d, packets=%d detected %s with score=%d\n", + pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets, + fmt->name, score); for (i = 0; fmt_id_type[i].name; i++) { if (!strcmp(fmt->name, fmt_id_type[i].name)) { st->codec->codec_id = fmt_id_type[i].id; @@ -322,7 +346,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa /************************************************************/ /* input media file */ -int av_demuxer_open(AVFormatContext *ic){ +int av_demuxer_open(AVFormatContext *ic) { int err; if (ic->iformat->read_header) { @@ -342,25 +366,24 @@ int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { - AVProbeData pd = { filename ? filename : "", NULL, -offset }; - unsigned char *buf = NULL; + AVProbeData pd = { filename ? filename : "" }; + uint8_t *buf = NULL; uint8_t *mime_type; int ret = 0, probe_size, buf_offset = 0; int score = 0; - if (!max_probe_size) { + if (!max_probe_size) max_probe_size = PROBE_BUF_MAX; - } else if (max_probe_size > PROBE_BUF_MAX) { + else if (max_probe_size > PROBE_BUF_MAX) max_probe_size = PROBE_BUF_MAX; - } else if (max_probe_size < PROBE_BUF_MIN) { + else if (max_probe_size < PROBE_BUF_MIN) { av_log(logctx, AV_LOG_ERROR, "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN); return AVERROR(EINVAL); } - if (offset >= max_probe_size) { + if (offset >= max_probe_size) return AVERROR(EINVAL); - } if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) { if (!av_strcasecmp(mime_type, "audio/aacp")) { @@ -369,38 +392,44 @@ int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, av_freep(&mime_type); } - for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt; - probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) { - - if (probe_size < offset) { - continue; - } + for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; + probe_size = FFMIN(probe_size << 1, + FFMAX(max_probe_size, probe_size + 1))) { score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; - /* read probe data */ + /* Read probe data. */ if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) return ret; - if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) { - /* fail if error was not end of file, otherwise, lower score */ + if ((ret = avio_read(pb, buf + buf_offset, + probe_size - buf_offset)) < 0) { + /* Fail if error was not end of file, otherwise, lower score. */ if (ret != AVERROR_EOF) { av_free(buf); return ret; } score = 0; - ret = 0; /* error was end of file, nothing read */ + ret = 0; /* error was end of file, nothing read */ } - pd.buf_size = buf_offset += ret; + buf_offset += ret; + if (buf_offset < offset) + continue; + pd.buf_size = buf_offset - offset; pd.buf = &buf[offset]; memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE); - /* guess file format */ + /* Guess file format. */ *fmt = av_probe_input_format2(&pd, 1, &score); - if(*fmt){ - if(score <= AVPROBE_SCORE_RETRY){ //this can only be true in the last iteration - av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!\n", (*fmt)->name, score); - }else - av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); + if (*fmt) { + /* This can only be true in the last iteration. */ + if (score <= AVPROBE_SCORE_RETRY) { + av_log(logctx, AV_LOG_WARNING, + "Format %s detected only with low score of %d, " + "misdetection possible!\n", (*fmt)->name, score); + } else + av_log(logctx, AV_LOG_DEBUG, + "Format %s probed with size=%d and score=%d\n", + (*fmt)->name, probe_size, score); #if 0 FILE *f = fopen("probestat.tmp", "ab"); fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename); @@ -414,8 +443,8 @@ int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, return AVERROR_INVALIDDATA; } - /* rewind. reuse probe buffer to avoid seeking */ - ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size); + /* Rewind. Reuse probe buffer to avoid seeking. */ + ret = ffio_rewind_with_probe_data(pb, &buf, buf_offset); return ret < 0 ? ret : score; } @@ -428,25 +457,26 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, return ret < 0 ? ret : 0; } - -/* open input file and probe the format if necessary */ -static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options) +/* Open input file and probe the format if necessary. */ +static int init_input(AVFormatContext *s, const char *filename, + AVDictionary **options) { int ret; - AVProbeData pd = {filename, NULL, 0}; + AVProbeData pd = { filename, NULL, 0 }; int score = AVPROBE_SCORE_RETRY; if (s->pb) { s->flags |= AVFMT_FLAG_CUSTOM_IO; if (!s->iformat) - return av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, + s, 0, s->probesize); else if (s->iformat->flags & AVFMT_NOFILE) av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " "will be ignored with AVFMT_NOFILE format.\n"); return 0; } - if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || + if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score)))) return score; @@ -455,11 +485,13 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o return ret; if (s->iformat) return 0; - return av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, + s, 0, s->probesize); } static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, - AVPacketList **plast_pktl){ + AVPacketList **plast_pktl) +{ AVPacketList *pktl = av_mallocz(sizeof(AVPacketList)); if (!pktl) return NULL; @@ -469,9 +501,9 @@ static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, else *packet_buffer = pktl; - /* add the packet in the buffered packet list */ + /* Add the packet in the buffered packet list. */ *plast_pktl = pktl; - pktl->pkt= *pkt; + pktl->pkt = *pkt; return &pktl->pkt; } @@ -482,16 +514,18 @@ int avformat_queue_attached_pictures(AVFormatContext *s) if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC && s->streams[i]->discard < AVDISCARD_ALL) { AVPacket copy = s->streams[i]->attached_pic; - copy.buf = av_buffer_ref(copy.buf); + copy.buf = av_buffer_ref(copy.buf); if (!copy.buf) return AVERROR(ENOMEM); - add_to_pktbuf(&s->raw_packet_buffer, ©, &s->raw_packet_buffer_end); + add_to_pktbuf(&s->raw_packet_buffer, ©, + &s->raw_packet_buffer_end); } return 0; } -int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options) +int avformat_open_input(AVFormatContext **ps, const char *filename, + AVInputFormat *fmt, AVDictionary **options) { AVFormatContext *s = *ps; int ret = 0; @@ -500,7 +534,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if (!s && !(s = avformat_alloc_context())) return AVERROR(ENOMEM); - if (!s->av_class){ + if (!s->av_class) { av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n"); return AVERROR(EINVAL); } @@ -518,7 +552,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma s->probe_score = ret; avio_skip(s->pb, s->skip_initial_bytes); - /* check filename in case an image number is expected */ + /* Check filename in case an image number is expected. */ if (s->iformat->flags & AVFMT_NEEDNUMBER) { if (!av_filename_number_test(filename)) { ret = AVERROR(EINVAL); @@ -529,14 +563,14 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma s->duration = s->start_time = AV_NOPTS_VALUE; av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename)); - /* allocate private data */ + /* Allocate private data. */ if (s->iformat->priv_data_size > 0) { if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) { ret = AVERROR(ENOMEM); goto fail; } if (s->iformat->priv_class) { - *(const AVClass**)s->priv_data = s->iformat->priv_class; + *(const AVClass **) s->priv_data = s->iformat->priv_class; av_opt_set_defaults(s->priv_data); if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) goto fail; @@ -545,7 +579,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ if (s->pb) - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0) @@ -554,7 +588,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if (id3v2_extra_meta) { if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || !strcmp(s->iformat->name, "tta")) { - if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) + if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) goto fail; } else av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n"); @@ -590,22 +624,25 @@ fail: static void force_codec_ids(AVFormatContext *s, AVStream *st) { - switch(st->codec->codec_type){ + switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: - if(s->video_codec_id) st->codec->codec_id= s->video_codec_id; + if (s->video_codec_id) + st->codec->codec_id = s->video_codec_id; break; case AVMEDIA_TYPE_AUDIO: - if(s->audio_codec_id) st->codec->codec_id= s->audio_codec_id; + if (s->audio_codec_id) + st->codec->codec_id = s->audio_codec_id; break; case AVMEDIA_TYPE_SUBTITLE: - if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id; + if (s->subtitle_codec_id) + st->codec->codec_id = s->subtitle_codec_id; break; } } static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) { - if(st->request_probe>0){ + if (st->request_probe>0) { AVProbeData *pd = &st->probe_data; int end; av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets); @@ -613,38 +650,38 @@ static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) if (pkt) { uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); - if(!new_buf) { + if (!new_buf) { av_log(s, AV_LOG_WARNING, "Failed to reallocate probe buffer for stream %d\n", st->index); goto no_packet; } pd->buf = new_buf; - memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size); + memcpy(pd->buf + pd->buf_size, pkt->data, pkt->size); pd->buf_size += pkt->size; - memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE); + memset(pd->buf + pd->buf_size, 0, AVPROBE_PADDING_SIZE); } else { no_packet: st->probe_packets = 0; if (!pd->buf_size) { - av_log(s, AV_LOG_WARNING, "nothing to probe for stream %d\n", - st->index); + av_log(s, AV_LOG_WARNING, + "nothing to probe for stream %d\n", st->index); } } end= s->raw_packet_buffer_remaining_size <= 0 - || st->probe_packets<=0; + || st->probe_packets<= 0; - if(end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){ - int score= set_codec_from_probe_data(s, st, pd); - if( (st->codec->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_RETRY) - || end){ - pd->buf_size=0; + if (end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) { + int score = set_codec_from_probe_data(s, st, pd); + if ( (st->codec->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_STREAM_RETRY) + || end) { + pd->buf_size = 0; av_freep(&pd->buf); - st->request_probe= -1; - if(st->codec->codec_id != AV_CODEC_ID_NONE){ + st->request_probe = -1; + if (st->codec->codec_id != AV_CODEC_ID_NONE) { av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index); - }else + } else av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index); } force_codec_ids(s, st); @@ -664,13 +701,13 @@ static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_in ref = pkt->pts; if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow) return 0; - ref &= (1LL<<st->pts_wrap_bits)-1; + ref &= (1LL << st->pts_wrap_bits)-1; // reference time stamp should be 60 s before first time stamp pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num); // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset - pts_wrap_behavior = (ref < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) || - (ref < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? + pts_wrap_behavior = (ref < (1LL << st->pts_wrap_bits) - (1LL << st->pts_wrap_bits-3)) || + (ref < (1LL << st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET; first_program = av_find_program_from_stream(s, NULL, stream_index); @@ -678,7 +715,7 @@ static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_in if (!first_program) { int default_stream_index = av_find_default_stream_index(s); if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) { - for (i=0; i<s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { s->streams[i]->pts_wrap_reference = pts_wrap_reference; s->streams[i]->pts_wrap_behavior = pts_wrap_behavior; } @@ -701,9 +738,9 @@ static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_in // update every program with differing pts_wrap_reference program = first_program; - while(program) { + while (program) { if (program->pts_wrap_reference != pts_wrap_reference) { - for (i=0; i<program->nb_stream_indexes; i++) { + for (i = 0; i<program->nb_stream_indexes; i++) { s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference; s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior; } @@ -722,18 +759,17 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) int ret, i, err; AVStream *st; - for(;;){ + for (;;) { AVPacketList *pktl = s->raw_packet_buffer; if (pktl) { *pkt = pktl->pkt; - st = s->streams[pkt->stream_index]; - if (s->raw_packet_buffer_remaining_size <= 0) { + st = s->streams[pkt->stream_index]; + if (s->raw_packet_buffer_remaining_size <= 0) if ((err = probe_codec(s, st, NULL)) < 0) return err; - } - if(st->request_probe <= 0){ - s->raw_packet_buffer = pktl->next; + if (st->request_probe <= 0) { + s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; av_free(pktl); return 0; @@ -743,16 +779,15 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->data = NULL; pkt->size = 0; av_init_packet(pkt); - ret= s->iformat->read_packet(s, pkt); + ret = s->iformat->read_packet(s, pkt); if (ret < 0) { if (!pktl || ret == AVERROR(EAGAIN)) return ret; for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; - if (st->probe_packets) { + if (st->probe_packets) if ((err = probe_codec(s, st, NULL)) < 0) return err; - } av_assert0(st->request_probe <= 0); } continue; @@ -767,12 +802,12 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } - if(pkt->stream_index >= (unsigned)s->nb_streams){ + if (pkt->stream_index >= (unsigned)s->nb_streams) { av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index); continue; } - st= s->streams[pkt->stream_index]; + st = s->streams[pkt->stream_index]; if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) { // correct first time stamps to negative values @@ -793,7 +828,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (s->use_wallclock_as_timestamps) pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base); - if(!pktl && st->request_probe <= 0) + if (!pktl && st->request_probe <= 0) return ret; add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); @@ -845,7 +880,7 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux) //For WMA we currently have no other means to calculate duration thus we //do it here by assuming CBR, which is true for all known cases. - if(!mux && enc->bit_rate>0 && size>0 && enc->sample_rate>0 && enc->block_align>1) { + if (!mux && enc->bit_rate>0 && size>0 && enc->sample_rate>0 && enc->block_align>1) { if (enc->codec_id == AV_CODEC_ID_WMAV1 || enc->codec_id == AV_CODEC_ID_WMAV2) return ((int64_t)size * 8 * enc->sample_rate) / enc->bit_rate; } @@ -853,7 +888,6 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux) return -1; } - /** * Return the frame duration in seconds. Return 0 if not available. */ @@ -864,15 +898,15 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st, *pnum = 0; *pden = 0; - switch(st->codec->codec_type) { + switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: if (st->r_frame_rate.num && !pc) { *pnum = st->r_frame_rate.den; *pden = st->r_frame_rate.num; - } else if(st->time_base.num*1000LL > st->time_base.den) { + } else if (st->time_base.num * 1000LL > st->time_base.den) { *pnum = st->time_base.num; *pden = st->time_base.den; - }else if(st->codec->time_base.num*1000LL > st->codec->time_base.den){ + } else if (st->codec->time_base.num * 1000LL > st->codec->time_base.den) { *pnum = st->codec->time_base.num; *pden = st->codec->time_base.den; if (pc && pc->repeat_pict) { @@ -881,11 +915,11 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st, else *pnum *= 1 + pc->repeat_pict; } - //If this codec can be interlaced or progressive then we need a parser to compute duration of a packet - //Thus if we have no parser in such case leave duration undefined. - if(st->codec->ticks_per_frame>1 && !pc){ + /* If this codec can be interlaced or progressive then we need + * a parser to compute duration of a packet. Thus if we have + * no parser in such case leave duration undefined. */ + if (st->codec->ticks_per_frame > 1 && !pc) *pnum = *pden = 0; - } } break; case AVMEDIA_TYPE_AUDIO: @@ -900,10 +934,10 @@ void ff_compute_frame_duration(int *pnum, int *pden, AVStream *st, } } -static int is_intra_only(AVCodecContext *enc){ +static int is_intra_only(AVCodecContext *enc) { const AVCodecDescriptor *desc; - if(enc->codec_type != AVMEDIA_TYPE_VIDEO) + if (enc->codec_type != AVMEDIA_TYPE_VIDEO) return 1; desc = av_codec_get_codec_descriptor(enc); @@ -918,17 +952,17 @@ static int is_intra_only(AVCodecContext *enc){ static int has_decode_delay_been_guessed(AVStream *st) { - if(st->codec->codec_id != AV_CODEC_ID_H264) return 1; - if(!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy + if (st->codec->codec_id != AV_CODEC_ID_H264) return 1; + if (!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy return 1; #if CONFIG_H264_DECODER - if(st->codec->has_b_frames && + if (st->codec->has_b_frames && avpriv_h264_has_num_reorder_frames(st->codec) == st->codec->has_b_frames) return 1; #endif - if(st->codec->has_b_frames<3) + if (st->codec->has_b_frames<3) return st->nb_decoded_frames >= 7; - else if(st->codec->has_b_frames<4) + else if (st->codec->has_b_frames<4) return st->nb_decoded_frames >= 18; else return st->nb_decoded_frames >= 20; @@ -938,52 +972,97 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList { if (pktl->next) return pktl->next; - if (pktl == s->parse_queue_end) - return s->packet_buffer; + if (pktl == s->packet_buffer_end) + return s->parse_queue; return NULL; } +static int64_t select_from_pts_buffer(AVStream *st, int64_t *pts_buffer, int64_t dts) { + int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 && + st->codec->codec_id != AV_CODEC_ID_HEVC; + + if(!onein_oneout) { + int delay = st->codec->has_b_frames; + int i; + + if (dts == AV_NOPTS_VALUE) { + int64_t best_score = INT64_MAX; + for (i = 0; i<delay; i++) { + if (st->pts_reorder_error_count[i]) { + int64_t score = st->pts_reorder_error[i] / st->pts_reorder_error_count[i]; + if (score < best_score) { + best_score = score; + dts = pts_buffer[i]; + } + } + } + } else { + for (i = 0; i<delay; i++) { + if (pts_buffer[i] != AV_NOPTS_VALUE) { + int64_t diff = FFABS(pts_buffer[i] - dts) + + (uint64_t)st->pts_reorder_error[i]; + diff = FFMAX(diff, st->pts_reorder_error[i]); + st->pts_reorder_error[i] = diff; + st->pts_reorder_error_count[i]++; + if (st->pts_reorder_error_count[i] > 250) { + st->pts_reorder_error[i] >>= 1; + st->pts_reorder_error_count[i] >>= 1; + } + } + } + } + } + + if (dts == AV_NOPTS_VALUE) + dts = pts_buffer[0]; + + return dts; +} + static void update_initial_timestamps(AVFormatContext *s, int stream_index, int64_t dts, int64_t pts, AVPacket *pkt) { - AVStream *st= s->streams[stream_index]; - AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; + AVStream *st = s->streams[stream_index]; + AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; int64_t pts_buffer[MAX_REORDER_DELAY+1]; int64_t shift; int i, delay; - if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE || is_relative(dts)) + if (st->first_dts != AV_NOPTS_VALUE || + dts == AV_NOPTS_VALUE || + st->cur_dts == AV_NOPTS_VALUE || + is_relative(dts)) return; - delay = st->codec->has_b_frames; - st->first_dts= dts - (st->cur_dts - RELATIVE_TS_BASE); - st->cur_dts= dts; - shift = st->first_dts - RELATIVE_TS_BASE; + delay = st->codec->has_b_frames; + st->first_dts = dts - (st->cur_dts - RELATIVE_TS_BASE); + st->cur_dts = dts; + shift = st->first_dts - RELATIVE_TS_BASE; - for (i=0; i<MAX_REORDER_DELAY+1; i++) + for (i = 0; i<MAX_REORDER_DELAY+1; i++) pts_buffer[i] = AV_NOPTS_VALUE; if (is_relative(pts)) pts += shift; - for(; pktl; pktl= get_next_pkt(s, st, pktl)){ - if(pktl->pkt.stream_index != stream_index) + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { + if (pktl->pkt.stream_index != stream_index) continue; - if(is_relative(pktl->pkt.pts)) + if (is_relative(pktl->pkt.pts)) pktl->pkt.pts += shift; - if(is_relative(pktl->pkt.dts)) + if (is_relative(pktl->pkt.dts)) pktl->pkt.dts += shift; - if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE) - st->start_time= pktl->pkt.pts; + if (st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE) + st->start_time = pktl->pkt.pts; + + if (pktl->pkt.pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) { + pts_buffer[0] = pktl->pkt.pts; + for (i = 0; i<delay && pts_buffer[i] > pts_buffer[i + 1]; i++) + FFSWAP(int64_t, pts_buffer[i], pts_buffer[i + 1]); - if(pktl->pkt.pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)){ - pts_buffer[0]= pktl->pkt.pts; - for(i=0; i<delay && pts_buffer[i] > pts_buffer[i+1]; i++) - FFSWAP(int64_t, pts_buffer[i], pts_buffer[i+1]); - if(pktl->pkt.dts == AV_NOPTS_VALUE) - pktl->pkt.dts= pts_buffer[0]; + pktl->pkt.dts = select_from_pts_buffer(st, pts_buffer, pktl->pkt.dts); } } @@ -994,48 +1073,54 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, static void update_initial_durations(AVFormatContext *s, AVStream *st, int stream_index, int duration) { - AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; - int64_t cur_dts= RELATIVE_TS_BASE; - - if(st->first_dts != AV_NOPTS_VALUE){ - cur_dts= st->first_dts; - for(; pktl; pktl= get_next_pkt(s, st, pktl)){ - if(pktl->pkt.stream_index == stream_index){ - if(pktl->pkt.pts != pktl->pkt.dts || pktl->pkt.dts != AV_NOPTS_VALUE || pktl->pkt.duration) + AVPacketList *pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; + int64_t cur_dts = RELATIVE_TS_BASE; + + if (st->first_dts != AV_NOPTS_VALUE) { + if (st->update_initial_durations_done) + return; + st->update_initial_durations_done = 1; + cur_dts = st->first_dts; + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { + if (pktl->pkt.stream_index == stream_index) { + if (pktl->pkt.pts != pktl->pkt.dts || + pktl->pkt.dts != AV_NOPTS_VALUE || + pktl->pkt.duration) break; cur_dts -= duration; } } - if(pktl && pktl->pkt.dts != st->first_dts) { + if (pktl && pktl->pkt.dts != st->first_dts) { av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s (pts %s, duration %d) in the queue\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts), av_ts2str(pktl->pkt.pts), pktl->pkt.duration); return; } - if(!pktl) { + if (!pktl) { av_log(s, AV_LOG_DEBUG, "first_dts %s but no packet with dts in the queue\n", av_ts2str(st->first_dts)); return; } - pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; + pktl = s->packet_buffer ? s->packet_buffer : s->parse_queue; st->first_dts = cur_dts; - }else if(st->cur_dts != RELATIVE_TS_BASE) + } else if (st->cur_dts != RELATIVE_TS_BASE) return; - for(; pktl; pktl= get_next_pkt(s, st, pktl)){ - if(pktl->pkt.stream_index != stream_index) + for (; pktl; pktl = get_next_pkt(s, st, pktl)) { + if (pktl->pkt.stream_index != stream_index) continue; - if(pktl->pkt.pts == pktl->pkt.dts && (pktl->pkt.dts == AV_NOPTS_VALUE || pktl->pkt.dts == st->first_dts) - && !pktl->pkt.duration){ - pktl->pkt.dts= cur_dts; - if(!st->codec->has_b_frames) - pktl->pkt.pts= cur_dts; + if (pktl->pkt.pts == pktl->pkt.dts && + (pktl->pkt.dts == AV_NOPTS_VALUE || pktl->pkt.dts == st->first_dts) && + !pktl->pkt.duration) { + pktl->pkt.dts = cur_dts; + if (!st->codec->has_b_frames) + pktl->pkt.pts = cur_dts; // if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) pktl->pkt.duration = duration; - }else + } else break; cur_dts = pktl->pkt.dts + pktl->pkt.duration; } - if(!pktl) - st->cur_dts= cur_dts; + if (!pktl) + st->cur_dts = cur_dts; } static void compute_pkt_fields(AVFormatContext *s, AVStream *st, @@ -1043,12 +1128,37 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, { int num, den, presentation_delayed, delay, i; int64_t offset; + AVRational duration; + int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 && + st->codec->codec_id != AV_CODEC_ID_HEVC; if (s->flags & AVFMT_FLAG_NOFILLIN) return; - if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) - pkt->dts= AV_NOPTS_VALUE; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pkt->dts != AV_NOPTS_VALUE) { + if (pkt->dts == pkt->pts && st->last_dts_for_order_check != AV_NOPTS_VALUE) { + if (st->last_dts_for_order_check <= pkt->dts) { + st->dts_ordered++; + } else { + av_log(s, st->dts_misordered ? AV_LOG_DEBUG : AV_LOG_WARNING, + "DTS %"PRIi64" < %"PRIi64" out of order\n", + pkt->dts, + st->last_dts_for_order_check); + st->dts_misordered++; + } + if (st->dts_ordered + st->dts_misordered > 250) { + st->dts_ordered >>= 1; + st->dts_misordered >>= 1; + } + } + + st->last_dts_for_order_check = pkt->dts; + if (st->dts_ordered < 8*st->dts_misordered && pkt->dts == pkt->pts) + pkt->dts = AV_NOPTS_VALUE; + } + + if ((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) + pkt->dts = AV_NOPTS_VALUE; if (pc && pc->pict_type == AV_PICTURE_TYPE_B && !st->codec->has_b_frames) @@ -1056,11 +1166,11 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, st->codec->has_b_frames = 1; /* do we have a video B-frame ? */ - delay= st->codec->has_b_frames; + delay = st->codec->has_b_frames; presentation_delayed = 0; /* XXX: need has_b_frame, but cannot get it if the codec is - not initialized */ + * not initialized */ if (delay && pc && pc->pict_type != AV_PICTURE_TYPE_B) presentation_delayed = 1; @@ -1068,50 +1178,64 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && st->pts_wrap_bits < 63 && pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) { - if(is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > st->cur_dts) { - pkt->dts -= 1LL<<st->pts_wrap_bits; + if (is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits - 1)) > st->cur_dts) { + pkt->dts -= 1LL << st->pts_wrap_bits; } else - pkt->pts += 1LL<<st->pts_wrap_bits; + pkt->pts += 1LL << st->pts_wrap_bits; } - // some mpeg2 in mpeg-ps lack dts (issue171 / input_file.mpg) - // we take the conservative approach and discard both - // Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly. - if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){ + /* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg). + * We take the conservative approach and discard both. + * Note: If this is misbehaving for an H.264 file, then possibly + * presentation_delayed is not set correctly. */ + if (delay == 1 && pkt->dts == pkt->pts && + pkt->dts != AV_NOPTS_VALUE && presentation_delayed) { av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts); - if(strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")) // otherwise we discard correct timestamps for vc1-wmapro.ism - pkt->dts= AV_NOPTS_VALUE; + if ( strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") + && strcmp(s->iformat->name, "flv")) // otherwise we discard correct timestamps for vc1-wmapro.ism + pkt->dts = AV_NOPTS_VALUE; } + duration = av_mul_q((AVRational) {pkt->duration, 1}, st->time_base); if (pkt->duration == 0) { ff_compute_frame_duration(&num, &den, st, pc, pkt); if (den && num) { - pkt->duration = av_rescale_rnd(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num, AV_ROUND_DOWN); + duration = (AVRational) {num, den}; + pkt->duration = av_rescale_rnd(1, + num * (int64_t) st->time_base.den, + den * (int64_t) st->time_base.num, + AV_ROUND_DOWN); } } - if(pkt->duration != 0 && (s->packet_buffer || s->parse_queue)) + + if (pkt->duration != 0 && (s->packet_buffer || s->parse_queue)) update_initial_durations(s, st, pkt->stream_index, pkt->duration); - /* correct timestamps with byte offset if demuxers only have timestamps - on packet boundaries */ - if(pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size){ + /* Correct timestamps with byte offset if demuxers only have timestamps + * on packet boundaries */ + if (pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size) { /* this will estimate bitrate based on this frame's duration and size */ offset = av_rescale(pc->offset, pkt->duration, pkt->size); - if(pkt->pts != AV_NOPTS_VALUE) + if (pkt->pts != AV_NOPTS_VALUE) pkt->pts += offset; - if(pkt->dts != AV_NOPTS_VALUE) + if (pkt->dts != AV_NOPTS_VALUE) pkt->dts += offset; } /* This may be redundant, but it should not hurt. */ - if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts) + if (pkt->dts != AV_NOPTS_VALUE && + pkt->pts != AV_NOPTS_VALUE && + pkt->pts > pkt->dts) presentation_delayed = 1; - av_dlog(NULL, "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d\n", - presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), pkt->stream_index, pc, pkt->duration); - /* interpolate PTS and DTS if they are not present */ - //We skip H264 currently because delay and has_b_frames are not reliably set - if((delay==0 || (delay==1 && pc)) && st->codec->codec_id != AV_CODEC_ID_H264){ + av_dlog(NULL, + "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d\n", + presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), + pkt->stream_index, pc, pkt->duration); + /* Interpolate PTS and DTS if they are not present. We skip H264 + * currently because delay and has_b_frames are not reliably set. */ + if ((delay == 0 || (delay == 1 && pc)) && + onein_oneout) { if (presentation_delayed) { /* DTS = decompression timestamp */ /* PTS = presentation timestamp */ @@ -1121,20 +1245,19 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if (pkt->dts == AV_NOPTS_VALUE) pkt->dts = st->cur_dts; - /* this is tricky: the dts must be incremented by the duration - of the frame we are displaying, i.e. the last I- or P-frame */ + /* This is tricky: the dts must be incremented by the duration + * of the frame we are displaying, i.e. the last I- or P-frame. */ if (st->last_IP_duration == 0) st->last_IP_duration = pkt->duration; - if(pkt->dts != AV_NOPTS_VALUE) + if (pkt->dts != AV_NOPTS_VALUE) st->cur_dts = pkt->dts + st->last_IP_duration; - st->last_IP_duration = pkt->duration; - st->last_IP_pts= pkt->pts; - /* cannot compute PTS if not present (we can compute it only - by knowing the future */ + st->last_IP_duration = pkt->duration; + st->last_IP_pts = pkt->pts; + /* Cannot compute PTS if not present (we can compute it only + * by knowing the future. */ } else if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE || pkt->duration ) { - int duration = pkt->duration; /* presentation is not delayed : PTS and DTS are the same */ if (pkt->pts == AV_NOPTS_VALUE) @@ -1145,21 +1268,22 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pkt->pts = st->cur_dts; pkt->dts = pkt->pts; if (pkt->pts != AV_NOPTS_VALUE) - st->cur_dts = pkt->pts + duration; + st->cur_dts = av_add_stable(st->time_base, pkt->pts, duration, 1); } } - if(pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)){ - st->pts_buffer[0]= pkt->pts; - for(i=0; i<delay && st->pts_buffer[i] > st->pts_buffer[i+1]; i++) - FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i+1]); - if(pkt->dts == AV_NOPTS_VALUE) - pkt->dts= st->pts_buffer[0]; - } - if(st->codec->codec_id == AV_CODEC_ID_H264){ // we skipped it above so we try here - update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); // this should happen on the first packet + if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) { + st->pts_buffer[0] = pkt->pts; + for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++) + FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]); + + pkt->dts = select_from_pts_buffer(st, st->pts_buffer, pkt->dts); } - if(pkt->dts > st->cur_dts) + // We skipped it above so we try here. + if (!onein_oneout) + // This should happen on the first packet + update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); + if (pkt->dts > st->cur_dts) st->cur_dts = pkt->dts; av_dlog(NULL, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s\n", @@ -1184,21 +1308,21 @@ static void free_packet_buffer(AVPacketList **pkt_buf, AVPacketList **pkt_buf_en } /** - * Parse a packet, add all split parts to parse_queue + * Parse a packet, add all split parts to parse_queue. * - * @param pkt packet to parse, NULL when flushing the parser at end of stream + * @param pkt Packet to parse, NULL when flushing the parser at end of stream. */ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) { AVPacket out_pkt = { 0 }, flush_pkt = { 0 }; - AVStream *st = s->streams[stream_index]; - uint8_t *data = pkt ? pkt->data : NULL; - int size = pkt ? pkt->size : 0; + AVStream *st = s->streams[stream_index]; + uint8_t *data = pkt ? pkt->data : NULL; + int size = pkt ? pkt->size : 0; int ret = 0, got_output = 0; if (!pkt) { av_init_packet(&flush_pkt); - pkt = &flush_pkt; + pkt = &flush_pkt; got_output = 1; } else if (!size && st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) { // preserve 0-size sync packets @@ -1209,7 +1333,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) int len; av_init_packet(&out_pkt); - len = av_parser_parse2(st->parser, st->codec, + len = av_parser_parse2(st->parser, st->codec, &out_pkt.data, &out_pkt.size, data, size, pkt->pts, pkt->dts, pkt->pos); @@ -1227,33 +1351,28 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (pkt->side_data) { out_pkt.side_data = pkt->side_data; out_pkt.side_data_elems = pkt->side_data_elems; - pkt->side_data = NULL; - pkt->side_data_elems = 0; + pkt->side_data = NULL; + pkt->side_data_elems = 0; } /* set the duration */ out_pkt.duration = 0; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if (st->codec->sample_rate > 0) { - out_pkt.duration = av_rescale_q_rnd(st->parser->duration, - (AVRational){ 1, st->codec->sample_rate }, - st->time_base, - AV_ROUND_DOWN); + out_pkt.duration = + av_rescale_q_rnd(st->parser->duration, + (AVRational) { 1, st->codec->sample_rate }, + st->time_base, + AV_ROUND_DOWN); } - } else if (st->codec->time_base.num != 0 && - st->codec->time_base.den != 0) { - out_pkt.duration = av_rescale_q_rnd(st->parser->duration, - st->codec->time_base, - st->time_base, - AV_ROUND_DOWN); } out_pkt.stream_index = st->index; - out_pkt.pts = st->parser->pts; - out_pkt.dts = st->parser->dts; - out_pkt.pos = st->parser->pos; + out_pkt.pts = st->parser->pts; + out_pkt.dts = st->parser->dts; + out_pkt.pos = st->parser->pos; - if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) + if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) out_pkt.pos = st->parser->frame_offset; if (st->parser->key_frame == 1 || @@ -1261,14 +1380,14 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) st->parser->pict_type == AV_PICTURE_TYPE_I)) out_pkt.flags |= AV_PKT_FLAG_KEY; - if(st->parser->key_frame == -1 && st->parser->pict_type==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY)) + if (st->parser->key_frame == -1 && st->parser->pict_type ==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY)) out_pkt.flags |= AV_PKT_FLAG_KEY; compute_pkt_fields(s, st, st->parser, &out_pkt); if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) { - out_pkt.buf = pkt->buf; - pkt->buf = NULL; + out_pkt.buf = pkt->buf; + pkt->buf = NULL; #if FF_API_DESTRUCT_PACKET FF_DISABLE_DEPRECATION_WARNINGS out_pkt.destruct = pkt->destruct; @@ -1286,7 +1405,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - /* end of the stream => close and free the parser */ if (pkt == &flush_pkt) { av_parser_close(st->parser); @@ -1304,8 +1422,8 @@ static int read_from_packet_buffer(AVPacketList **pkt_buffer, { AVPacketList *pktl; av_assert0(*pkt_buffer); - pktl = *pkt_buffer; - *pkt = pktl->pkt; + pktl = *pkt_buffer; + *pkt = pktl->pkt; *pkt_buffer = pktl->next; if (!pktl->next) *pkt_buffer_end = NULL; @@ -1329,7 +1447,7 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (ret == AVERROR(EAGAIN)) return ret; /* flush the parsers */ - for(i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->parser && st->need_parsing) parse_packet(s, NULL, st->index); @@ -1344,20 +1462,20 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (cur_pkt.pts != AV_NOPTS_VALUE && cur_pkt.dts != AV_NOPTS_VALUE && cur_pkt.pts < cur_pkt.dts) { - av_log(s, AV_LOG_WARNING, "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n", + av_log(s, AV_LOG_WARNING, + "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n", cur_pkt.stream_index, av_ts2str(cur_pkt.pts), av_ts2str(cur_pkt.dts), cur_pkt.size); } if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_DEBUG, "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", + av_log(s, AV_LOG_DEBUG, + "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", cur_pkt.stream_index, av_ts2str(cur_pkt.pts), av_ts2str(cur_pkt.dts), - cur_pkt.size, - cur_pkt.duration, - cur_pkt.flags); + cur_pkt.size, cur_pkt.duration, cur_pkt.flags); if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); @@ -1367,13 +1485,12 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) avcodec_get_name(st->codec->codec_id)); /* no parser available: just output the raw packets */ st->need_parsing = AVSTREAM_PARSE_NONE; - } else if(st->need_parsing == AVSTREAM_PARSE_HEADERS) { + } else if (st->need_parsing == AVSTREAM_PARSE_HEADERS) st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - } else if(st->need_parsing == AVSTREAM_PARSE_FULL_ONCE) { + else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE) st->parser->flags |= PARSER_FLAG_ONCE; - } else if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) { + else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) st->parser->flags |= PARSER_FLAG_USE_CODEC_TS; - } } if (!st->need_parsing || !st->parser) { @@ -1383,7 +1500,8 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) { ff_reduce_index(s, st->index); - av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); + av_add_index_entry(st, pkt->pos, pkt->dts, + 0, 0, AVINDEX_KEYFRAME); } got_packet = 1; } else if (st->discard < AVDISCARD_ALL) { @@ -1417,19 +1535,38 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) } st->skip_samples = 0; } - } - if(ret >= 0 && !(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) - av_packet_merge_side_data(pkt); + if (st->inject_global_side_data) { + for (i = 0; i < st->nb_side_data; i++) { + AVPacketSideData *src_sd = &st->side_data[i]; + uint8_t *dst_data; + + if (av_packet_get_side_data(pkt, src_sd->type, NULL)) + continue; + + dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size); + if (!dst_data) { + av_log(s, AV_LOG_WARNING, "Could not inject global side data\n"); + continue; + } + + memcpy(dst_data, src_sd->data, src_sd->size); + } + st->inject_global_side_data = 0; + } - if(s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", - pkt->stream_index, - av_ts2str(pkt->pts), - av_ts2str(pkt->dts), - pkt->size, - pkt->duration, - pkt->flags); + if (!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) + av_packet_merge_side_data(pkt); + } + + if (s->debug & FF_FDEBUG_TS) + av_log(s, AV_LOG_DEBUG, + "read_frame_internal stream=%d, pts=%s, dts=%s, " + "size=%d, duration=%d, flags=%d\n", + pkt->stream_index, + av_ts2str(pkt->pts), + av_ts2str(pkt->dts), + pkt->size, pkt->duration, pkt->flags); return ret; } @@ -1437,14 +1574,15 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) int av_read_frame(AVFormatContext *s, AVPacket *pkt) { const int genpts = s->flags & AVFMT_FLAG_GENPTS; - int eof = 0; + int eof = 0; int ret; AVStream *st; if (!genpts) { - ret = s->packet_buffer ? - read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt) : - read_frame_internal(s, pkt); + ret = s->packet_buffer + ? read_from_packet_buffer(&s->packet_buffer, + &s->packet_buffer_end, pkt) + : read_frame_internal(s, pkt); if (ret < 0) return ret; goto return_packet; @@ -1464,7 +1602,8 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) while (pktl && next_pkt->pts == AV_NOPTS_VALUE) { if (pktl->pkt.stream_index == next_pkt->stream_index && (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) { - if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame + if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { + // not B-frame next_pkt->pts = pktl->pkt.dts; } if (last_dts != AV_NOPTS_VALUE) { @@ -1504,7 +1643,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) } if (av_dup_packet(add_to_pktbuf(&s->packet_buffer, pkt, - &s->packet_buffer_end)) < 0) + &s->packet_buffer_end)) < 0) return AVERROR(ENOMEM); } @@ -1545,21 +1684,20 @@ int av_find_default_stream_index(AVFormatContext *s) if (s->nb_streams <= 0) return -1; - for(i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { return i; } - if (first_audio_index < 0 && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + if (first_audio_index < 0 && + st->codec->codec_type == AVMEDIA_TYPE_AUDIO) first_audio_index = i; } return first_audio_index >= 0 ? first_audio_index : 0; } -/** - * Flush the frame reader. - */ +/** Flush the frame reader. */ void ff_read_frame_flush(AVFormatContext *s) { AVStream *st; @@ -1567,8 +1705,8 @@ void ff_read_frame_flush(AVFormatContext *s) flush_packet_queue(s); - /* for each stream, reset read state */ - for(i = 0; i < s->nb_streams; i++) { + /* Reset read state for each stream. */ + for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->parser) { @@ -1576,13 +1714,20 @@ void ff_read_frame_flush(AVFormatContext *s) st->parser = NULL; } st->last_IP_pts = AV_NOPTS_VALUE; - if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = RELATIVE_TS_BASE; - else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ + st->last_dts_for_order_check = AV_NOPTS_VALUE; + if (st->first_dts == AV_NOPTS_VALUE) + st->cur_dts = RELATIVE_TS_BASE; + else + /* We set the current DTS to an unspecified origin. */ + st->cur_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; - for(j=0; j<MAX_REORDER_DELAY+1; j++) - st->pts_buffer[j]= AV_NOPTS_VALUE; + for (j = 0; j < MAX_REORDER_DELAY + 1; j++) + st->pts_buffer[j] = AV_NOPTS_VALUE; + + if (s->internal->inject_global_side_data) + st->inject_global_side_data = 1; } } @@ -1590,40 +1735,42 @@ void ff_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp) { int i; - for(i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - st->cur_dts = av_rescale(timestamp, - st->time_base.den * (int64_t)ref_st->time_base.num, - st->time_base.num * (int64_t)ref_st->time_base.den); + st->cur_dts = + av_rescale(timestamp, + st->time_base.den * (int64_t) ref_st->time_base.num, + st->time_base.num * (int64_t) ref_st->time_base.den); } } void ff_reduce_index(AVFormatContext *s, int stream_index) { - AVStream *st= s->streams[stream_index]; - unsigned int max_entries= s->max_index_size / sizeof(AVIndexEntry); + AVStream *st = s->streams[stream_index]; + unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry); - if((unsigned)st->nb_index_entries >= max_entries){ + if ((unsigned) st->nb_index_entries >= max_entries) { int i; - for(i=0; 2*i<st->nb_index_entries; i++) - st->index_entries[i]= st->index_entries[2*i]; - st->nb_index_entries= i; + for (i = 0; 2 * i < st->nb_index_entries; i++) + st->index_entries[i] = st->index_entries[2 * i]; + st->nb_index_entries = i; } } int ff_add_index_entry(AVIndexEntry **index_entries, int *nb_index_entries, unsigned int *index_entries_allocated_size, - int64_t pos, int64_t timestamp, int size, int distance, int flags) + int64_t pos, int64_t timestamp, + int size, int distance, int flags) { AVIndexEntry *entries, *ie; int index; - if((unsigned)*nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) + if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) return -1; - if(timestamp == AV_NOPTS_VALUE) + if (timestamp == AV_NOPTS_VALUE) return AVERROR(EINVAL); if (size < 0 || size > 0x3FFFFFFF) @@ -1636,39 +1783,42 @@ int ff_add_index_entry(AVIndexEntry **index_entries, index_entries_allocated_size, (*nb_index_entries + 1) * sizeof(AVIndexEntry)); - if(!entries) + if (!entries) return -1; - *index_entries= entries; + *index_entries = entries; - index= ff_index_search_timestamp(*index_entries, *nb_index_entries, timestamp, AVSEEK_FLAG_ANY); + index = ff_index_search_timestamp(*index_entries, *nb_index_entries, + timestamp, AVSEEK_FLAG_ANY); - if(index<0){ - index= (*nb_index_entries)++; - ie= &entries[index]; - av_assert0(index==0 || ie[-1].timestamp < timestamp); - }else{ - ie= &entries[index]; - if(ie->timestamp != timestamp){ - if(ie->timestamp <= timestamp) + if (index < 0) { + index = (*nb_index_entries)++; + ie = &entries[index]; + av_assert0(index == 0 || ie[-1].timestamp < timestamp); + } else { + ie = &entries[index]; + if (ie->timestamp != timestamp) { + if (ie->timestamp <= timestamp) return -1; - memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(*nb_index_entries - index)); + memmove(entries + index + 1, entries + index, + sizeof(AVIndexEntry) * (*nb_index_entries - index)); (*nb_index_entries)++; - }else if(ie->pos == pos && distance < ie->min_distance) //do not reduce the distance - distance= ie->min_distance; + } else if (ie->pos == pos && distance < ie->min_distance) + // do not reduce the distance + distance = ie->min_distance; } - ie->pos = pos; - ie->timestamp = timestamp; - ie->min_distance= distance; - ie->size= size; - ie->flags = flags; + ie->pos = pos; + ie->timestamp = timestamp; + ie->min_distance = distance; + ie->size = size; + ie->flags = flags; return index; } -int av_add_index_entry(AVStream *st, - int64_t pos, int64_t timestamp, int size, int distance, int flags) +int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, + int size, int distance, int flags) { timestamp = wrap_timestamp(st, timestamp); return ff_add_index_entry(&st->index_entries, &st->nb_index_entries, @@ -1682,36 +1832,34 @@ int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries, int a, b, m; int64_t timestamp; - a = - 1; + a = -1; b = nb_entries; - //optimize appending index entries at the end - if(b && entries[b-1].timestamp < wanted_timestamp) - a= b-1; + // Optimize appending index entries at the end. + if (b && entries[b - 1].timestamp < wanted_timestamp) + a = b - 1; while (b - a > 1) { - m = (a + b) >> 1; + m = (a + b) >> 1; timestamp = entries[m].timestamp; - if(timestamp >= wanted_timestamp) + if (timestamp >= wanted_timestamp) b = m; - if(timestamp <= wanted_timestamp) + if (timestamp <= wanted_timestamp) a = m; } - m= (flags & AVSEEK_FLAG_BACKWARD) ? a : b; + m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b; - if(!(flags & AVSEEK_FLAG_ANY)){ - while(m>=0 && m<nb_entries && !(entries[m].flags & AVINDEX_KEYFRAME)){ + if (!(flags & AVSEEK_FLAG_ANY)) + while (m >= 0 && m < nb_entries && + !(entries[m].flags & AVINDEX_KEYFRAME)) m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1; - } - } - if(m == nb_entries) + if (m == nb_entries) return -1; - return m; + return m; } -int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, - int flags) +int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) { return ff_index_search_timestamp(st->index_entries, st->nb_index_entries, wanted_timestamp, flags); @@ -1726,9 +1874,10 @@ static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t * return ts; } -int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) +int ff_seek_frame_binary(AVFormatContext *s, int stream_index, + int64_t target_ts, int flags) { - AVInputFormat *avif= s->iformat; + AVInputFormat *avif = s->iformat; int64_t av_uninit(pos_min), av_uninit(pos_max), pos, pos_limit; int64_t ts_min, ts_max, ts; int index; @@ -1740,42 +1889,47 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts av_dlog(s, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts)); - ts_max= - ts_min= AV_NOPTS_VALUE; - pos_limit= -1; //gcc falsely says it may be uninitialized + ts_max = + ts_min = AV_NOPTS_VALUE; + pos_limit = -1; // GCC falsely says it may be uninitialized. - st= s->streams[stream_index]; - if(st->index_entries){ + st = s->streams[stream_index]; + if (st->index_entries) { AVIndexEntry *e; - index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp() - index= FFMAX(index, 0); - e= &st->index_entries[index]; + /* FIXME: Whole function must be checked for non-keyframe entries in + * index case, especially read_timestamp(). */ + index = av_index_search_timestamp(st, target_ts, + flags | AVSEEK_FLAG_BACKWARD); + index = FFMAX(index, 0); + e = &st->index_entries[index]; - if(e->timestamp <= target_ts || e->pos == e->min_distance){ - pos_min= e->pos; - ts_min= e->timestamp; + if (e->timestamp <= target_ts || e->pos == e->min_distance) { + pos_min = e->pos; + ts_min = e->timestamp; av_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%s\n", pos_min, av_ts2str(ts_min)); - }else{ - av_assert1(index==0); + } else { + av_assert1(index == 0); } - index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD); + index = av_index_search_timestamp(st, target_ts, + flags & ~AVSEEK_FLAG_BACKWARD); av_assert0(index < st->nb_index_entries); - if(index >= 0){ - e= &st->index_entries[index]; + if (index >= 0) { + e = &st->index_entries[index]; av_assert1(e->timestamp >= target_ts); - pos_max= e->pos; - ts_max= e->timestamp; - pos_limit= pos_max - e->min_distance; - av_dlog(s, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64" dts_max=%s\n", - pos_max, pos_limit, av_ts2str(ts_max)); + pos_max = e->pos; + ts_max = e->timestamp; + pos_limit = pos_max - e->min_distance; + av_dlog(s, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64 + " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max)); } } - pos= ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit, ts_min, ts_max, flags, &ts, avif->read_timestamp); - if(pos<0) + pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit, + ts_min, ts_max, flags, &ts, avif->read_timestamp); + if (pos < 0) return -1; /* do the seek */ @@ -1791,28 +1945,30 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) { - int64_t step= 1024; + int64_t step = 1024; int64_t limit, ts_max; int64_t filesize = avio_size(s->pb); - int64_t pos_max = filesize - 1; - do{ + int64_t pos_max = filesize - 1; + do { limit = pos_max; pos_max = FFMAX(0, (pos_max) - step); - ts_max = ff_read_timestamp(s, stream_index, &pos_max, limit, read_timestamp); - step += step; - }while(ts_max == AV_NOPTS_VALUE && 2*limit > step); + ts_max = ff_read_timestamp(s, stream_index, + &pos_max, limit, read_timestamp); + step += step; + } while (ts_max == AV_NOPTS_VALUE && 2*limit > step); if (ts_max == AV_NOPTS_VALUE) return -1; - for(;;){ + for (;;) { int64_t tmp_pos = pos_max + 1; - int64_t tmp_ts = ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp); - if(tmp_ts == AV_NOPTS_VALUE) + int64_t tmp_ts = ff_read_timestamp(s, stream_index, + &tmp_pos, INT64_MAX, read_timestamp); + if (tmp_ts == AV_NOPTS_VALUE) break; av_assert0(tmp_pos > pos_max); ts_max = tmp_ts; pos_max = tmp_pos; - if(tmp_pos >= filesize) + if (tmp_pos >= filesize) break; } @@ -1826,8 +1982,10 @@ int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t * int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, - int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, - int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) + int64_t ts_min, int64_t ts_max, + int flags, int64_t *ts_ret, + int64_t (*read_timestamp)(struct AVFormatContext *, int, + int64_t *, int64_t)) { int64_t pos, ts; int64_t start_pos; @@ -1836,107 +1994,114 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, av_dlog(s, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts)); - if(ts_min == AV_NOPTS_VALUE){ + if (ts_min == AV_NOPTS_VALUE) { pos_min = s->data_offset; - ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); + ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); if (ts_min == AV_NOPTS_VALUE) return -1; } - if(ts_min >= target_ts){ - *ts_ret= ts_min; + if (ts_min >= target_ts) { + *ts_ret = ts_min; return pos_min; } - if(ts_max == AV_NOPTS_VALUE){ + if (ts_max == AV_NOPTS_VALUE) { if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0) return ret; - pos_limit= pos_max; + pos_limit = pos_max; } - if(ts_max <= target_ts){ - *ts_ret= ts_max; + if (ts_max <= target_ts) { + *ts_ret = ts_max; return pos_max; } - if(ts_min > ts_max){ + if (ts_min > ts_max) return -1; - }else if(ts_min == ts_max){ - pos_limit= pos_min; - } + else if (ts_min == ts_max) + pos_limit = pos_min; - no_change=0; + no_change = 0; while (pos_min < pos_limit) { - av_dlog(s, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n", + av_dlog(s, + "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n", pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max)); assert(pos_limit <= pos_max); - if(no_change==0){ - int64_t approximate_keyframe_distance= pos_max - pos_limit; + if (no_change == 0) { + int64_t approximate_keyframe_distance = pos_max - pos_limit; // interpolate position (better than dichotomy) - pos = av_rescale(target_ts - ts_min, pos_max - pos_min, ts_max - ts_min) - + pos_min - approximate_keyframe_distance; - }else if(no_change==1){ - // bisection, if interpolation failed to change min or max pos last time - pos = (pos_min + pos_limit)>>1; - }else{ + pos = av_rescale(target_ts - ts_min, pos_max - pos_min, + ts_max - ts_min) + + pos_min - approximate_keyframe_distance; + } else if (no_change == 1) { + // bisection if interpolation did not change min / max pos last time + pos = (pos_min + pos_limit) >> 1; + } else { /* linear search if bisection failed, can only happen if there - are very few or no keyframes between min/max */ - pos=pos_min; + * are very few or no keyframes between min/max */ + pos = pos_min; } - if(pos <= pos_min) - pos= pos_min + 1; - else if(pos > pos_limit) - pos= pos_limit; - start_pos= pos; - - ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); //may pass pos_limit instead of -1 - if(pos == pos_max) + if (pos <= pos_min) + pos = pos_min + 1; + else if (pos > pos_limit) + pos = pos_limit; + start_pos = pos; + + // May pass pos_limit instead of -1. + ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); + if (pos == pos_max) no_change++; else - no_change=0; - av_dlog(s, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n", + no_change = 0; + av_dlog(s, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s" + " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n", pos_min, pos, pos_max, av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts), pos_limit, start_pos, no_change); - if(ts == AV_NOPTS_VALUE){ + if (ts == AV_NOPTS_VALUE) { av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n"); return -1; } assert(ts != AV_NOPTS_VALUE); if (target_ts <= ts) { pos_limit = start_pos - 1; - pos_max = pos; - ts_max = ts; + pos_max = pos; + ts_max = ts; } if (target_ts >= ts) { pos_min = pos; - ts_min = ts; + ts_min = ts; } } - pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; - ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max; + pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; + ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max; #if 0 pos_min = pos; - ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); + ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); pos_min++; ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp); av_dlog(s, "pos=0x%"PRIx64" %s<=%s<=%s\n", pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max)); #endif - *ts_ret= ts; + *ts_ret = ts; return pos; } -static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){ +static int seek_frame_byte(AVFormatContext *s, int stream_index, + int64_t pos, int flags) +{ int64_t pos_min, pos_max; pos_min = s->data_offset; pos_max = avio_size(s->pb) - 1; - if (pos < pos_min) pos= pos_min; - else if(pos > pos_max) pos= pos_max; + if (pos < pos_min) + pos = pos_min; + else if (pos > pos_max) + pos = pos_max; avio_seek(s->pb, pos, SEEK_SET); @@ -1945,8 +2110,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, in return 0; } -static int seek_frame_generic(AVFormatContext *s, - int stream_index, int64_t timestamp, int flags) +static int seek_frame_generic(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) { int index; int64_t ret; @@ -1957,35 +2122,36 @@ static int seek_frame_generic(AVFormatContext *s, index = av_index_search_timestamp(st, timestamp, flags); - if(index < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp) + if (index < 0 && st->nb_index_entries && + timestamp < st->index_entries[0].timestamp) return -1; - if(index < 0 || index==st->nb_index_entries-1){ + if (index < 0 || index == st->nb_index_entries - 1) { AVPacket pkt; - int nonkey=0; + int nonkey = 0; - if(st->nb_index_entries){ + if (st->nb_index_entries) { av_assert0(st->index_entries); - ie= &st->index_entries[st->nb_index_entries-1]; + ie = &st->index_entries[st->nb_index_entries - 1]; if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; ff_update_cur_dts(s, st, ie->timestamp); - }else{ + } else { if ((ret = avio_seek(s->pb, s->data_offset, SEEK_SET)) < 0) return ret; } for (;;) { int read_status; - do{ + do { read_status = av_read_frame(s, &pkt); } while (read_status == AVERROR(EAGAIN)); if (read_status < 0) break; av_free_packet(&pkt); - if(stream_index == pkt.stream_index && pkt.dts > timestamp){ - if(pkt.flags & AV_PKT_FLAG_KEY) + if (stream_index == pkt.stream_index && pkt.dts > timestamp) { + if (pkt.flags & AV_PKT_FLAG_KEY) break; - if(nonkey++ > 1000 && st->codec->codec_id != AV_CODEC_ID_CDGRAPHICS){ + if (nonkey++ > 1000 && st->codec->codec_id != AV_CODEC_ID_CDGRAPHICS) { av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey); break; } @@ -1997,10 +2163,9 @@ static int seek_frame_generic(AVFormatContext *s, return -1; ff_read_frame_flush(s); - if (s->iformat->read_seek){ - if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0) + if (s->iformat->read_seek) + if (s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0) return 0; - } ie = &st->index_entries[index]; if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; @@ -2022,14 +2187,15 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index, return seek_frame_byte(s, stream_index, timestamp, flags); } - if(stream_index < 0){ - stream_index= av_find_default_stream_index(s); - if(stream_index < 0) + if (stream_index < 0) { + stream_index = av_find_default_stream_index(s); + if (stream_index < 0) return -1; - st= s->streams[stream_index]; + st = s->streams[stream_index]; /* timestamp for default must be expressed in AV_TIME_BASE units */ - timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); + timestamp = av_rescale(timestamp, st->time_base.den, + AV_TIME_BASE * (int64_t) st->time_base.num); } /* first, we try the format specific seek */ @@ -2038,22 +2204,22 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index, ret = s->iformat->read_seek(s, stream_index, timestamp, flags); } else ret = -1; - if (ret >= 0) { + if (ret >= 0) return 0; - } - if (s->iformat->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH)) { + if (s->iformat->read_timestamp && + !(s->iformat->flags & AVFMT_NOBINSEARCH)) { ff_read_frame_flush(s); return ff_seek_frame_binary(s, stream_index, timestamp, flags); } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) { ff_read_frame_flush(s); return seek_frame_generic(s, stream_index, timestamp, flags); - } - else + } else return -1; } -int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +int av_seek_frame(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) { int ret; @@ -2075,14 +2241,15 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int f return ret; } -int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, + int64_t ts, int64_t max_ts, int flags) { - if(min_ts > ts || max_ts < ts) + if (min_ts > ts || max_ts < ts) return -1; if (stream_index < -1 || stream_index >= (int)s->nb_streams) return AVERROR(EINVAL); - if(s->seek2any>0) + if (s->seek2any>0) flags |= AVSEEK_FLAG_ANY; flags &= ~AVSEEK_FLAG_BACKWARD; @@ -2101,15 +2268,16 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); } - ret = s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags); + ret = s->iformat->read_seek2(s, stream_index, min_ts, + ts, max_ts, flags); if (ret >= 0) ret = avformat_queue_attached_pictures(s); return ret; } - if(s->iformat->read_timestamp){ - //try to seek via read_timestamp() + if (s->iformat->read_timestamp) { + // try to seek via read_timestamp() } // Fall back on old API if new is not implemented but old is. @@ -2141,7 +2309,7 @@ static int has_duration(AVFormatContext *ic) int i; AVStream *st; - for(i = 0;i < ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->duration != AV_NOPTS_VALUE) return 1; @@ -2166,47 +2334,50 @@ static void update_stream_timings(AVFormatContext *ic) start_time = INT64_MAX; start_time_text = INT64_MAX; - end_time = INT64_MIN; - duration = INT64_MIN; - for(i = 0;i < ic->nb_streams; i++) { + end_time = INT64_MIN; + duration = INT64_MIN; + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) { - start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q); + start_time1 = av_rescale_q(st->start_time, st->time_base, + AV_TIME_BASE_Q); if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA) { if (start_time1 < start_time_text) start_time_text = start_time1; } else start_time = FFMIN(start_time, start_time1); - end_time1 = AV_NOPTS_VALUE; + end_time1 = AV_NOPTS_VALUE; if (st->duration != AV_NOPTS_VALUE) { - end_time1 = start_time1 - + av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); + end_time1 = start_time1 + + av_rescale_q(st->duration, st->time_base, + AV_TIME_BASE_Q); end_time = FFMAX(end_time, end_time1); } - for(p = NULL; (p = av_find_program_from_stream(ic, p, i)); ){ - if(p->start_time == AV_NOPTS_VALUE || p->start_time > start_time1) + for (p = NULL; (p = av_find_program_from_stream(ic, p, i)); ) { + if (p->start_time == AV_NOPTS_VALUE || p->start_time > start_time1) p->start_time = start_time1; - if(p->end_time < end_time1) + if (p->end_time < end_time1) p->end_time = end_time1; } } if (st->duration != AV_NOPTS_VALUE) { - duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); - duration = FFMAX(duration, duration1); + duration1 = av_rescale_q(st->duration, st->time_base, + AV_TIME_BASE_Q); + duration = FFMAX(duration, duration1); } } if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE)) start_time = start_time_text; - else if(start_time > start_time_text) + else if (start_time > start_time_text) av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE); if (start_time != INT64_MAX) { ic->start_time = start_time; if (end_time != INT64_MIN) { if (ic->nb_programs) { - for (i=0; i<ic->nb_programs; i++) { + for (i = 0; i < ic->nb_programs; i++) { p = ic->programs[i]; - if(p->start_time != AV_NOPTS_VALUE && p->end_time > p->start_time) + if (p->start_time != AV_NOPTS_VALUE && p->end_time > p->start_time) duration = FFMAX(duration, p->end_time - p->start_time); } } else @@ -2216,13 +2387,13 @@ static void update_stream_timings(AVFormatContext *ic) if (duration != INT64_MIN && duration > 0 && ic->duration == AV_NOPTS_VALUE) { ic->duration = duration; } - if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) { - /* compute the bitrate */ - double bitrate = (double)filesize * 8.0 * AV_TIME_BASE / - (double)ic->duration; - if (bitrate >= 0 && bitrate <= INT_MAX) - ic->bit_rate = bitrate; - } + if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) { + /* compute the bitrate */ + double bitrate = (double) filesize * 8.0 * AV_TIME_BASE / + (double) ic->duration; + if (bitrate >= 0 && bitrate <= INT_MAX) + ic->bit_rate = bitrate; + } } static void fill_all_stream_timings(AVFormatContext *ic) @@ -2231,13 +2402,15 @@ static void fill_all_stream_timings(AVFormatContext *ic) AVStream *st; update_stream_timings(ic); - for(i = 0;i < ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE) { - if(ic->start_time != AV_NOPTS_VALUE) - st->start_time = av_rescale_q(ic->start_time, AV_TIME_BASE_Q, st->time_base); - if(ic->duration != AV_NOPTS_VALUE) - st->duration = av_rescale_q(ic->duration, AV_TIME_BASE_Q, st->time_base); + if (ic->start_time != AV_NOPTS_VALUE) + st->start_time = av_rescale_q(ic->start_time, AV_TIME_BASE_Q, + st->time_base); + if (ic->duration != AV_NOPTS_VALUE) + st->duration = av_rescale_q(ic->duration, AV_TIME_BASE_Q, + st->time_base); } } } @@ -2251,7 +2424,7 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) /* if bit_rate is already set, we believe it */ if (ic->bit_rate <= 0) { int bit_rate = 0; - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->codec->bit_rate > 0) { if (INT_MAX - st->codec->bit_rate < bit_rate) { @@ -2269,11 +2442,13 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) ic->bit_rate != 0) { filesize = ic->pb ? avio_size(ic->pb) : 0; if (filesize > 0) { - for(i = 0; i < ic->nb_streams; i++) { - st = ic->streams[i]; + for (i = 0; i < ic->nb_streams; i++) { + 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, ic->bit_rate*(int64_t)st->time_base.num); + duration = av_rescale(8 * filesize, st->time_base.den, + ic->bit_rate * + (int64_t) st->time_base.num); st->duration = duration; show_warning = 1; } @@ -2281,7 +2456,8 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) } } if (show_warning) - av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n"); + av_log(ic, AV_LOG_WARNING, + "Estimating duration from bitrate, this may be inaccurate\n"); } #define DURATION_MAX_READ_SIZE 250000LL @@ -2295,19 +2471,22 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) int read_size, i, ret; int64_t end_time; int64_t filesize, offset, duration; - int retry=0; + int retry = 0; /* flush packet queue */ flush_packet_queue(ic); - for (i=0; i<ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; - if (st->start_time == AV_NOPTS_VALUE && st->first_dts == AV_NOPTS_VALUE) - av_log(st->codec, AV_LOG_WARNING, "start time is not set in estimate_timings_from_pts\n"); + if (st->start_time == AV_NOPTS_VALUE && + st->first_dts == AV_NOPTS_VALUE && + st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) + av_log(st->codec, AV_LOG_WARNING, + "start time for stream %d is not set in estimate_timings_from_pts\n", i); if (st->parser) { av_parser_close(st->parser); - st->parser= NULL; + st->parser = NULL; } } @@ -2315,24 +2494,24 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) /* XXX: may need to support wrapping */ filesize = ic->pb ? avio_size(ic->pb) : 0; end_time = AV_NOPTS_VALUE; - do{ - offset = filesize - (DURATION_MAX_READ_SIZE<<retry); + do { + offset = filesize - (DURATION_MAX_READ_SIZE << retry); if (offset < 0) offset = 0; avio_seek(ic->pb, offset, SEEK_SET); read_size = 0; - for(;;) { - if (read_size >= DURATION_MAX_READ_SIZE<<(FFMAX(retry-1,0))) + for (;;) { + if (read_size >= DURATION_MAX_READ_SIZE << (FFMAX(retry - 1, 0))) break; do { ret = ff_read_packet(ic, pkt); - } while(ret == AVERROR(EAGAIN)); + } while (ret == AVERROR(EAGAIN)); if (ret != 0) break; read_size += pkt->size; - st = ic->streams[pkt->stream_index]; + st = ic->streams[pkt->stream_index]; if (pkt->pts != AV_NOPTS_VALUE && (st->start_time != AV_NOPTS_VALUE || st->first_dts != AV_NOPTS_VALUE)) { @@ -2342,7 +2521,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) else duration -= st->first_dts; if (duration > 0) { - if (st->duration == AV_NOPTS_VALUE || st->info->last_duration<=0 || + if (st->duration == AV_NOPTS_VALUE || st->info->last_duration<= 0 || (st->duration < duration && FFABS(duration - st->info->last_duration) < 60LL*st->time_base.den / st->time_base.num)) st->duration = duration; st->info->last_duration = duration; @@ -2350,17 +2529,22 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } av_free_packet(pkt); } - }while( end_time==AV_NOPTS_VALUE - && filesize > (DURATION_MAX_READ_SIZE<<retry) - && ++retry <= DURATION_MAX_RETRY); + } while (end_time == AV_NOPTS_VALUE && + filesize > (DURATION_MAX_READ_SIZE << retry) && + ++retry <= DURATION_MAX_RETRY); fill_all_stream_timings(ic); avio_seek(ic->pb, old_offset, SEEK_SET); - for (i=0; i<ic->nb_streams; i++) { - st= ic->streams[i]; - st->cur_dts= st->first_dts; + for (i = 0; i < ic->nb_streams; i++) { + int j; + + st = ic->streams[i]; + st->cur_dts = st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; + st->last_dts_for_order_check = AV_NOPTS_VALUE; + for (j = 0; j < MAX_REORDER_DELAY + 1; j++) + st->pts_buffer[j] = AV_NOPTS_VALUE; } } @@ -2384,7 +2568,7 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS; } else if (has_duration(ic)) { /* at least one component has timings - we use them for all - the components */ + * the components */ fill_all_stream_timings(ic); ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM; } else { @@ -2397,13 +2581,14 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) { int i; AVStream av_unused *st; - for(i = 0;i < ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; av_dlog(ic, "%d: start_time: %0.3f duration: %0.3f\n", i, (double) st->start_time / AV_TIME_BASE, (double) st->duration / AV_TIME_BASE); } - av_dlog(ic, "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n", + av_dlog(ic, + "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n", (double) ic->start_time / AV_TIME_BASE, (double) ic->duration / AV_TIME_BASE, ic->bit_rate / 1000); @@ -2424,7 +2609,8 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) case AVMEDIA_TYPE_AUDIO: if (!avctx->frame_size && determinable_frame_size(avctx)) FAIL("unspecified frame size"); - if (st->info->found_decoder >= 0 && avctx->sample_fmt == AV_SAMPLE_FMT_NONE) + if (st->info->found_decoder >= 0 && + avctx->sample_fmt == AV_SAMPLE_FMT_NONE) FAIL("unspecified sample format"); if (!avctx->sample_rate) FAIL("unspecified sample rate"); @@ -2447,7 +2633,7 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) FAIL("unspecified size"); break; case AVMEDIA_TYPE_DATA: - if(avctx->codec_id == AV_CODEC_ID_NONE) return 1; + if (avctx->codec_id == AV_CODEC_ID_NONE) return 1; } if (avctx->codec_id == AV_CODEC_ID_NONE) @@ -2456,7 +2642,8 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) } /* returns 1 or 0 if or if not decoded data was returned, or a negative error */ -static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, AVDictionary **options) +static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, + AVDictionary **options) { const AVCodec *codec; int got_picture = 1, ret = 0; @@ -2467,25 +2654,27 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, A if (!frame) return AVERROR(ENOMEM); - if (!avcodec_is_open(st->codec) && !st->info->found_decoder) { + if (!avcodec_is_open(st->codec) && + st->info->found_decoder <= 0 && + (st->codec->codec_id != -st->info->found_decoder || !st->codec->codec_id)) { AVDictionary *thread_opt = NULL; codec = find_decoder(s, st, st->codec->codec_id); if (!codec) { - st->info->found_decoder = -1; - ret = -1; + st->info->found_decoder = -st->codec->codec_id; + ret = -1; goto fail; } - /* force thread count to 1 since the h264 decoder will not extract SPS - * and PPS to extradata during multi-threaded decoding */ + /* Force thread count to 1 since the H.264 decoder will not extract + * SPS and PPS to extradata during multi-threaded decoding. */ av_dict_set(options ? options : &thread_opt, "threads", "1", 0); ret = avcodec_open2(st->codec, codec, options ? options : &thread_opt); if (!options) av_dict_free(&thread_opt); if (ret < 0) { - st->info->found_decoder = -1; + st->info->found_decoder = -st->codec->codec_id; goto fail; } st->info->found_decoder = 1; @@ -2499,12 +2688,11 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, A while ((pkt.size > 0 || (!pkt.data && got_picture)) && ret >= 0 && - (!has_codec_parameters(st, NULL) || - !has_decode_delay_been_guessed(st) || - (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { + (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) || + (!st->codec_info_nb_frames && + st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { got_picture = 0; - avcodec_get_frame_defaults(frame); - switch(st->codec->codec_type) { + switch (st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: ret = avcodec_decode_video2(st->codec, frame, &got_picture, &pkt); @@ -2529,11 +2717,11 @@ static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, A } } - if(!pkt.data && !got_picture) + if (!pkt.data && !got_picture) ret = -1; fail: - avcodec_free_frame(&frame); + av_frame_free(&frame); return ret; } @@ -2550,14 +2738,12 @@ 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 i; - for(i=0; tags[i].id != AV_CODEC_ID_NONE;i++) { - if(tag == tags[i].tag) + for (i = 0; tags[i].id != AV_CODEC_ID_NONE; i++) + if (tag == tags[i].tag) return tags[i].id; - } - for(i=0; tags[i].id != AV_CODEC_ID_NONE; i++) { + for (i = 0; tags[i].id != AV_CODEC_ID_NONE; i++) if (avpriv_toupper4(tag) == avpriv_toupper4(tags[i].tag)) return tags[i].id; - } return AV_CODEC_ID_NONE; } @@ -2565,34 +2751,47 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags) { if (flt) { switch (bps) { - case 32: return be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; - case 64: return be ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F64LE; - default: return AV_CODEC_ID_NONE; + case 32: + return be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; + case 64: + return be ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F64LE; + default: + return AV_CODEC_ID_NONE; } } else { bps += 7; bps >>= 3; if (sflags & (1 << (bps - 1))) { switch (bps) { - case 1: return AV_CODEC_ID_PCM_S8; - case 2: return be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; - case 3: return be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE; - case 4: return be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE; - default: return AV_CODEC_ID_NONE; + case 1: + return AV_CODEC_ID_PCM_S8; + case 2: + return be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; + case 3: + return be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE; + case 4: + return be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE; + default: + return AV_CODEC_ID_NONE; } } else { switch (bps) { - case 1: return AV_CODEC_ID_PCM_U8; - case 2: return be ? AV_CODEC_ID_PCM_U16BE : AV_CODEC_ID_PCM_U16LE; - case 3: return be ? AV_CODEC_ID_PCM_U24BE : AV_CODEC_ID_PCM_U24LE; - case 4: return be ? AV_CODEC_ID_PCM_U32BE : AV_CODEC_ID_PCM_U32LE; - default: return AV_CODEC_ID_NONE; + case 1: + return AV_CODEC_ID_PCM_U8; + case 2: + return be ? AV_CODEC_ID_PCM_U16BE : AV_CODEC_ID_PCM_U16LE; + case 3: + return be ? AV_CODEC_ID_PCM_U24BE : AV_CODEC_ID_PCM_U24LE; + case 4: + return be ? AV_CODEC_ID_PCM_U32BE : AV_CODEC_ID_PCM_U32LE; + default: + return AV_CODEC_ID_NONE; } } } } -unsigned int av_codec_get_tag(const AVCodecTag * const *tags, enum AVCodecID id) +unsigned int av_codec_get_tag(const AVCodecTag *const *tags, enum AVCodecID id) { unsigned int tag; if (!av_codec_get_tag2(tags, id, &tag)) @@ -2604,7 +2803,7 @@ int av_codec_get_tag2(const AVCodecTag * const *tags, enum AVCodecID id, unsigned int *tag) { int i; - for(i=0; tags && tags[i]; i++){ + for (i = 0; tags && tags[i]; i++) { const AVCodecTag *codec_tags = tags[i]; while (codec_tags->id != AV_CODEC_ID_NONE) { if (codec_tags->id == id) { @@ -2617,12 +2816,13 @@ int av_codec_get_tag2(const AVCodecTag * const *tags, enum AVCodecID id, return 0; } -enum AVCodecID av_codec_get_id(const AVCodecTag * const *tags, unsigned int tag) +enum AVCodecID av_codec_get_id(const AVCodecTag *const *tags, unsigned int tag) { int i; - for(i=0; tags && tags[i]; i++){ - enum AVCodecID id= ff_codec_get_id(tags[i], tag); - if(id!=AV_CODEC_ID_NONE) return id; + for (i = 0; tags && tags[i]; i++) { + enum AVCodecID id = ff_codec_get_id(tags[i], tag); + if (id != AV_CODEC_ID_NONE) + return id; } return AV_CODEC_ID_NONE; } @@ -2630,17 +2830,20 @@ enum AVCodecID av_codec_get_id(const AVCodecTag * const *tags, unsigned int tag) static void compute_chapters_end(AVFormatContext *s) { unsigned int i, j; - int64_t max_time = s->duration + ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time); + int64_t max_time = s->duration + + ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time); for (i = 0; i < s->nb_chapters; i++) if (s->chapters[i]->end == AV_NOPTS_VALUE) { AVChapter *ch = s->chapters[i]; - int64_t end = max_time ? av_rescale_q(max_time, AV_TIME_BASE_Q, ch->time_base) - : INT64_MAX; + int64_t end = max_time ? av_rescale_q(max_time, AV_TIME_BASE_Q, + ch->time_base) + : INT64_MAX; for (j = 0; j < s->nb_chapters; j++) { - AVChapter *ch1 = s->chapters[j]; - int64_t next_start = av_rescale_q(ch1->start, ch1->time_base, ch->time_base); + AVChapter *ch1 = s->chapters[j]; + int64_t next_start = av_rescale_q(ch1->start, ch1->time_base, + ch->time_base); if (j != i && next_start > ch->start && next_start < end) end = next_start; } @@ -2648,28 +2851,30 @@ static void compute_chapters_end(AVFormatContext *s) } } -static int get_std_framerate(int i){ - if(i<60*12) return (i+1)*1001; - else return ((const int[]){24,30,60,12,15,48})[i-60*12]*1000*12; +static int get_std_framerate(int i) +{ + if (i < 60 * 12) + return (i + 1) * 1001; + else + return ((const int[]) { 24, 30, 60, 12, 15, 48 })[i - 60 * 12] * 1000 * 12; } -/* - * Is the time base unreliable. +/* Is the time base unreliable? * This is a heuristic to balance between quick acceptance of the values in * the headers vs. some extra checks. * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps. * MPEG-2 commonly misuses field repeat flags to store different framerates. - * And there are "variable" fps files this needs to detect as well. - */ -static int tb_unreliable(AVCodecContext *c){ - if( c->time_base.den >= 101L*c->time_base.num - || c->time_base.den < 5L*c->time_base.num -/* || c->codec_tag == AV_RL32("DIVX") - || c->codec_tag == AV_RL32("XVID")*/ - || c->codec_tag == AV_RL32("mp4v") - || c->codec_id == AV_CODEC_ID_MPEG2VIDEO - || c->codec_id == AV_CODEC_ID_H264 - ) + * And there are "variable" fps files this needs to detect as well. */ +static int tb_unreliable(AVCodecContext *c) +{ + if (c->time_base.den >= 101L * c->time_base.num || + c->time_base.den < 5L * c->time_base.num || + // c->codec_tag == AV_RL32("DIVX") || + // c->codec_tag == AV_RL32("XVID") || + c->codec_tag == AV_RL32("mp4v") || + c->codec_id == AV_CODEC_ID_MPEG2VIDEO || + c->codec_id == AV_CODEC_ID_GIF || + c->codec_id == AV_CODEC_ID_H264) return 1; return 0; } @@ -2701,29 +2906,45 @@ int ff_alloc_extradata(AVCodecContext *avctx, int size) return ret; } +int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size) +{ + int ret = ff_alloc_extradata(avctx, size); + if (ret < 0) + return ret; + ret = avio_read(pb, avctx->extradata, size); + if (ret != size) { + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + av_log(avctx, AV_LOG_ERROR, "Failed to read extradata of size %d\n", size); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } + + return ret; +} + int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts) { int i, j; int64_t last = st->info->last_dts; - if( ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last - && ts - (uint64_t)last < INT64_MAX){ - double dts= (is_relative(ts) ? ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base); - int64_t duration= ts - last; + if ( ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last + && ts - (uint64_t)last < INT64_MAX) { + double dts = (is_relative(ts) ? ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base); + int64_t duration = ts - last; if (!st->info->duration_error) st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2); if (!st->info->duration_error) return AVERROR(ENOMEM); -// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) +// if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) // av_log(NULL, AV_LOG_ERROR, "%f\n", dts); - for (i=0; i<MAX_STD_TIMEBASES; i++) { + for (i = 0; i<MAX_STD_TIMEBASES; i++) { if (st->info->duration_error[0][1][i] < 1e10) { - int framerate= get_std_framerate(i); - double sdts= dts*framerate/(1001*12); - for(j=0; j<2; j++){ - int64_t ticks= llrint(sdts+j*0.5); + int framerate = get_std_framerate(i); + double sdts = dts*framerate/(1001*12); + for (j= 0; j<2; j++) { + int64_t ticks = llrint(sdts+j*0.5); double error= sdts - ticks + j*0.5; st->info->duration_error[j][0][i] += error; st->info->duration_error[j][1][i] += error*error; @@ -2731,10 +2952,11 @@ int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts) } } st->info->duration_count++; + st->info->rfps_duration_sum += duration; if (st->info->duration_count % 10 == 0) { int n = st->info->duration_count; - for (i=0; i<MAX_STD_TIMEBASES; i++) { + for (i = 0; i<MAX_STD_TIMEBASES; i++) { if (st->info->duration_error[0][1][i] < 1e10) { double a0 = st->info->duration_error[0][0][i] / n; double error0 = st->info->duration_error[0][1][i] / n - a0*a0; @@ -2762,7 +2984,7 @@ void ff_rfps_calculate(AVFormatContext *ic) { int i, j; - for (i = 0; i<ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { AVStream *st = ic->streams[i]; if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) @@ -2776,35 +2998,50 @@ void ff_rfps_calculate(AVFormatContext *ic) && tb_unreliable(st->codec)) { int num = 0; double best_error= 0.01; + AVRational ref_rate = st->r_frame_rate.num ? st->r_frame_rate : av_inv_q(st->time_base); - for (j=0; j<MAX_STD_TIMEBASES; j++) { + for (j= 0; j<MAX_STD_TIMEBASES; j++) { int k; - if(st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j)) + if (st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j)) continue; - if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j)) + if (!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j)) + continue; + + if (av_q2d(st->time_base) * st->info->rfps_duration_sum / st->info->duration_count < (1001*12.0 * 0.8)/get_std_framerate(j)) continue; - for(k=0; k<2; k++){ - int n= st->info->duration_count; + + for (k= 0; k<2; k++) { + int n = st->info->duration_count; double a= st->info->duration_error[k][0][j] / n; double error= st->info->duration_error[k][1][j]/n - a*a; - if(error < best_error && best_error> 0.000000001){ + if (error < best_error && best_error> 0.000000001) { best_error= error; num = get_std_framerate(j); } - if(error < 0.02) + if (error < 0.02) av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error); } } // do not increase frame rate by more than 1 % in order to match a standard rate. - if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate))) + if (num && (!ref_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(ref_rate))) av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); } + if ( !st->avg_frame_rate.num + && st->r_frame_rate.num && st->info->rfps_duration_sum + && st->info->codec_info_duration <= 0 + && st->info->duration_count > 2 + && fabs(1.0 / (av_q2d(st->r_frame_rate) * av_q2d(st->time_base)) - st->info->rfps_duration_sum / (double)st->info->duration_count) <= 1.0 + ) { + av_log(ic, AV_LOG_DEBUG, "Setting avg frame rate based on r frame rate\n"); + st->avg_frame_rate = st->r_frame_rate; + } av_freep(&st->info->duration_error); st->info->last_dts = AV_NOPTS_VALUE; st->info->duration_count = 0; + st->info->rfps_duration_sum = 0; } } @@ -2814,33 +3051,34 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int64_t read_size; AVStream *st; AVPacket pkt1, *pkt; - int64_t old_offset = avio_tell(ic->pb); - int orig_nb_streams = ic->nb_streams; // new streams might appear, no options for those - int flush_codecs = ic->probesize > 0; + int64_t old_offset = avio_tell(ic->pb); + // new streams might appear, no options for those + int orig_nb_streams = ic->nb_streams; + int flush_codecs = ic->probesize > 0; - if(ic->pb) + if (ic->pb) av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d\n", avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count); - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { const AVCodec *codec; AVDictionary *thread_opt = NULL; st = ic->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { -/* if(!st->time_base.num) - st->time_base= */ - if(!st->codec->time_base.num) - st->codec->time_base= st->time_base; +/* if (!st->time_base.num) + st->time_base = */ + if (!st->codec->time_base.num) + st->codec->time_base = st->time_base; } - //only for the split stuff + // only for the split stuff if (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); - if(st->parser){ - if(st->need_parsing == AVSTREAM_PARSE_HEADERS){ + if (st->parser) { + if (st->need_parsing == AVSTREAM_PARSE_HEADERS) { st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - } else if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) { + } else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) { st->parser->flags |= PARSER_FLAG_USE_CODEC_TS; } } else if (st->need_parsing) { @@ -2851,27 +3089,30 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } codec = find_decoder(ic, st, st->codec->codec_id); - /* force thread count to 1 since the h264 decoder will not extract SPS - * and PPS to extradata during multi-threaded decoding */ + /* Force thread count to 1 since the H.264 decoder will not extract + * SPS and PPS to extradata during multi-threaded decoding. */ av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0); /* Ensure that subtitle_header is properly set. */ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE - && codec && !st->codec->codec) - avcodec_open2(st->codec, codec, options ? &options[i] - : &thread_opt); + && codec && !st->codec->codec) { + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, + "Failed to open codec in av_find_stream_info\n"); + } - //try to just open decoders, in case this is enough to get parameters + // Try to just open decoders, in case this is enough to get parameters. if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) { if (codec && !st->codec->codec) - avcodec_open2(st->codec, codec, options ? &options[i] - : &thread_opt); + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, + "Failed to open codec in av_find_stream_info\n"); } if (!options) av_dict_free(&thread_opt); } - for (i=0; i<ic->nb_streams; i++) { + for (i = 0; i < ic->nb_streams; i++) { #if FF_API_R_FRAME_RATE ic->streams[i]->info->last_dts = AV_NOPTS_VALUE; #endif @@ -2879,37 +3120,40 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) ic->streams[i]->info->fps_last_dts = AV_NOPTS_VALUE; } - count = 0; + count = 0; read_size = 0; - for(;;) { - if (ff_check_interrupt(&ic->interrupt_callback)){ - ret= AVERROR_EXIT; + for (;;) { + if (ff_check_interrupt(&ic->interrupt_callback)) { + ret = AVERROR_EXIT; av_log(ic, AV_LOG_DEBUG, "interrupted\n"); break; } /* check if one codec still needs to be handled */ - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { int fps_analyze_framecount = 20; st = ic->streams[i]; if (!has_codec_parameters(st, NULL)) break; - /* if the timebase is coarse (like the usual millisecond precision - of mkv), we need to analyze more frames to reliably arrive at - the correct fps */ + /* If the timebase is coarse (like the usual millisecond precision + * of mkv), we need to analyze more frames to reliably arrive at + * the correct fps. */ if (av_q2d(st->time_base) > 0.0005) fps_analyze_framecount *= 2; + if (!tb_unreliable(st->codec)) + fps_analyze_framecount = 0; if (ic->fps_probe_size >= 0) fps_analyze_framecount = ic->fps_probe_size; if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) fps_analyze_framecount = 0; /* variable fps and no guess at the real fps */ - if( tb_unreliable(st->codec) && !(st->r_frame_rate.num && st->avg_frame_rate.num) - && st->info->duration_count < fps_analyze_framecount - && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + if (!(st->r_frame_rate.num && st->avg_frame_rate.num) && + st->info->duration_count < fps_analyze_framecount && + st->codec->codec_type == AVMEDIA_TYPE_VIDEO) break; - if(st->parser && st->parser->parser->split && !st->codec->extradata) + if (st->parser && st->parser->parser->split && + !st->codec->extradata) break; if (st->first_dts == AV_NOPTS_VALUE && (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || @@ -2917,24 +3161,25 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) break; } if (i == ic->nb_streams) { - /* NOTE: if the format has no header, then we need to read - some packets to get most of the streams, so we cannot - stop here */ + /* NOTE: If the format has no header, then we need to read some + * packets to get most of the streams, so we cannot stop here. */ if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) { - /* if we found the info for all the codecs, we can stop */ + /* If we found the info for all the codecs, we can stop. */ ret = count; av_log(ic, AV_LOG_DEBUG, "All info found\n"); flush_codecs = 0; break; } } - /* we did not get all the codec info, but we read too much data */ + /* We did not get all the codec info, but we read too much data. */ if (read_size >= ic->probesize) { ret = count; - av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit of %d bytes reached\n", ic->probesize); + av_log(ic, AV_LOG_DEBUG, + "Probe buffer size limit of %d bytes reached\n", ic->probesize); for (i = 0; i < ic->nb_streams; i++) if (!ic->streams[i]->r_frame_rate.num && ic->streams[i]->info->duration_count <= 1 && + ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && strcmp(ic->iformat->name, "image2")) av_log(ic, AV_LOG_WARNING, "Stream #%d: not enough frames to estimate rate; " @@ -2942,8 +3187,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) break; } - /* NOTE: a new stream can be added there if no header in file - (AVFMTCTX_NOHEADER) */ + /* NOTE: A new stream can be added there if no header in file + * (AVFMTCTX_NOHEADER). */ ret = read_frame_internal(ic, &pkt1); if (ret == AVERROR(EAGAIN)) continue; @@ -2974,24 +3219,31 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) /* check for non-increasing dts */ if (st->info->fps_last_dts != AV_NOPTS_VALUE && st->info->fps_last_dts >= pkt->dts) { - av_log(ic, AV_LOG_DEBUG, "Non-increasing DTS in stream %d: " - "packet %d with DTS %"PRId64", packet %d with DTS " - "%"PRId64"\n", st->index, st->info->fps_last_dts_idx, - st->info->fps_last_dts, st->codec_info_nb_frames, pkt->dts); - st->info->fps_first_dts = st->info->fps_last_dts = AV_NOPTS_VALUE; + av_log(ic, AV_LOG_DEBUG, + "Non-increasing DTS in stream %d: packet %d with DTS " + "%"PRId64", packet %d with DTS %"PRId64"\n", + st->index, st->info->fps_last_dts_idx, + st->info->fps_last_dts, st->codec_info_nb_frames, + pkt->dts); + st->info->fps_first_dts = + st->info->fps_last_dts = AV_NOPTS_VALUE; } - /* check for a discontinuity in dts - if the difference in dts - * is more than 1000 times the average packet duration in the sequence, - * we treat it as a discontinuity */ + /* Check for a discontinuity in dts. If the difference in dts + * is more than 1000 times the average packet duration in the + * sequence, we treat it as a discontinuity. */ if (st->info->fps_last_dts != AV_NOPTS_VALUE && st->info->fps_last_dts_idx > st->info->fps_first_dts_idx && (pkt->dts - st->info->fps_last_dts) / 1000 > - (st->info->fps_last_dts - st->info->fps_first_dts) / (st->info->fps_last_dts_idx - st->info->fps_first_dts_idx)) { - av_log(ic, AV_LOG_WARNING, "DTS discontinuity in stream %d: " - "packet %d with DTS %"PRId64", packet %d with DTS " - "%"PRId64"\n", st->index, st->info->fps_last_dts_idx, - st->info->fps_last_dts, st->codec_info_nb_frames, pkt->dts); - st->info->fps_first_dts = st->info->fps_last_dts = AV_NOPTS_VALUE; + (st->info->fps_last_dts - st->info->fps_first_dts) / + (st->info->fps_last_dts_idx - st->info->fps_first_dts_idx)) { + av_log(ic, AV_LOG_WARNING, + "DTS discontinuity in stream %d: packet %d with DTS " + "%"PRId64", packet %d with DTS %"PRId64"\n", + st->index, st->info->fps_last_dts_idx, + st->info->fps_last_dts, st->codec_info_nb_frames, + pkt->dts); + st->info->fps_first_dts = + st->info->fps_last_dts = AV_NOPTS_VALUE; } /* update stored dts values */ @@ -2999,53 +3251,57 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st->info->fps_first_dts = pkt->dts; st->info->fps_first_dts_idx = st->codec_info_nb_frames; } - st->info->fps_last_dts = pkt->dts; + st->info->fps_last_dts = pkt->dts; st->info->fps_last_dts_idx = st->codec_info_nb_frames; } if (st->codec_info_nb_frames>1) { - int64_t t=0; + int64_t t = 0; if (st->time_base.den > 0) t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q); if (st->avg_frame_rate.num > 0) t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q)); - if ( t==0 + if ( t == 0 && st->codec_info_nb_frames>30 && st->info->fps_first_dts != AV_NOPTS_VALUE && st->info->fps_last_dts != AV_NOPTS_VALUE) t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q)); if (t >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t); + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %d reached at %"PRId64" microseconds\n", + ic->max_analyze_duration, + t); break; } if (pkt->duration) { st->info->codec_info_duration += pkt->duration; - st->info->codec_info_duration_fields += st->parser && st->need_parsing && st->codec->ticks_per_frame==2 ? st->parser->repeat_pict + 1 : 2; + st->info->codec_info_duration_fields += st->parser && st->need_parsing && st->codec->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2; } } #if FF_API_R_FRAME_RATE ff_rfps_add_frame(ic, st, pkt->dts); #endif - if(st->parser && st->parser->parser->split && !st->codec->extradata){ - int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); + if (st->parser && st->parser->parser->split && !st->codec->extradata) { + int i = st->parser->parser->split(st->codec, pkt->data, pkt->size); if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) { if (ff_alloc_extradata(st->codec, i)) return AVERROR(ENOMEM); - memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size); + memcpy(st->codec->extradata, pkt->data, + st->codec->extradata_size); } } - /* if still no information, we try to open the codec and to - decompress the frame. We try to avoid that in most cases as - it takes longer and uses more memory. For MPEG-4, we need to - decompress for QuickTime. - - If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at - least one frame of codec data, this makes sure the codec initializes - the channel configuration and does not only trust the values from the container. - */ - try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL); + /* If still no information, we try to open the codec and to + * decompress the frame. We try to avoid that in most cases as + * it takes longer and uses more memory. For MPEG-4, we need to + * decompress for QuickTime. + * + * If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at + * least one frame of codec data, this makes sure the codec initializes + * the channel configuration and does not only trust the values from + * the container. */ + try_decode_frame(ic, st, pkt, + (options && i < orig_nb_streams) ? &options[i] : NULL); st->codec_info_nb_frames++; count++; @@ -3056,7 +3312,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int err = 0; av_init_packet(&empty_pkt); - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; @@ -3064,8 +3320,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if (st->info->found_decoder == 1) { do { err = try_decode_frame(ic, st, &empty_pkt, - (options && i < orig_nb_streams) ? - &options[i] : NULL); + (options && i < orig_nb_streams) + ? &options[i] : NULL); } while (err > 0 && !has_codec_parameters(st, NULL)); if (err < 0) { @@ -3077,25 +3333,27 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) } // close codecs which were opened in try_decode_frame() - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; avcodec_close(st->codec); } ff_rfps_calculate(ic); - for(i=0;i<ic->nb_streams;i++) { + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if(st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample){ + if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) { uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); if (avpriv_find_pix_fmt(ff_raw_pix_fmt_tags, tag) == st->codec->pix_fmt) st->codec->codec_tag= tag; } /* estimate average framerate if not set by demuxer */ - if (st->info->codec_info_duration_fields && !st->avg_frame_rate.num && st->info->codec_info_duration) { - int best_fps = 0; + if (st->info->codec_info_duration_fields && + !st->avg_frame_rate.num && + st->info->codec_info_duration) { + int best_fps = 0; double best_error = 0.01; if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2|| @@ -3103,61 +3361,68 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st->info->codec_info_duration < 0) continue; av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, - st->info->codec_info_duration_fields*(int64_t)st->time_base.den, - st->info->codec_info_duration*2*(int64_t)st->time_base.num, 60000); + st->info->codec_info_duration_fields * (int64_t) st->time_base.den, + st->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000); - /* round guessed framerate to a "standard" framerate if it's - * within 1% of the original estimate*/ - for (j = 1; j < MAX_STD_TIMEBASES; j++) { - AVRational std_fps = { get_std_framerate(j), 12*1001 }; - double error = fabs(av_q2d(st->avg_frame_rate) / av_q2d(std_fps) - 1); + /* Round guessed framerate to a "standard" framerate if it's + * within 1% of the original estimate. */ + for (j = 0; j < MAX_STD_TIMEBASES; j++) { + AVRational std_fps = { get_std_framerate(j), 12 * 1001 }; + double error = fabs(av_q2d(st->avg_frame_rate) / + av_q2d(std_fps) - 1); if (error < best_error) { best_error = error; best_fps = std_fps.num; } } - if (best_fps) { + if (best_fps) av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, - best_fps, 12*1001, INT_MAX); - } + best_fps, 12 * 1001, INT_MAX); } - if (!st->r_frame_rate.num){ - if( st->codec->time_base.den * (int64_t)st->time_base.num - <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t)st->time_base.den){ + if (!st->r_frame_rate.num) { + if ( st->codec->time_base.den * (int64_t) st->time_base.num + <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t) st->time_base.den) { st->r_frame_rate.num = st->codec->time_base.den; st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame; - }else{ + } else { st->r_frame_rate.num = st->time_base.den; st->r_frame_rate.den = st->time_base.num; } } - }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if(!st->codec->bits_per_coded_sample) - st->codec->bits_per_coded_sample= av_get_bits_per_sample(st->codec->codec_id); + } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + if (!st->codec->bits_per_coded_sample) + st->codec->bits_per_coded_sample = + av_get_bits_per_sample(st->codec->codec_id); // set stream disposition based on audio service type switch (st->codec->audio_service_type) { case AV_AUDIO_SERVICE_TYPE_EFFECTS: - st->disposition = AV_DISPOSITION_CLEAN_EFFECTS; break; + st->disposition = AV_DISPOSITION_CLEAN_EFFECTS; + break; case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED: - st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED; break; + st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED; + break; case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED: - st->disposition = AV_DISPOSITION_HEARING_IMPAIRED; break; + st->disposition = AV_DISPOSITION_HEARING_IMPAIRED; + break; case AV_AUDIO_SERVICE_TYPE_COMMENTARY: - st->disposition = AV_DISPOSITION_COMMENT; break; + st->disposition = AV_DISPOSITION_COMMENT; + break; case AV_AUDIO_SERVICE_TYPE_KARAOKE: - st->disposition = AV_DISPOSITION_KARAOKE; break; + st->disposition = AV_DISPOSITION_KARAOKE; + break; } } } - if(ic->probesize) + if (ic->probesize) estimate_timings(ic, old_offset); if (ret >= 0 && ic->nb_streams) - ret = -1; /* we could not have all the codec parameters before EOF */ - for(i=0;i<ic->nb_streams;i++) { + /* We could not have all the codec parameters before EOF. */ + ret = -1; + for (i = 0; i < ic->nb_streams; i++) { const char *errmsg; st = ic->streams[i]; if (!has_codec_parameters(st, &errmsg)) { @@ -3174,16 +3439,16 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) compute_chapters_end(ic); - find_stream_info_err: - for (i=0; i < ic->nb_streams; i++) { +find_stream_info_err: + for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; - if (ic->streams[i]->codec && ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) + if (ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) ic->streams[i]->codec->thread_count = 0; if (st->info) av_freep(&st->info->duration_error); av_freep(&ic->streams[i]->info); } - if(ic->pb) + if (ic->pb) av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n", avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count); return ret; @@ -3206,34 +3471,35 @@ AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int return NULL; } -int av_find_best_stream(AVFormatContext *ic, - enum AVMediaType type, - int wanted_stream_nb, - int related_stream, - AVCodec **decoder_ret, - int flags) +int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, + int wanted_stream_nb, int related_stream, + AVCodec **decoder_ret, int flags) { int i, nb_streams = ic->nb_streams; int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1, best_bitrate = -1, best_multiframe = -1, count, bitrate, multiframe; unsigned *program = NULL; - AVCodec *decoder = NULL, *best_decoder = NULL; + const AVCodec *decoder = NULL, *best_decoder = NULL; if (related_stream >= 0 && wanted_stream_nb < 0) { AVProgram *p = av_find_program_from_stream(ic, NULL, related_stream); if (p) { - program = p->stream_index; + program = p->stream_index; nb_streams = p->nb_stream_indexes; } } for (i = 0; i < nb_streams; i++) { int real_stream_index = program ? program[i] : i; - AVStream *st = ic->streams[real_stream_index]; + AVStream *st = ic->streams[real_stream_index]; AVCodecContext *avctx = st->codec; if (avctx->codec_type != type) continue; if (wanted_stream_nb >= 0 && real_stream_index != wanted_stream_nb) continue; - if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED)) + if (wanted_stream_nb != real_stream_index && + st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED | + AV_DISPOSITION_VISUAL_IMPAIRED)) + continue; + if (type == AVMEDIA_TYPE_AUDIO && !avctx->channels) continue; if (decoder_ret) { decoder = find_decoder(ic, st, st->codec->codec_id); @@ -3250,19 +3516,20 @@ int av_find_best_stream(AVFormatContext *ic, (best_multiframe == multiframe && best_bitrate > bitrate) || (best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count)) continue; - best_count = count; + best_count = count; best_bitrate = bitrate; best_multiframe = multiframe; - ret = real_stream_index; + ret = real_stream_index; best_decoder = decoder; if (program && i == nb_streams - 1 && ret < 0) { - program = NULL; + program = NULL; nb_streams = ic->nb_streams; - i = 0; /* no related stream found, try again with everything */ + /* no related stream found, try again with everything */ + i = 0; } } if (decoder_ret) - *decoder_ret = best_decoder; + *decoder_ret = (AVCodec*)best_decoder; return ret; } @@ -3286,9 +3553,15 @@ int av_read_pause(AVFormatContext *s) return AVERROR(ENOSYS); } -void ff_free_stream(AVFormatContext *s, AVStream *st){ +void ff_free_stream(AVFormatContext *s, AVStream *st) { + int j; av_assert0(s->nb_streams>0); - av_assert0(s->streams[ s->nb_streams-1 ] == st); + av_assert0(s->streams[ s->nb_streams - 1 ] == st); + + for (j = 0; j < st->nb_side_data; j++) + av_freep(&st->side_data[j].data); + av_freep(&st->side_data); + st->nb_side_data = 0; if (st->parser) { av_parser_close(st->parser); @@ -3318,24 +3591,27 @@ void avformat_free_context(AVFormatContext *s) av_opt_free(s); if (s->iformat && s->iformat->priv_class && s->priv_data) av_opt_free(s->priv_data); + if (s->oformat && s->oformat->priv_class && s->priv_data) + av_opt_free(s->priv_data); - for(i=s->nb_streams-1; i>=0; i--) { + for (i = s->nb_streams - 1; i >= 0; i--) { ff_free_stream(s, s->streams[i]); } - for(i=s->nb_programs-1; i>=0; i--) { + for (i = s->nb_programs - 1; i >= 0; i--) { av_dict_free(&s->programs[i]->metadata); av_freep(&s->programs[i]->stream_index); av_freep(&s->programs[i]); } av_freep(&s->programs); av_freep(&s->priv_data); - while(s->nb_chapters--) { + while (s->nb_chapters--) { av_dict_free(&s->chapters[s->nb_chapters]->metadata); av_freep(&s->chapters[s->nb_chapters]); } av_freep(&s->chapters); av_dict_free(&s->metadata); av_freep(&s->streams); + av_freep(&s->internal); av_free(s); } @@ -3354,7 +3630,7 @@ void avformat_close_input(AVFormatContext **ps) if (!ps || !*ps) return; - s = *ps; + s = *ps; pb = s->pb; if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || @@ -3363,10 +3639,9 @@ void avformat_close_input(AVFormatContext **ps) flush_packet_queue(s); - if (s->iformat) { + if (s->iformat) if (s->iformat->read_close) s->iformat->read_close(s); - } avformat_free_context(s); @@ -3408,19 +3683,18 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) st->info->last_dts = AV_NOPTS_VALUE; st->codec = avcodec_alloc_context3(c); - if (s->iformat) { + if (s->iformat) /* no default bitrate if decoding */ st->codec->bit_rate = 0; - } - st->index = s->nb_streams; + st->index = s->nb_streams; st->start_time = AV_NOPTS_VALUE; - st->duration = AV_NOPTS_VALUE; - /* we set the current DTS to 0 so that formats without any timestamps - but durations get some timestamps, formats with some unknown - timestamps have their first few packets buffered and the - timestamps corrected before they are returned to the user */ - st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0; - st->first_dts = AV_NOPTS_VALUE; + st->duration = AV_NOPTS_VALUE; + /* we set the current DTS to 0 so that formats without any timestamps + * but durations get some timestamps, formats with some unknown + * timestamps have their first few packets buffered and the + * timestamps corrected before they are returned to the user */ + st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0; + st->first_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; st->pts_wrap_reference = AV_NOPTS_VALUE; st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE; @@ -3428,10 +3702,11 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) /* default pts setting is MPEG-like */ avpriv_set_pts_info(st, 33, 1, 90000); st->last_IP_pts = AV_NOPTS_VALUE; - for(i=0; i<MAX_REORDER_DELAY+1; i++) - st->pts_buffer[i]= AV_NOPTS_VALUE; + st->last_dts_for_order_check = AV_NOPTS_VALUE; + for (i = 0; i < MAX_REORDER_DELAY + 1; i++) + st->pts_buffer[i] = AV_NOPTS_VALUE; - st->sample_aspect_ratio = (AVRational){0,1}; + st->sample_aspect_ratio = (AVRational) { 0, 1 }; #if FF_API_R_FRAME_RATE st->info->last_dts = AV_NOPTS_VALUE; @@ -3439,22 +3714,24 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) st->info->fps_first_dts = AV_NOPTS_VALUE; st->info->fps_last_dts = AV_NOPTS_VALUE; + st->inject_global_side_data = s->internal->inject_global_side_data; + s->streams[s->nb_streams++] = st; return st; } AVProgram *av_new_program(AVFormatContext *ac, int id) { - AVProgram *program=NULL; + AVProgram *program = NULL; int i; av_dlog(ac, "new_program: id=0x%04x\n", id); - for(i=0; i<ac->nb_programs; i++) - if(ac->programs[i]->id == id) + for (i = 0; i < ac->nb_programs; i++) + if (ac->programs[i]->id == id) program = ac->programs[i]; - if(!program){ + if (!program) { program = av_mallocz(sizeof(AVProgram)); if (!program) return NULL; @@ -3471,34 +3748,35 @@ AVProgram *av_new_program(AVFormatContext *ac, int id) return program; } -AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base, int64_t start, int64_t end, const char *title) +AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base, + int64_t start, int64_t end, const char *title) { AVChapter *chapter = NULL; int i; - for(i=0; i<s->nb_chapters; i++) - if(s->chapters[i]->id == id) + for (i = 0; i < s->nb_chapters; i++) + if (s->chapters[i]->id == id) chapter = s->chapters[i]; - if(!chapter){ - chapter= av_mallocz(sizeof(AVChapter)); - if(!chapter) + if (!chapter) { + chapter = av_mallocz(sizeof(AVChapter)); + if (!chapter) return NULL; dynarray_add(&s->chapters, &s->nb_chapters, chapter); } av_dict_set(&chapter->metadata, "title", title, 0); - chapter->id = id; - chapter->time_base= time_base; - chapter->start = start; - chapter->end = end; + chapter->id = id; + chapter->time_base = time_base; + chapter->start = start; + chapter->end = end; return chapter; } -void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx) +void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx) { int i, j; - AVProgram *program=NULL; + AVProgram *program = NULL; void *tmp; if (idx >= ac->nb_streams) { @@ -3506,16 +3784,16 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i return; } - for(i=0; i<ac->nb_programs; i++){ - if(ac->programs[i]->id != progid) + for (i = 0; i < ac->nb_programs; i++) { + if (ac->programs[i]->id != progid) continue; program = ac->programs[i]; - for(j=0; j<program->nb_stream_indexes; j++) - if(program->stream_index[j] == idx) + for (j = 0; j < program->nb_stream_indexes; j++) + if (program->stream_index[j] == idx) return; tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int)); - if(!tmp) + if (!tmp) return; program->stream_index = tmp; program->stream_index[program->nb_stream_indexes++] = idx; @@ -3523,24 +3801,29 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i } } -static void print_fps(double d, const char *postfix){ - uint64_t v= lrintf(d*100); - if (v% 100 ) av_log(NULL, AV_LOG_INFO, ", %3.2f %s", d, postfix); - else if(v%(100*1000)) av_log(NULL, AV_LOG_INFO, ", %1.0f %s", d, postfix); - else av_log(NULL, AV_LOG_INFO, ", %1.0fk %s", d/1000, postfix); +static void print_fps(double d, const char *postfix) +{ + uint64_t v = lrintf(d * 100); + if (v % 100) + av_log(NULL, AV_LOG_INFO, ", %3.2f %s", d, postfix); + else if (v % (100 * 1000)) + av_log(NULL, AV_LOG_INFO, ", %1.0f %s", d, postfix); + else + av_log(NULL, AV_LOG_INFO, ", %1.0fk %s", d / 1000, postfix); } static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) { - if(m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0))){ - AVDictionaryEntry *tag=NULL; + if (m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0))) { + AVDictionaryEntry *tag = NULL; av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent); - while((tag=av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { - if(strcmp("language", tag->key)){ + while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) + if (strcmp("language", tag->key)) { const char *p = tag->value; - av_log(ctx, AV_LOG_INFO, "%s %-16s: ", indent, tag->key); - while(*p) { + av_log(ctx, AV_LOG_INFO, + "%s %-16s: ", indent, tag->key); + while (*p) { char tmp[256]; size_t len = strcspn(p, "\x8\xa\xb\xc\xd"); av_strlcpy(tmp, p, FFMIN(sizeof(tmp), len+1)); @@ -3552,12 +3835,12 @@ static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) } av_log(ctx, AV_LOG_INFO, "\n"); } - } } } /* "user interface" functions */ -static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) +static void dump_stream_format(AVFormatContext *ic, int i, + int index, int is_output) { char buf[256]; int flags = (is_output ? ic->oformat->flags : ic->iformat->flags); @@ -3572,30 +3855,31 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id); if (lang) av_log(NULL, AV_LOG_INFO, "(%s)", lang->value); - av_log(NULL, AV_LOG_DEBUG, ", %d, %d/%d", st->codec_info_nb_frames, st->time_base.num/g, st->time_base.den/g); + av_log(NULL, AV_LOG_DEBUG, ", %d, %d/%d", st->codec_info_nb_frames, + st->time_base.num / g, st->time_base.den / g); av_log(NULL, AV_LOG_INFO, ": %s", buf); if (st->sample_aspect_ratio.num && // default av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) { AVRational display_aspect_ratio; av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, - st->codec->width*st->sample_aspect_ratio.num, - st->codec->height*st->sample_aspect_ratio.den, - 1024*1024); + st->codec->width * st->sample_aspect_ratio.num, + st->codec->height * st->sample_aspect_ratio.den, + 1024 * 1024); av_log(NULL, AV_LOG_INFO, ", SAR %d:%d DAR %d:%d", - st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, - display_aspect_ratio.num, display_aspect_ratio.den); + st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, + display_aspect_ratio.num, display_aspect_ratio.den); } - if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ - if(st->avg_frame_rate.den && st->avg_frame_rate.num) + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->avg_frame_rate.den && st->avg_frame_rate.num) print_fps(av_q2d(st->avg_frame_rate), "fps"); #if FF_API_R_FRAME_RATE - if(st->r_frame_rate.den && st->r_frame_rate.num) + if (st->r_frame_rate.den && st->r_frame_rate.num) print_fps(av_q2d(st->r_frame_rate), "tbr"); #endif - if(st->time_base.den && st->time_base.num) - print_fps(1/av_q2d(st->time_base), "tbn"); - if(st->codec->time_base.den && st->codec->time_base.num) - print_fps(1/av_q2d(st->codec->time_base), "tbc"); + if (st->time_base.den && st->time_base.num) + print_fps(1 / av_q2d(st->time_base), "tbn"); + if (st->codec->time_base.den && st->codec->time_base.num) + print_fps(1 / av_q2d(st->codec->time_base), "tbc"); } if (st->disposition & AV_DISPOSITION_DEFAULT) av_log(NULL, AV_LOG_INFO, " (default)"); @@ -3621,10 +3905,8 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out dump_metadata(NULL, st->metadata, " "); } -void av_dump_format(AVFormatContext *ic, - int index, - const char *url, - int is_output) +void av_dump_format(AVFormatContext *ic, int index, + const char *url, int is_output) { int i; uint8_t *printed = ic->nb_streams ? av_mallocz(ic->nb_streams) : NULL; @@ -3632,19 +3914,19 @@ void av_dump_format(AVFormatContext *ic, return; av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n", - is_output ? "Output" : "Input", - index, - is_output ? ic->oformat->name : ic->iformat->name, - is_output ? "to" : "from", url); + is_output ? "Output" : "Input", + index, + is_output ? ic->oformat->name : ic->iformat->name, + is_output ? "to" : "from", url); dump_metadata(NULL, ic->metadata, " "); if (!is_output) { av_log(NULL, AV_LOG_INFO, " Duration: "); if (ic->duration != AV_NOPTS_VALUE) { int hours, mins, secs, us; int64_t duration = ic->duration + 5000; - secs = duration / AV_TIME_BASE; - us = duration % AV_TIME_BASE; - mins = secs / 60; + secs = duration / AV_TIME_BASE; + us = duration % AV_TIME_BASE; + mins = secs / 60; secs %= 60; hours = mins / 60; mins %= 60; @@ -3657,36 +3939,38 @@ void av_dump_format(AVFormatContext *ic, int secs, us; av_log(NULL, AV_LOG_INFO, ", start: "); secs = ic->start_time / AV_TIME_BASE; - us = abs(ic->start_time % AV_TIME_BASE); + us = abs(ic->start_time % AV_TIME_BASE); av_log(NULL, AV_LOG_INFO, "%d.%06d", - secs, (int)av_rescale(us, 1000000, AV_TIME_BASE)); + secs, (int) av_rescale(us, 1000000, AV_TIME_BASE)); } av_log(NULL, AV_LOG_INFO, ", bitrate: "); - if (ic->bit_rate) { - av_log(NULL, AV_LOG_INFO,"%d kb/s", ic->bit_rate / 1000); - } else { + if (ic->bit_rate) + av_log(NULL, AV_LOG_INFO, "%d kb/s", ic->bit_rate / 1000); + else av_log(NULL, AV_LOG_INFO, "N/A"); - } av_log(NULL, AV_LOG_INFO, "\n"); } for (i = 0; i < ic->nb_chapters; i++) { 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)); - av_log(NULL, AV_LOG_INFO, "end %f\n", ch->end * av_q2d(ch->time_base)); + av_log(NULL, AV_LOG_INFO, + "start %f, ", ch->start * av_q2d(ch->time_base)); + av_log(NULL, AV_LOG_INFO, + "end %f\n", ch->end * av_q2d(ch->time_base)); dump_metadata(NULL, ch->metadata, " "); } - if(ic->nb_programs) { + if (ic->nb_programs) { int j, k, total = 0; - for(j=0; j<ic->nb_programs; j++) { + 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, 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], index, is_output); + for (k = 0; k < ic->programs[j]->nb_stream_indexes; k++) { + dump_stream_format(ic, ic->programs[j]->stream_index[k], + index, is_output); printed[ic->programs[j]->stream_index[k]] = 1; } total += ic->programs[j]->nb_stream_indexes; @@ -3694,7 +3978,7 @@ void av_dump_format(AVFormatContext *ic, if (total < ic->nb_streams) av_log(NULL, AV_LOG_INFO, " No Program\n"); } - for(i=0;i<ic->nb_streams;i++) + for (i = 0; i < ic->nb_streams; i++) if (!printed[i]) dump_stream_format(ic, i, index, is_output); @@ -3703,11 +3987,10 @@ void av_dump_format(AVFormatContext *ic, uint64_t ff_ntp_time(void) { - return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; + return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; } -int av_get_frame_filename(char *buf, int buf_size, - const char *path, int number) +int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) { const char *p; char *q, buf1[20], c; @@ -3716,20 +3999,19 @@ int av_get_frame_filename(char *buf, int buf_size, q = buf; p = path; percentd_found = 0; - for(;;) { + for (;;) { c = *p++; if (c == '\0') break; if (c == '%') { do { nd = 0; - while (av_isdigit(*p)) { + while (av_isdigit(*p)) nd = nd * 10 + *p++ - '0'; - } c = *p++; } while (av_isdigit(c)); - switch(c) { + switch (c) { case '%': goto addchar; case 'd': @@ -3747,7 +4029,7 @@ int av_get_frame_filename(char *buf, int buf_size, goto fail; } } else { - addchar: +addchar: if ((q - buf) < buf_size - 1) *q++ = c; } @@ -3756,38 +4038,44 @@ int av_get_frame_filename(char *buf, int buf_size, goto fail; *q = '\0'; return 0; - fail: +fail: *q = '\0'; return -1; } +#define HEXDUMP_PRINT(...) \ + do { \ + if (!f) \ + av_log(avcl, level, __VA_ARGS__); \ + else \ + fprintf(f, __VA_ARGS__); \ + } while (0) + static void hex_dump_internal(void *avcl, FILE *f, int level, const uint8_t *buf, int size) { int len, i, j, c; -#define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0) - for(i=0;i<size;i+=16) { + for (i = 0; i < size; i += 16) { len = size - i; if (len > 16) len = 16; - PRINT("%08x ", i); - for(j=0;j<16;j++) { + HEXDUMP_PRINT("%08x ", i); + for (j = 0; j < 16; j++) { if (j < len) - PRINT(" %02x", buf[i+j]); + HEXDUMP_PRINT(" %02x", buf[i + j]); else - PRINT(" "); + HEXDUMP_PRINT(" "); } - PRINT(" "); - for(j=0;j<len;j++) { - c = buf[i+j]; + HEXDUMP_PRINT(" "); + for (j = 0; j < len; j++) { + c = buf[i + j]; if (c < ' ' || c > '~') c = '.'; - PRINT("%c", c); + HEXDUMP_PRINT("%c", c); } - PRINT("\n"); + HEXDUMP_PRINT("\n"); } -#undef PRINT } void av_hex_dump(FILE *f, const uint8_t *buf, int size) @@ -3800,38 +4088,37 @@ void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size) hex_dump_internal(avcl, NULL, level, buf, size); } -static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int dump_payload, AVRational time_base) +static void pkt_dump_internal(void *avcl, FILE *f, int level, const AVPacket *pkt, + int dump_payload, AVRational time_base) { -#define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0) - PRINT("stream #%d:\n", pkt->stream_index); - PRINT(" keyframe=%d\n", ((pkt->flags & AV_PKT_FLAG_KEY) != 0)); - PRINT(" duration=%0.3f\n", pkt->duration * av_q2d(time_base)); + HEXDUMP_PRINT("stream #%d:\n", pkt->stream_index); + HEXDUMP_PRINT(" keyframe=%d\n", (pkt->flags & AV_PKT_FLAG_KEY) != 0); + HEXDUMP_PRINT(" duration=%0.3f\n", pkt->duration * av_q2d(time_base)); /* DTS is _always_ valid after av_read_frame() */ - PRINT(" dts="); + HEXDUMP_PRINT(" dts="); if (pkt->dts == AV_NOPTS_VALUE) - PRINT("N/A"); + HEXDUMP_PRINT("N/A"); else - PRINT("%0.3f", pkt->dts * av_q2d(time_base)); + HEXDUMP_PRINT("%0.3f", pkt->dts * av_q2d(time_base)); /* PTS may not be known if B-frames are present. */ - PRINT(" pts="); + HEXDUMP_PRINT(" pts="); if (pkt->pts == AV_NOPTS_VALUE) - PRINT("N/A"); + HEXDUMP_PRINT("N/A"); else - PRINT("%0.3f", pkt->pts * av_q2d(time_base)); - PRINT("\n"); - PRINT(" size=%d\n", pkt->size); -#undef PRINT + HEXDUMP_PRINT("%0.3f", pkt->pts * av_q2d(time_base)); + HEXDUMP_PRINT("\n"); + HEXDUMP_PRINT(" size=%d\n", pkt->size); if (dump_payload) av_hex_dump(f, pkt->data, pkt->size); } -void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st) +void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st) { pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base); } -void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, - AVStream *st) +void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload, + const AVStream *st) { pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, st->time_base); } @@ -3839,24 +4126,29 @@ void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, - int *port_ptr, - char *path, int path_size, - const char *url) + int *port_ptr, char *path, int path_size, const char *url) { const char *p, *ls, *ls2, *at, *at2, *col, *brk; - if (port_ptr) *port_ptr = -1; - if (proto_size > 0) proto[0] = 0; - if (authorization_size > 0) authorization[0] = 0; - if (hostname_size > 0) hostname[0] = 0; - if (path_size > 0) path[0] = 0; + if (port_ptr) + *port_ptr = -1; + if (proto_size > 0) + proto[0] = 0; + if (authorization_size > 0) + authorization[0] = 0; + if (hostname_size > 0) + hostname[0] = 0; + if (path_size > 0) + path[0] = 0; /* parse protocol */ if ((p = strchr(url, ':'))) { av_strlcpy(proto, url, FFMIN(proto_size, p + 1 - url)); p++; /* skip ':' */ - if (*p == '/') p++; - if (*p == '/') p++; + if (*p == '/') + p++; + if (*p == '/') + p++; } else { /* no protocol means plain filename */ av_strlcpy(path, url, path_size); @@ -3866,14 +4158,14 @@ void av_url_split(char *proto, int proto_size, /* separate path from hostname */ ls = strchr(p, '/'); ls2 = strchr(p, '?'); - if(!ls) + if (!ls) ls = ls2; else if (ls && ls2) ls = FFMIN(ls, ls2); - if(ls) + if (ls) av_strlcpy(path, ls, path_size); else - ls = &p[strlen(p)]; // XXX + ls = &p[strlen(p)]; // XXX /* the rest is hostname, use that to parse auth/port */ if (ls != p) { @@ -3894,7 +4186,8 @@ void av_url_split(char *proto, int proto_size, } else if ((col = strchr(p, ':')) && col < ls) { av_strlcpy(hostname, p, FFMIN(col + 1 - p, hostname_size)); - if (port_ptr) *port_ptr = atoi(col + 1); + if (port_ptr) + *port_ptr = atoi(col + 1); } else av_strlcpy(hostname, p, FFMIN(ls + 1 - p, hostname_size)); @@ -3914,7 +4207,7 @@ char *ff_data_to_hex(char *buff, const uint8_t *src, int s, int lowercase) 'c', 'd', 'e', 'f' }; const char *hex_table = lowercase ? hex_table_lc : hex_table_uc; - for(i = 0; i < s; i++) { + for (i = 0; i < s; i++) { buff[i * 2] = hex_table[src[i] >> 4]; buff[i * 2 + 1] = hex_table[src[i] & 0xF]; } @@ -3927,7 +4220,7 @@ int ff_hex_to_data(uint8_t *data, const char *p) int c, len, v; len = 0; - v = 1; + v = 1; for (;;) { p += strspn(p, SPACE_CHARS); if (*p == '\0') @@ -3962,17 +4255,23 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) { AVRational new_tb; - if(av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)){ - if(new_tb.num != pts_num) - av_log(NULL, AV_LOG_DEBUG, "st:%d removing common factor %d from timebase\n", s->index, pts_num/new_tb.num); - }else - av_log(NULL, AV_LOG_WARNING, "st:%d has too large timebase, reducing\n", s->index); - - if(new_tb.num <= 0 || new_tb.den <= 0) { - av_log(NULL, AV_LOG_ERROR, "Ignoring attempt to set invalid timebase %d/%d for st:%d\n", new_tb.num, new_tb.den, s->index); + if (av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)) { + if (new_tb.num != pts_num) + av_log(NULL, AV_LOG_DEBUG, + "st:%d removing common factor %d from timebase\n", + s->index, pts_num / new_tb.num); + } else + av_log(NULL, AV_LOG_WARNING, + "st:%d has too large timebase, reducing\n", s->index); + + if (new_tb.num <= 0 || new_tb.den <= 0) { + av_log(NULL, AV_LOG_ERROR, + "Ignoring attempt to set invalid timebase %d/%d for st:%d\n", + new_tb.num, new_tb.den, + s->index); return; } - s->time_base = new_tb; + s->time_base = new_tb; av_codec_set_pkt_timebase(s->codec, new_tb); s->pts_wrap_bits = pts_wrap_bits; } @@ -4034,16 +4333,15 @@ void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, int ff_find_stream_index(AVFormatContext *s, int id) { int i; - for (i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->id == id) return i; - } return -1; } int64_t ff_iso8601_to_unix_time(const char *datestr) { - struct tm time1 = {0}, time2 = {0}; + struct tm time1 = { 0 }, time2 = { 0 }; char *ret1, *ret2; ret1 = av_small_strptime(datestr, "%Y - %m - %d %H:%M:%S", &time1); ret2 = av_small_strptime(datestr, "%Y - %m - %dT%H:%M:%S", &time2); @@ -4053,14 +4351,16 @@ int64_t ff_iso8601_to_unix_time(const char *datestr) return av_timegm(&time1); } -int avformat_query_codec(AVOutputFormat *ofmt, enum AVCodecID codec_id, int std_compliance) +int avformat_query_codec(AVOutputFormat *ofmt, enum AVCodecID codec_id, + int std_compliance) { if (ofmt) { if (ofmt->query_codec) return ofmt->query_codec(codec_id, std_compliance); else if (ofmt->codec_tag) return !!av_codec_get_tag(ofmt->codec_tag, codec_id); - else if (codec_id == ofmt->video_codec || codec_id == ofmt->audio_codec || + else if (codec_id == ofmt->video_codec || + codec_id == ofmt->audio_codec || codec_id == ofmt->subtitle_codec) return 1; } @@ -4098,19 +4398,19 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels, if (!pkt) return AVERROR(EINVAL); if (channels) { - size += 4; + size += 4; flags |= AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT; } if (channel_layout) { - size += 8; + size += 8; flags |= AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT; } if (sample_rate) { - size += 4; + size += 4; flags |= AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE; } if (width || height) { - size += 8; + size += 8; flags |= AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS; } data = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, size); @@ -4156,10 +4456,16 @@ AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *strea AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame) { AVRational fr = st->r_frame_rate; + AVRational codec_fr = av_inv_q(st->codec->time_base); + AVRational avg_fr = st->avg_frame_rate; + + if (avg_fr.num > 0 && avg_fr.den > 0 && fr.num > 0 && fr.den > 0 && + av_q2d(avg_fr) < 70 && av_q2d(fr) > 210) { + fr = avg_fr; + } + if (st->codec->ticks_per_frame > 1) { - AVRational codec_fr = av_inv_q(st->codec->time_base); - AVRational avg_fr = st->avg_frame_rate; codec_fr.den *= st->codec->ticks_per_frame; if ( codec_fr.num > 0 && codec_fr.den > 0 && av_q2d(codec_fr) < av_q2d(fr)*0.7 && fabs(1.0 - av_q2d(av_div_q(avg_fr, fr))) > 0.1) @@ -4217,12 +4523,14 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, return 1; } return 0; - } else if (*spec == '#') { - int sid; + } else if (*spec == '#' || + (*spec == 'i' && *(spec + 1) == ':')) { + int stream_id; char *endptr; - sid = strtol(spec + 1, &endptr, 0); + spec += 1 + (*spec == 'i'); + stream_id = strtol(spec, &endptr, 0); if (!*endptr) - return st->id == sid; + return stream_id == st->id; } else if (!*spec) /* empty specifier, matches everything */ return 1; @@ -4299,7 +4607,7 @@ int ff_generate_avci_extradata(AVStream *st) }; const uint8_t *data = NULL; - int size = 0; + int size = 0; if (st->codec->width == 1920) { if (st->codec->field_order == AV_FIELD_PROGRESSIVE) { diff --git a/chromium/third_party/ffmpeg/libavformat/vc1test.c b/chromium/third_party/ffmpeg/libavformat/vc1test.c index bf1bfe0318e..e5303fa46e7 100644 --- a/chromium/third_party/ffmpeg/libavformat/vc1test.c +++ b/chromium/third_party/ffmpeg/libavformat/vc1test.c @@ -61,9 +61,8 @@ static int vc1t_read_header(AVFormatContext *s) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_WMV3; - if (ff_alloc_extradata(st->codec, VC1_EXTRADATA_SIZE)) + if (ff_get_extradata(st->codec, pb, VC1_EXTRADATA_SIZE) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, VC1_EXTRADATA_SIZE); st->codec->height = avio_rl32(pb); st->codec->width = avio_rl32(pb); if(avio_rl32(pb) != 0xC) diff --git a/chromium/third_party/ffmpeg/libavformat/version.h b/chromium/third_party/ffmpeg/libavformat/version.h index 4fe8364ab20..c6667ca7bfd 100644 --- a/chromium/third_party/ffmpeg/libavformat/version.h +++ b/chromium/third_party/ffmpeg/libavformat/version.h @@ -27,10 +27,10 @@ * Libavformat version macros */ -#include "libavutil/avutil.h" +#include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 22 +#define LIBAVFORMAT_VERSION_MINOR 38 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -51,6 +51,9 @@ #ifndef FF_API_REFERENCE_DTS #define FF_API_REFERENCE_DTS (LIBAVFORMAT_VERSION_MAJOR < 56) #endif +#ifndef FF_API_LAVF_BITEXACT +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif #ifndef FF_API_ALLOC_OUTPUT_CONTEXT #define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56) diff --git a/chromium/third_party/ffmpeg/libavformat/vqf.c b/chromium/third_party/ffmpeg/libavformat/vqf.c index 526b5961461..74c7f5fc172 100644 --- a/chromium/third_party/ffmpeg/libavformat/vqf.c +++ b/chromium/third_party/ffmpeg/libavformat/vqf.c @@ -249,7 +249,7 @@ static int vqf_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->data[1] = c->last_frame_bits; ret = avio_read(s->pb, pkt->data+2, size); - if (ret<=0) { + if (ret != size) { av_free_packet(pkt); return AVERROR(EIO); } diff --git a/chromium/third_party/ffmpeg/libavformat/wavdec.c b/chromium/third_party/ffmpeg/libavformat/wavdec.c index daea64edc5a..a865b760b78 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wavdec.c @@ -114,7 +114,7 @@ static void handle_stream_probing(AVStream *st) { if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) { st->request_probe = AVPROBE_SCORE_EXTENSION; - st->probe_packets = FFMIN(st->probe_packets, 4); + st->probe_packets = FFMIN(st->probe_packets, 14); } } diff --git a/chromium/third_party/ffmpeg/libavformat/wavenc.c b/chromium/third_party/ffmpeg/libavformat/wavenc.c index 0067dfef29b..c892c7b34db 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavenc.c +++ b/chromium/third_party/ffmpeg/libavformat/wavenc.c @@ -126,7 +126,7 @@ static int wav_write_header(AVFormatContext *s) avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ } else { ffio_wfourcc(pb, "RIFF"); - avio_wl32(pb, 0); /* file length */ + avio_wl32(pb, -1); /* file length */ } ffio_wfourcc(pb, "WAVE"); @@ -141,7 +141,7 @@ static int wav_write_header(AVFormatContext *s) /* format header */ fmt = ff_start_tag(pb, "fmt "); - if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) { + if (ff_put_wav_header(pb, s->streams[0]->codec, 0) < 0) { av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); return -1; @@ -323,7 +323,7 @@ static int w64_write_header(AVFormatContext *s) avio_wl64(pb, -1); avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave)); start_guid(pb, ff_w64_guid_fmt, &start); - if ((ret = ff_put_wav_header(pb, s->streams[0]->codec)) < 0) { + if ((ret = ff_put_wav_header(pb, s->streams[0]->codec, 0)) < 0) { av_log(s, AV_LOG_ERROR, "%s codec not supported\n", s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); return ret; diff --git a/chromium/third_party/ffmpeg/libavformat/wc3movie.c b/chromium/third_party/ffmpeg/libavformat/wc3movie.c index 657380a6be1..408c050b7c7 100644 --- a/chromium/third_party/ffmpeg/libavformat/wc3movie.c +++ b/chromium/third_party/ffmpeg/libavformat/wc3movie.c @@ -27,6 +27,7 @@ * http://www.pcisys.net/~melanson/codecs/ */ +#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" @@ -249,10 +250,16 @@ static int wc3_read_packet(AVFormatContext *s, else { int i = 0; av_log (s, AV_LOG_DEBUG, "Subtitle time!\n"); + if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1) + return AVERROR_INVALIDDATA; av_log (s, AV_LOG_DEBUG, " inglish: %s\n", &text[i + 1]); i += text[i] + 1; + if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1) + return AVERROR_INVALIDDATA; av_log (s, AV_LOG_DEBUG, " doytsch: %s\n", &text[i + 1]); i += text[i] + 1; + if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1) + return AVERROR_INVALIDDATA; av_log (s, AV_LOG_DEBUG, " fronsay: %s\n", &text[i + 1]); } #endif diff --git a/chromium/third_party/ffmpeg/libavformat/webvttdec.c b/chromium/third_party/ffmpeg/libavformat/webvttdec.c index 065448532d3..e457e8f6d21 100644 --- a/chromium/third_party/ffmpeg/libavformat/webvttdec.c +++ b/chromium/third_party/ffmpeg/libavformat/webvttdec.c @@ -119,7 +119,7 @@ static int webvtt_read_header(AVFormatContext *s) break; if (!(p = strstr(p, "-->"))) break; - p += 3; + p += 2; do p++; while (*p == ' ' || *p == '\t'); if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE) break; diff --git a/chromium/third_party/ffmpeg/libavformat/westwood_vqa.c b/chromium/third_party/ffmpeg/libavformat/westwood_vqa.c index 1d4bb5ad6c6..2a988ad3900 100644 --- a/chromium/third_party/ffmpeg/libavformat/westwood_vqa.c +++ b/chromium/third_party/ffmpeg/libavformat/westwood_vqa.c @@ -101,13 +101,9 @@ static int wsvqa_read_header(AVFormatContext *s) avio_seek(pb, 20, SEEK_SET); /* the VQA header needs to go to the decoder */ - if (ff_alloc_extradata(st->codec, VQA_HEADER_SIZE)) + if (ff_get_extradata(st->codec, pb, VQA_HEADER_SIZE) < 0) return AVERROR(ENOMEM); header = (uint8_t *)st->codec->extradata; - if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) != - VQA_HEADER_SIZE) { - return AVERROR(EIO); - } st->codec->width = AV_RL16(&header[6]); st->codec->height = AV_RL16(&header[8]); fps = header[12]; diff --git a/chromium/third_party/ffmpeg/libavformat/wtv.h b/chromium/third_party/ffmpeg/libavformat/wtv.h index efe90d68466..f26ad5efb90 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtv.h +++ b/chromium/third_party/ffmpeg/libavformat/wtv.h @@ -55,4 +55,6 @@ extern const ff_asf_guid ff_mediasubtype_cpfilters_processed; extern const ff_asf_guid ff_format_cpfilters_processed; extern const ff_asf_guid ff_format_waveformatex; extern const ff_asf_guid ff_format_mpeg2_video; +extern const ff_asf_guid ff_format_videoinfo2; + #endif /* AVFORMAT_WTV_H */ diff --git a/chromium/third_party/ffmpeg/libavformat/wtv_common.c b/chromium/third_party/ffmpeg/libavformat/wtv_common.c index 5b1e61b810b..ce4349dce54 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtv_common.c +++ b/chromium/third_party/ffmpeg/libavformat/wtv_common.c @@ -75,6 +75,8 @@ const ff_asf_guid ff_format_waveformatex = {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A}; const ff_asf_guid ff_format_mpeg2_video = {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}; +const ff_asf_guid ff_format_videoinfo2 = + {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; const AVCodecGuid ff_video_guids[] = { {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, diff --git a/chromium/third_party/ffmpeg/libavformat/wtvdec.c b/chromium/third_party/ffmpeg/libavformat/wtvdec.c index 4dfe7010d12..cfdc55523a8 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtvdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wtvdec.c @@ -25,6 +25,8 @@ * @author Peter Ross <pross@xvid.org> */ +#include <inttypes.h> + #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" @@ -35,7 +37,7 @@ /* Macros for formating GUIDs */ #define PRI_PRETTY_GUID \ - "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x" + "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02x%02x%02x%02x%02x%02x%02x%02x" #define ARG_PRETTY_GUID(g) \ AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15] #define LEN_PRETTY_GUID 34 @@ -153,6 +155,7 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int AVIOContext *pb; WtvFile *wf; uint8_t *buffer; + int64_t size; if (seek_by_sector(s->pb, first_sector, 0) < 0) return NULL; @@ -205,7 +208,8 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int return NULL; } - if ((int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > avio_tell(s->pb)) + size = avio_size(s->pb); + if (size >= 0 && (int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > size) av_log(s, AV_LOG_WARNING, "truncated file\n"); /* check length */ @@ -370,10 +374,6 @@ static const ff_asf_guid mediasubtype_dtvccdata = static const ff_asf_guid mediasubtype_mpeg2_sections = {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61}; -/* Formats */ -static const ff_asf_guid format_videoinfo2 = - {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; - static int read_probe(AVProbeData *p) { return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX; @@ -473,7 +473,7 @@ static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int ty return; if (type == 0 && length == 4) { - snprintf(buf, buf_size, "%"PRIi32, avio_rl32(pb)); + snprintf(buf, buf_size, "%u", avio_rl32(pb)); } else if (type == 1) { avio_get_str16le(pb, length, buf, buf_size); if (!strlen(buf)) { @@ -562,7 +562,7 @@ static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st) AVIOContext *pb = wtv->pb; avio_skip(pb, 72); // picture aspect ratio is unreliable - ff_get_bmp_header(pb, st, NULL); + st->codec->codec_tag = ff_get_bmp_header(pb, st, NULL); return 72 + 40; } @@ -635,7 +635,7 @@ static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int code */ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, ff_asf_guid mediatype, ff_asf_guid subtype, - ff_asf_guid formattype, int size) + ff_asf_guid formattype, uint64_t size) { WtvContext *wtv = s->priv_data; AVIOContext *pb = wtv->pb; @@ -689,11 +689,12 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO); if (!st) return NULL; - if (!ff_guidcmp(formattype, format_videoinfo2)) { + if (!ff_guidcmp(formattype, ff_format_videoinfo2)) { int consumed = parse_videoinfoheader2(s, st); avio_skip(pb, FFMAX(size - consumed, 0)); } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) { - int consumed = parse_videoinfoheader2(s, st); + uint64_t consumed = parse_videoinfoheader2(s, st); + /* ignore extradata; files produced by windows media center contain meaningless mpeg1 sequence header */ avio_skip(pb, FFMAX(size - consumed, 0)); } else { if (ff_guidcmp(formattype, ff_format_none)) diff --git a/chromium/third_party/ffmpeg/libavformat/wtvenc.c b/chromium/third_party/ffmpeg/libavformat/wtvenc.c index 04e6cc22f8d..634545d4594 100644 --- a/chromium/third_party/ffmpeg/libavformat/wtvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/wtvenc.c @@ -30,8 +30,8 @@ #include "avformat.h" #include "avio_internal.h" #include "internal.h" +#include "mpegts.h" #include "wtv.h" -#include "asf.h" #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS) #define INDEX_BASE 0x2 @@ -130,16 +130,6 @@ typedef struct { #define write_pad(pb, size) ffio_fill(pb, 0, size) -static const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid) -{ - int i; - for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) { - if (id == av_guid[i].id) - return &(av_guid[i].guid); - } - return NULL; -} - /** * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks */ @@ -223,10 +213,53 @@ static void finish_chunk(AVFormatContext *s) write_index(s); } +static void put_videoinfoheader2(AVIOContext *pb, AVStream *st) +{ + AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational){st->codec->width, st->codec->height}); + unsigned int num, den; + av_reduce(&num, &den, dar.num, dar.den, 0xFFFFFFFF); + + /* VIDEOINFOHEADER2 */ + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, st->codec->width); + avio_wl32(pb, st->codec->height); + + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + avio_wl32(pb, st->codec->bit_rate); + avio_wl32(pb, 0); + avio_wl64(pb, st->avg_frame_rate.num && st->avg_frame_rate.den ? INT64_C(10000000) / av_q2d(st->avg_frame_rate) : 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + avio_wl32(pb, num); + avio_wl32(pb, den); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0, 1); + + if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + int padding = (st->codec->extradata_size & 3) ? 4 - (st->codec->extradata_size & 3) : 0; + /* MPEG2VIDEOINFO */ + avio_wl32(pb, 0); + avio_wl32(pb, st->codec->extradata_size + padding); + avio_wl32(pb, -1); + avio_wl32(pb, -1); + avio_wl32(pb, 0); + avio_write(pb, st->codec->extradata, st->codec->extradata_size); + ffio_fill(pb, 0, padding); + } +} + static int write_stream_codec_info(AVFormatContext *s, AVStream *st) { - WtvContext *wctx = s->priv_data; const ff_asf_guid *g, *media_type, *format_type; + const AVCodecTag *tags; AVIOContext *pb = s->pb; int64_t hdr_pos_start; int hdr_size = 0; @@ -234,21 +267,18 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { g = get_codec_guid(st->codec->codec_id, ff_video_guids); media_type = &ff_mediatype_video; - format_type = &ff_format_mpeg2_video; + format_type = st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO ? &ff_format_mpeg2_video : &ff_format_videoinfo2; + tags = ff_codec_bmp_tags; } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { g = get_codec_guid(st->codec->codec_id, ff_codec_wav_guids); media_type = &ff_mediatype_audio; format_type = &ff_format_waveformatex; + tags = ff_codec_wav_tags; } else { av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type); return -1; } - if (g == NULL) { - av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id); - return -1; - } - ff_put_guid(pb, media_type); // mediatype ff_put_guid(pb, &ff_mediasubtype_cpfilters_processed); // subtype write_pad(pb, 12); @@ -257,15 +287,10 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) hdr_pos_start = avio_tell(pb); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if (wctx->first_video_flag) { - write_pad(pb, 216); //The size is sensitive. - wctx->first_video_flag = 0; - } else { - write_pad(pb, 72); // aspect ratio - ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0); - } + put_videoinfoheader2(pb, st); } else { - ff_put_wav_header(pb, st->codec); + if (ff_put_wav_header(pb, st->codec, 0) < 0) + format_type = &ff_format_none; } hdr_size = avio_tell(pb) - hdr_pos_start; @@ -273,7 +298,17 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) avio_seek(pb, -(hdr_size + 4), SEEK_CUR); avio_wl32(pb, hdr_size + 32); avio_seek(pb, hdr_size, SEEK_CUR); - ff_put_guid(pb, g); // actual_subtype + if (g) { + ff_put_guid(pb, g); // actual_subtype + } else { + int tag = ff_codec_get_tag(tags, st->codec->codec_id); + if (!tag) { + av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x)\n", st->codec->codec_id); + return -1; + } + avio_wl32(pb, tag); + avio_write(pb, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12); + } ff_put_guid(pb, format_type); // actual_formattype return 0; @@ -426,10 +461,15 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; WtvContext *wctx = s->priv_data; + AVStream *st = s->streams[pkt->stream_index]; - if (s->streams[pkt->stream_index]->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) { + if (st->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) { av_copy_packet(&wctx->thumbnail, pkt); return 0; + } else if (st->codec->codec_id == AV_CODEC_ID_H264) { + int ret = ff_check_h264_startcode(s, st, pkt); + if (ret < 0) + return ret; } /* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */ diff --git a/chromium/third_party/ffmpeg/libavformat/xmv.c b/chromium/third_party/ffmpeg/libavformat/xmv.c index 20f9bea55bc..6eac4d21e84 100644 --- a/chromium/third_party/ffmpeg/libavformat/xmv.c +++ b/chromium/third_party/ffmpeg/libavformat/xmv.c @@ -25,7 +25,7 @@ * Microsoft XMV demuxer */ -#include <stdint.h> +#include <inttypes.h> #include "libavutil/intreadwrite.h" @@ -155,7 +155,7 @@ static int xmv_read_header(AVFormatContext *s) file_version = avio_rl32(pb); if ((file_version != 4) && (file_version != 2)) - avpriv_request_sample(s, "Uncommon version %d", file_version); + avpriv_request_sample(s, "Uncommon version %"PRIu32"", file_version); /* Video track */ @@ -182,7 +182,7 @@ static int xmv_read_header(AVFormatContext *s) avio_skip(pb, 2); /* Unknown (padding?) */ - xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket)); + xmv->audio = av_malloc_array(xmv->audio_track_count, sizeof(XMVAudioPacket)); if (!xmv->audio) { ret = AVERROR(ENOMEM); goto fail; @@ -219,7 +219,7 @@ static int xmv_read_header(AVFormatContext *s) if (!packet->channels || !packet->sample_rate || packet->channels >= UINT16_MAX / XMV_BLOCK_ALIGN_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %d.\n", + av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %"PRIu16".\n", audio_track); ret = AVERROR_INVALIDDATA; goto fail; diff --git a/chromium/third_party/ffmpeg/libavformat/xwma.c b/chromium/third_party/ffmpeg/libavformat/xwma.c index e629b3f3844..127c097c449 100644 --- a/chromium/third_party/ffmpeg/libavformat/xwma.c +++ b/chromium/third_party/ffmpeg/libavformat/xwma.c @@ -46,7 +46,7 @@ static int xwma_read_header(AVFormatContext *s) int64_t size; int ret; uint32_t dpds_table_size = 0; - uint32_t *dpds_table = 0; + uint32_t *dpds_table = NULL; unsigned int tag; AVIOContext *pb = s->pb; AVStream *st; @@ -130,8 +130,10 @@ static int xwma_read_header(AVFormatContext *s) /* parse the remaining RIFF chunks */ for (;;) { - if (pb->eof_reached) - return -1; + if (pb->eof_reached) { + ret = AVERROR_EOF; + goto end; + } /* read next chunk tag */ tag = avio_rl32(pb); size = avio_rl32(pb); @@ -152,7 +154,8 @@ static int xwma_read_header(AVFormatContext *s) /* Error out if there is more than one dpds chunk. */ if (dpds_table) { av_log(s, AV_LOG_ERROR, "two dpds chunks present\n"); - return -1; + ret = AVERROR_INVALIDDATA; + goto end; } /* Compute the number of entries in the dpds chunk. */ @@ -164,7 +167,7 @@ static int xwma_read_header(AVFormatContext *s) if (dpds_table_size == 0 || dpds_table_size >= INT_MAX / 4) { av_log(s, AV_LOG_ERROR, "dpds chunk size %"PRId64" invalid\n", size); - return -1; + return AVERROR_INVALIDDATA; } /* Allocate some temporary storage to keep the dpds data around. @@ -184,8 +187,10 @@ static int xwma_read_header(AVFormatContext *s) } /* Determine overall data length */ - if (size < 0) - return -1; + if (size < 0) { + ret = AVERROR_INVALIDDATA; + goto end; + } if (!size) { xwma->data_end = INT64_MAX; } else @@ -204,7 +209,8 @@ static int xwma_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Invalid bits_per_coded_sample %d for %d channels\n", st->codec->bits_per_coded_sample, st->codec->channels); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto end; } st->duration = total_decoded_bytes / bytes_per_sample; @@ -239,9 +245,10 @@ static int xwma_read_header(AVFormatContext *s) st->duration = (size<<3) * st->codec->sample_rate / st->codec->bit_rate; } +end: av_free(dpds_table); - return 0; + return ret; } static int xwma_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.c b/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.c index 1999c733642..bc07b4c55de 100644 --- a/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.c +++ b/chromium/third_party/ffmpeg/libavformat/yuv4mpeg.c @@ -517,6 +517,7 @@ static int yuv4_read_header(AVFormatContext *s) st->codec->height = height; av_reduce(&raten, &rated, raten, rated, (1UL << 31) - 1); avpriv_set_pts_info(st, 64, rated, raten); + st->avg_frame_rate = av_inv_q(st->time_base); st->codec->pix_fmt = pix_fmt; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; |