summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
committerTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
commitf7813a5324be39d13ab536c245d15dfc602a7849 (patch)
treefad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavformat
parentb7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff)
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavformat')
-rw-r--r--ffmpeg/libavformat/4xm.c262
-rw-r--r--ffmpeg/libavformat/Makefile58
-rw-r--r--ffmpeg/libavformat/aacdec.c14
-rw-r--r--ffmpeg/libavformat/ac3dec.c6
-rw-r--r--ffmpeg/libavformat/act.c2
-rw-r--r--ffmpeg/libavformat/adtsenc.c31
-rw-r--r--ffmpeg/libavformat/adxdec.c16
-rw-r--r--ffmpeg/libavformat/afc.c4
-rw-r--r--ffmpeg/libavformat/aiff.h3
-rw-r--r--ffmpeg/libavformat/aiffdec.c33
-rw-r--r--ffmpeg/libavformat/aiffenc.c2
-rw-r--r--ffmpeg/libavformat/allformats.c26
-rw-r--r--ffmpeg/libavformat/amr.c3
-rw-r--r--ffmpeg/libavformat/apc.c10
-rw-r--r--ffmpeg/libavformat/ape.c57
-rw-r--r--ffmpeg/libavformat/apetag.c82
-rw-r--r--ffmpeg/libavformat/apetag.h4
-rw-r--r--ffmpeg/libavformat/apetagenc.c65
-rw-r--r--ffmpeg/libavformat/aqtitledec.c4
-rw-r--r--ffmpeg/libavformat/asf.c4
-rw-r--r--ffmpeg/libavformat/asf.h6
-rw-r--r--ffmpeg/libavformat/asfdec.c107
-rw-r--r--ffmpeg/libavformat/asfenc.c127
-rw-r--r--ffmpeg/libavformat/assdec.c2
-rw-r--r--ffmpeg/libavformat/assenc.c33
-rw-r--r--ffmpeg/libavformat/astdec.c15
-rw-r--r--ffmpeg/libavformat/au.c20
-rw-r--r--ffmpeg/libavformat/audiointerleave.c6
-rw-r--r--ffmpeg/libavformat/avformat.h194
-rw-r--r--ffmpeg/libavformat/avidec.c1091
-rw-r--r--ffmpeg/libavformat/avienc.c27
-rw-r--r--ffmpeg/libavformat/avio.c110
-rw-r--r--ffmpeg/libavformat/avio.h28
-rw-r--r--ffmpeg/libavformat/avio_internal.h48
-rw-r--r--ffmpeg/libavformat/aviobuf.c119
-rw-r--r--ffmpeg/libavformat/avisynth.c444
-rw-r--r--ffmpeg/libavformat/avr.c25
-rw-r--r--ffmpeg/libavformat/avs.c4
-rw-r--r--ffmpeg/libavformat/bethsoftvid.c3
-rw-r--r--ffmpeg/libavformat/bfi.c15
-rw-r--r--ffmpeg/libavformat/bink.c9
-rw-r--r--ffmpeg/libavformat/bintext.c49
-rw-r--r--ffmpeg/libavformat/bit.c3
-rw-r--r--ffmpeg/libavformat/bmv.c17
-rw-r--r--ffmpeg/libavformat/cafdec.c9
-rw-r--r--ffmpeg/libavformat/cafenc.c8
-rw-r--r--ffmpeg/libavformat/cavsvideodec.c2
-rw-r--r--ffmpeg/libavformat/cdxl.c2
-rw-r--r--ffmpeg/libavformat/concat.c9
-rw-r--r--ffmpeg/libavformat/concatdec.c8
-rw-r--r--ffmpeg/libavformat/crypto.c8
-rw-r--r--ffmpeg/libavformat/daud.c1
-rw-r--r--ffmpeg/libavformat/dfa.c13
-rw-r--r--ffmpeg/libavformat/diracdec.c15
-rw-r--r--ffmpeg/libavformat/dsicin.c2
-rw-r--r--ffmpeg/libavformat/dtsdec.c9
-rw-r--r--ffmpeg/libavformat/dv.c209
-rw-r--r--ffmpeg/libavformat/dvenc.c3
-rw-r--r--ffmpeg/libavformat/dxa.c10
-rw-r--r--ffmpeg/libavformat/electronicarts.c449
-rw-r--r--ffmpeg/libavformat/ffmdec.c12
-rw-r--r--ffmpeg/libavformat/ffmenc.c1
-rw-r--r--ffmpeg/libavformat/ffmetadec.c4
-rw-r--r--ffmpeg/libavformat/file.c26
-rw-r--r--ffmpeg/libavformat/flacdec.c132
-rw-r--r--ffmpeg/libavformat/flacenc.c7
-rw-r--r--ffmpeg/libavformat/flic.c10
-rw-r--r--ffmpeg/libavformat/flvdec.c868
-rw-r--r--ffmpeg/libavformat/flvenc.c36
-rw-r--r--ffmpeg/libavformat/framecrcenc.c21
-rw-r--r--ffmpeg/libavformat/framehash.c11
-rw-r--r--ffmpeg/libavformat/g723_1.c3
-rw-r--r--ffmpeg/libavformat/gif.c371
-rw-r--r--ffmpeg/libavformat/gifdec.c34
-rw-r--r--ffmpeg/libavformat/gsmdec.c12
-rw-r--r--ffmpeg/libavformat/gxf.c16
-rw-r--r--ffmpeg/libavformat/gxfenc.c100
-rw-r--r--ffmpeg/libavformat/h261dec.c41
-rw-r--r--ffmpeg/libavformat/h263dec.c4
-rw-r--r--ffmpeg/libavformat/h264dec.c54
-rw-r--r--ffmpeg/libavformat/hls.c96
-rw-r--r--ffmpeg/libavformat/hlsenc.c33
-rw-r--r--ffmpeg/libavformat/hlsproto.c14
-rw-r--r--ffmpeg/libavformat/http.c252
-rw-r--r--ffmpeg/libavformat/icodec.c2
-rw-r--r--ffmpeg/libavformat/icoenc.c2
-rw-r--r--ffmpeg/libavformat/id3v2.c354
-rw-r--r--ffmpeg/libavformat/id3v2enc.c99
-rw-r--r--ffmpeg/libavformat/idcin.c42
-rw-r--r--ffmpeg/libavformat/idroqdec.c7
-rw-r--r--ffmpeg/libavformat/iff.c6
-rw-r--r--ffmpeg/libavformat/ilbc.c1
-rw-r--r--ffmpeg/libavformat/img2.c5
-rw-r--r--ffmpeg/libavformat/img2dec.c65
-rw-r--r--ffmpeg/libavformat/img2enc.c86
-rw-r--r--ffmpeg/libavformat/internal.h76
-rw-r--r--ffmpeg/libavformat/ipmovie.c15
-rw-r--r--ffmpeg/libavformat/isom.c21
-rw-r--r--ffmpeg/libavformat/isom.h25
-rw-r--r--ffmpeg/libavformat/iss.c15
-rw-r--r--ffmpeg/libavformat/ivfenc.c1
-rw-r--r--ffmpeg/libavformat/jacosubdec.c7
-rw-r--r--ffmpeg/libavformat/jvdec.c46
-rw-r--r--ffmpeg/libavformat/latmenc.c10
-rw-r--r--ffmpeg/libavformat/libavformat.pc8
-rw-r--r--ffmpeg/libavformat/libmodplug.c21
-rw-r--r--ffmpeg/libavformat/libnut.c6
-rw-r--r--ffmpeg/libavformat/loasdec.c6
-rw-r--r--ffmpeg/libavformat/lvfdec.c10
-rw-r--r--ffmpeg/libavformat/lxfdec.c30
-rw-r--r--ffmpeg/libavformat/m4vdec.c2
-rw-r--r--ffmpeg/libavformat/matroska.c14
-rw-r--r--ffmpeg/libavformat/matroska.h9
-rw-r--r--ffmpeg/libavformat/matroskadec.c480
-rw-r--r--ffmpeg/libavformat/matroskaenc.c597
-rw-r--r--ffmpeg/libavformat/md5enc.c78
-rw-r--r--ffmpeg/libavformat/microdvddec.c4
-rw-r--r--ffmpeg/libavformat/microdvdenc.c1
-rw-r--r--ffmpeg/libavformat/mkvtimestamp_v2.c1
-rw-r--r--ffmpeg/libavformat/mm.c2
-rw-r--r--ffmpeg/libavformat/mmf.c79
-rw-r--r--ffmpeg/libavformat/mms.c2
-rw-r--r--ffmpeg/libavformat/mmsh.c33
-rw-r--r--ffmpeg/libavformat/mmst.c31
-rw-r--r--ffmpeg/libavformat/mov.c986
-rw-r--r--ffmpeg/libavformat/mov_chan.c8
-rw-r--r--ffmpeg/libavformat/mov_chan.h8
-rw-r--r--ffmpeg/libavformat/movenc.c1042
-rw-r--r--ffmpeg/libavformat/movenc.h18
-rw-r--r--ffmpeg/libavformat/movenchint.c46
-rw-r--r--ffmpeg/libavformat/mp3dec.c91
-rw-r--r--ffmpeg/libavformat/mp3enc.c6
-rw-r--r--ffmpeg/libavformat/mpc.c5
-rw-r--r--ffmpeg/libavformat/mpc8.c24
-rw-r--r--ffmpeg/libavformat/mpeg.c165
-rw-r--r--ffmpeg/libavformat/mpeg.h2
-rw-r--r--ffmpeg/libavformat/mpegenc.c37
-rw-r--r--ffmpeg/libavformat/mpegts.c320
-rw-r--r--ffmpeg/libavformat/mpegtsenc.c33
-rw-r--r--ffmpeg/libavformat/mpegvideodec.c25
-rw-r--r--ffmpeg/libavformat/mpjpeg.c1
-rw-r--r--ffmpeg/libavformat/mpl2dec.c10
-rw-r--r--ffmpeg/libavformat/mpsubdec.c16
-rw-r--r--ffmpeg/libavformat/mtv.c14
-rw-r--r--ffmpeg/libavformat/mux.c135
-rw-r--r--ffmpeg/libavformat/mvi.c10
-rw-r--r--ffmpeg/libavformat/mxfdec.c239
-rw-r--r--ffmpeg/libavformat/mxfenc.c78
-rw-r--r--ffmpeg/libavformat/mxg.c7
-rw-r--r--ffmpeg/libavformat/network.c199
-rw-r--r--ffmpeg/libavformat/network.h44
-rw-r--r--ffmpeg/libavformat/nistspheredec.c9
-rw-r--r--ffmpeg/libavformat/noproxy-test.c2
-rw-r--r--ffmpeg/libavformat/nsvdec.c32
-rw-r--r--ffmpeg/libavformat/nullenc.c2
-rw-r--r--ffmpeg/libavformat/nut.c297
-rw-r--r--ffmpeg/libavformat/nut.h9
-rw-r--r--ffmpeg/libavformat/nutdec.c71
-rw-r--r--ffmpeg/libavformat/nutenc.c30
-rw-r--r--ffmpeg/libavformat/nuv.c5
-rw-r--r--ffmpeg/libavformat/oggdec.c53
-rw-r--r--ffmpeg/libavformat/oggdec.h1
-rw-r--r--ffmpeg/libavformat/oggenc.c90
-rw-r--r--ffmpeg/libavformat/oggparsecelt.c17
-rw-r--r--ffmpeg/libavformat/oggparseflac.c30
-rw-r--r--ffmpeg/libavformat/oggparseogm.c67
-rw-r--r--ffmpeg/libavformat/oggparseopus.c132
-rw-r--r--ffmpeg/libavformat/oggparseskeleton.c13
-rw-r--r--ffmpeg/libavformat/oggparsespeex.c5
-rw-r--r--ffmpeg/libavformat/oggparsetheora.c138
-rw-r--r--ffmpeg/libavformat/oggparsevorbis.c242
-rw-r--r--ffmpeg/libavformat/oma.c16
-rw-r--r--ffmpeg/libavformat/oma.h11
-rw-r--r--ffmpeg/libavformat/omadec.c283
-rw-r--r--ffmpeg/libavformat/omaenc.c8
-rw-r--r--ffmpeg/libavformat/options.c2
-rw-r--r--ffmpeg/libavformat/options_table.h18
-rw-r--r--ffmpeg/libavformat/os_support.c62
-rw-r--r--ffmpeg/libavformat/os_support.h7
-rw-r--r--ffmpeg/libavformat/paf.c5
-rw-r--r--ffmpeg/libavformat/pjsdec.c4
-rw-r--r--ffmpeg/libavformat/pmpdec.c2
-rw-r--r--ffmpeg/libavformat/psxstr.c6
-rw-r--r--ffmpeg/libavformat/pva.c19
-rw-r--r--ffmpeg/libavformat/r3d.c8
-rw-r--r--ffmpeg/libavformat/rawdec.c31
-rw-r--r--ffmpeg/libavformat/rawdec.h2
-rw-r--r--ffmpeg/libavformat/rawenc.c39
-rw-r--r--ffmpeg/libavformat/rawvideodec.c30
-rw-r--r--ffmpeg/libavformat/rdt.c29
-rw-r--r--ffmpeg/libavformat/rdt.h2
-rw-r--r--ffmpeg/libavformat/realtextdec.c2
-rw-r--r--ffmpeg/libavformat/riff.c609
-rw-r--r--ffmpeg/libavformat/riff.h49
-rw-r--r--ffmpeg/libavformat/rl2.c14
-rw-r--r--ffmpeg/libavformat/rmdec.c95
-rw-r--r--ffmpeg/libavformat/rmenc.c2
-rw-r--r--ffmpeg/libavformat/rpl.c22
-rw-r--r--ffmpeg/libavformat/rtmp.h2
-rw-r--r--ffmpeg/libavformat/rtmphttp.c15
-rw-r--r--ffmpeg/libavformat/rtmppkt.c292
-rw-r--r--ffmpeg/libavformat/rtmppkt.h39
-rw-r--r--ffmpeg/libavformat/rtmpproto.c588
-rw-r--r--ffmpeg/libavformat/rtp.c3
-rw-r--r--ffmpeg/libavformat/rtp.h3
-rw-r--r--ffmpeg/libavformat/rtpdec.c11
-rw-r--r--ffmpeg/libavformat/rtpdec.h8
-rw-r--r--ffmpeg/libavformat/rtpdec_asf.c7
-rw-r--r--ffmpeg/libavformat/rtpdec_g726.c4
-rw-r--r--ffmpeg/libavformat/rtpdec_h263.c4
-rw-r--r--ffmpeg/libavformat/rtpdec_h263_rfc2190.c11
-rw-r--r--ffmpeg/libavformat/rtpdec_h264.c16
-rw-r--r--ffmpeg/libavformat/rtpdec_latm.c5
-rw-r--r--ffmpeg/libavformat/rtpdec_mpeg12.c5
-rw-r--r--ffmpeg/libavformat/rtpdec_mpeg4.c8
-rw-r--r--ffmpeg/libavformat/rtpdec_mpegts.c4
-rw-r--r--ffmpeg/libavformat/rtpdec_qdm2.c5
-rw-r--r--ffmpeg/libavformat/rtpdec_qt.c16
-rw-r--r--ffmpeg/libavformat/rtpdec_svq3.c5
-rw-r--r--ffmpeg/libavformat/rtpdec_xiph.c10
-rw-r--r--ffmpeg/libavformat/rtpenc.c28
-rw-r--r--ffmpeg/libavformat/rtpenc.h8
-rw-r--r--ffmpeg/libavformat/rtpenc_chain.c14
-rw-r--r--ffmpeg/libavformat/rtpenc_h263_rfc2190.c8
-rw-r--r--ffmpeg/libavformat/rtpenc_latm.c4
-rw-r--r--ffmpeg/libavformat/rtpenc_mpv.c4
-rw-r--r--ffmpeg/libavformat/rtpproto.c310
-rw-r--r--ffmpeg/libavformat/rtsp.c171
-rw-r--r--ffmpeg/libavformat/rtsp.h27
-rw-r--r--ffmpeg/libavformat/rtspdec.c5
-rw-r--r--ffmpeg/libavformat/rtspenc.c13
-rw-r--r--ffmpeg/libavformat/sapdec.c5
-rw-r--r--ffmpeg/libavformat/sapenc.c1
-rw-r--r--ffmpeg/libavformat/sbgdec.c6
-rw-r--r--ffmpeg/libavformat/sctp.c18
-rw-r--r--ffmpeg/libavformat/sdp.c14
-rw-r--r--ffmpeg/libavformat/seek-test.c5
-rw-r--r--ffmpeg/libavformat/seek.c5
-rw-r--r--ffmpeg/libavformat/seek.h1
-rw-r--r--ffmpeg/libavformat/segafilm.c61
-rw-r--r--ffmpeg/libavformat/segment.c112
-rw-r--r--ffmpeg/libavformat/sierravmd.c94
-rw-r--r--ffmpeg/libavformat/smacker.c61
-rw-r--r--ffmpeg/libavformat/smjpegenc.c1
-rw-r--r--ffmpeg/libavformat/smoothstreamingenc.c20
-rw-r--r--ffmpeg/libavformat/smush.c4
-rw-r--r--ffmpeg/libavformat/spdif.h6
-rw-r--r--ffmpeg/libavformat/spdifdec.c6
-rw-r--r--ffmpeg/libavformat/spdifenc.c11
-rw-r--r--ffmpeg/libavformat/srtdec.c8
-rw-r--r--ffmpeg/libavformat/srtenc.c1
-rw-r--r--ffmpeg/libavformat/srtp.c5
-rw-r--r--ffmpeg/libavformat/srtpproto.c3
-rw-r--r--ffmpeg/libavformat/subtitles.c92
-rw-r--r--ffmpeg/libavformat/subtitles.h25
-rw-r--r--ffmpeg/libavformat/subviewer1dec.c2
-rw-r--r--ffmpeg/libavformat/subviewerdec.c2
-rw-r--r--ffmpeg/libavformat/swf.h3
-rw-r--r--ffmpeg/libavformat/swfdec.c34
-rw-r--r--ffmpeg/libavformat/swfenc.c4
-rw-r--r--ffmpeg/libavformat/takdec.c39
-rw-r--r--ffmpeg/libavformat/tcp.c111
-rw-r--r--ffmpeg/libavformat/tedcaptionsdec.c5
-rw-r--r--ffmpeg/libavformat/tee.c282
-rw-r--r--ffmpeg/libavformat/thp.c28
-rw-r--r--ffmpeg/libavformat/tls.c193
-rw-r--r--ffmpeg/libavformat/tta.c78
-rw-r--r--ffmpeg/libavformat/tty.c27
-rw-r--r--ffmpeg/libavformat/udp.c139
-rw-r--r--ffmpeg/libavformat/url-test.c2
-rw-r--r--ffmpeg/libavformat/url.h45
-rw-r--r--ffmpeg/libavformat/utils.c1163
-rw-r--r--ffmpeg/libavformat/vc1test.c7
-rw-r--r--ffmpeg/libavformat/vc1testenc.c1
-rw-r--r--ffmpeg/libavformat/version.h16
-rw-r--r--ffmpeg/libavformat/vocdec.c12
-rw-r--r--ffmpeg/libavformat/vorbiscomment.c1
-rw-r--r--ffmpeg/libavformat/vqf.c30
-rw-r--r--ffmpeg/libavformat/w64.c33
-rw-r--r--ffmpeg/libavformat/wavdec.c196
-rw-r--r--ffmpeg/libavformat/wavenc.c5
-rw-r--r--ffmpeg/libavformat/webvttdec.c69
-rw-r--r--ffmpeg/libavformat/westwood_aud.c2
-rw-r--r--ffmpeg/libavformat/westwood_vqa.c29
-rw-r--r--ffmpeg/libavformat/wtv.c82
-rw-r--r--ffmpeg/libavformat/wtv.h2
-rw-r--r--ffmpeg/libavformat/wtvdec.c55
-rw-r--r--ffmpeg/libavformat/wtvenc.c93
-rw-r--r--ffmpeg/libavformat/wv.c387
-rw-r--r--ffmpeg/libavformat/wvenc.c133
-rw-r--r--ffmpeg/libavformat/xa.c5
-rw-r--r--ffmpeg/libavformat/xmv.c56
-rw-r--r--ffmpeg/libavformat/xwma.c7
-rw-r--r--ffmpeg/libavformat/yop.c13
-rw-r--r--ffmpeg/libavformat/yuv4mpeg.c6
295 files changed, 12119 insertions, 8089 deletions
diff --git a/ffmpeg/libavformat/4xm.c b/ffmpeg/libavformat/4xm.c
index 1e142f5..23279c4 100644
--- a/ffmpeg/libavformat/4xm.c
+++ b/ffmpeg/libavformat/4xm.c
@@ -57,7 +57,7 @@
#define GET_LIST_HEADER() \
fourcc_tag = avio_rl32(pb); \
- size = avio_rl32(pb); \
+ size = avio_rl32(pb); \
if (fourcc_tag != LIST_TAG) \
return AVERROR_INVALIDDATA; \
fourcc_tag = avio_rl32(pb);
@@ -72,8 +72,6 @@ typedef struct AudioTrack {
} AudioTrack;
typedef struct FourxmDemuxContext {
- int width;
- int height;
int video_stream_index;
int track_count;
AudioTrack *tracks;
@@ -91,6 +89,108 @@ static int fourxm_probe(AVProbeData *p)
return AVPROBE_SCORE_MAX;
}
+static int parse_vtrk(AVFormatContext *s,
+ FourxmDemuxContext *fourxm, uint8_t *buf, int size,
+ int left)
+{
+ AVStream *st;
+ /* check that there is enough data */
+ if (size != vtrk_SIZE || left < size + 8) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* allocate a new AVStream */
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avpriv_set_pts_info(st, 60, 1, fourxm->fps);
+
+ fourxm->video_stream_index = st->index;
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_4XM;
+ st->codec->extradata_size = 4;
+ st->codec->extradata = av_malloc(4);
+ AV_WL32(st->codec->extradata, AV_RL32(buf + 16));
+ st->codec->width = AV_RL32(buf + 36);
+ st->codec->height = AV_RL32(buf + 40);
+
+ return 0;
+}
+
+
+static int parse_strk(AVFormatContext *s,
+ FourxmDemuxContext *fourxm, uint8_t *buf, int size,
+ int left)
+{
+ AVStream *st;
+ int track;
+ /* check that there is enough data */
+ if (size != strk_SIZE || left < size + 8)
+ return AVERROR_INVALIDDATA;
+
+ track = AV_RL32(buf + 8);
+ if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) {
+ av_log(s, AV_LOG_ERROR, "current_track too large\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (track + 1 > fourxm->track_count) {
+ if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack)))
+ return AVERROR(ENOMEM);
+ memset(&fourxm->tracks[fourxm->track_count], 0,
+ sizeof(AudioTrack) * (track + 1 - fourxm->track_count));
+ fourxm->track_count = track + 1;
+ }
+ fourxm->tracks[track].adpcm = AV_RL32(buf + 12);
+ fourxm->tracks[track].channels = AV_RL32(buf + 36);
+ fourxm->tracks[track].sample_rate = AV_RL32(buf + 40);
+ fourxm->tracks[track].bits = AV_RL32(buf + 44);
+ fourxm->tracks[track].audio_pts = 0;
+
+ if (fourxm->tracks[track].channels <= 0 ||
+ fourxm->tracks[track].sample_rate <= 0 ||
+ fourxm->tracks[track].bits <= 0) {
+ av_log(s, AV_LOG_ERROR, "audio header invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) {
+ av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* allocate a new AVStream */
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->id = track;
+ avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate);
+
+ fourxm->tracks[track].stream_index = st->index;
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_tag = 0;
+ st->codec->channels = fourxm->tracks[track].channels;
+ st->codec->sample_rate = fourxm->tracks[track].sample_rate;
+ st->codec->bits_per_coded_sample = fourxm->tracks[track].bits;
+ st->codec->bit_rate = st->codec->channels *
+ st->codec->sample_rate *
+ st->codec->bits_per_coded_sample;
+ st->codec->block_align = st->codec->channels *
+ st->codec->bits_per_coded_sample;
+
+ if (fourxm->tracks[track].adpcm){
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
+ } else if (st->codec->bits_per_coded_sample == 8) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_U8;
+ } else
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+
+ return 0;
+}
+
static int fourxm_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
@@ -100,11 +200,10 @@ static int fourxm_read_header(AVFormatContext *s)
FourxmDemuxContext *fourxm = s->priv_data;
unsigned char *header;
int i, ret;
- AVStream *st;
fourxm->track_count = 0;
- fourxm->tracks = NULL;
- fourxm->fps = 1.0;
+ fourxm->tracks = NULL;
+ fourxm->fps = 1.0;
/* skip the first 3 32-bit numbers */
avio_skip(pb, 12);
@@ -119,7 +218,7 @@ static int fourxm_read_header(AVFormatContext *s)
header = av_malloc(header_size);
if (!header)
return AVERROR(ENOMEM);
- if (avio_read(pb, header, header_size) != header_size){
+ if (avio_read(pb, header, header_size) != header_size) {
av_free(header);
return AVERROR(EIO);
}
@@ -127,123 +226,38 @@ static int fourxm_read_header(AVFormatContext *s)
/* take the lazy approach and search for any and all vtrk and strk chunks */
for (i = 0; i < header_size - 8; i++) {
fourcc_tag = AV_RL32(&header[i]);
- size = AV_RL32(&header[i + 4]);
+ size = AV_RL32(&header[i + 4]);
if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
return AVERROR_INVALIDDATA;
}
if (fourcc_tag == std__TAG) {
- if (header_size < i + 16) {
+ if (header_size - i < 16) {
av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
} else if (fourcc_tag == vtrk_TAG) {
- /* check that there is enough data */
- if (size != vtrk_SIZE) {
- ret= AVERROR_INVALIDDATA;
+ if ((ret = parse_vtrk(s, fourxm, header + i, size,
+ header_size - i)) < 0)
goto fail;
- }
- fourxm->width = AV_RL32(&header[i + 36]);
- fourxm->height = AV_RL32(&header[i + 40]);
-
- /* allocate a new AVStream */
- st = avformat_new_stream(s, NULL);
- if (!st){
- ret= AVERROR(ENOMEM);
- goto fail;
- }
- avpriv_set_pts_info(st, 60, 1, fourxm->fps);
-
- fourxm->video_stream_index = st->index;
-
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_4XM;
- st->codec->extradata_size = 4;
- st->codec->extradata = av_malloc(4);
- AV_WL32(st->codec->extradata, AV_RL32(&header[i + 16]));
- st->codec->width = fourxm->width;
- st->codec->height = fourxm->height;
i += 8 + size;
} else if (fourcc_tag == strk_TAG) {
- int current_track;
- /* check that there is enough data */
- if (size != strk_SIZE) {
- ret= AVERROR_INVALIDDATA;
- goto fail;
- }
- current_track = AV_RL32(&header[i + 8]);
- if((unsigned)current_track >= UINT_MAX / sizeof(AudioTrack) - 1){
- av_log(s, AV_LOG_ERROR, "current_track too large\n");
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- if (current_track + 1 > fourxm->track_count) {
- fourxm->tracks = av_realloc_f(fourxm->tracks,
- sizeof(AudioTrack),
- current_track + 1);
- if (!fourxm->tracks) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- memset(&fourxm->tracks[fourxm->track_count], 0,
- sizeof(AudioTrack) * (current_track + 1 - fourxm->track_count));
- fourxm->track_count = current_track + 1;
- }
- fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]);
- fourxm->tracks[current_track].channels = AV_RL32(&header[i + 36]);
- fourxm->tracks[current_track].sample_rate = AV_RL32(&header[i + 40]);
- fourxm->tracks[current_track].bits = AV_RL32(&header[i + 44]);
- fourxm->tracks[current_track].audio_pts = 0;
- if( fourxm->tracks[current_track].channels <= 0
- || fourxm->tracks[current_track].sample_rate <= 0
- || fourxm->tracks[current_track].bits < 0){
- av_log(s, AV_LOG_ERROR, "audio header invalid\n");
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- if(!fourxm->tracks[current_track].adpcm && fourxm->tracks[current_track].bits<8){
- av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- i += 8 + size;
-
- /* allocate a new AVStream */
- st = avformat_new_stream(s, NULL);
- if (!st){
- ret= AVERROR(ENOMEM);
+ if ((ret = parse_strk(s, fourxm, header + i, size,
+ header_size - i)) < 0)
goto fail;
- }
- st->id = current_track;
- avpriv_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate);
-
- fourxm->tracks[current_track].stream_index = st->index;
-
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_tag = 0;
- st->codec->channels = fourxm->tracks[current_track].channels;
- st->codec->sample_rate = fourxm->tracks[current_track].sample_rate;
- st->codec->bits_per_coded_sample = fourxm->tracks[current_track].bits;
- st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
- st->codec->bits_per_coded_sample;
- st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
- if (fourxm->tracks[current_track].adpcm){
- st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
- }else if (st->codec->bits_per_coded_sample == 8){
- st->codec->codec_id = AV_CODEC_ID_PCM_U8;
- }else
- st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ i += 8 + size;
}
}
/* skip over the LIST-MOVI chunk (which is where the stream should be */
GET_LIST_HEADER();
- if (fourcc_tag != MOVI_TAG){
- ret= AVERROR_INVALIDDATA;
+ if (fourcc_tag != MOVI_TAG) {
+ ret = AVERROR_INVALIDDATA;
goto fail;
}
@@ -262,7 +276,7 @@ static int fourxm_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
FourxmDemuxContext *fourxm = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
unsigned int fourcc_tag;
unsigned int size;
int ret = 0;
@@ -272,18 +286,16 @@ static int fourxm_read_packet(AVFormatContext *s,
int audio_frame_count;
while (!packet_read) {
-
if ((ret = avio_read(s->pb, header, 8)) < 0)
return ret;
fourcc_tag = AV_RL32(&header[0]);
- size = AV_RL32(&header[4]);
+ size = AV_RL32(&header[4]);
if (url_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
-
case LIST_TAG:
/* this is a good time to bump the video pts */
- fourxm->video_pts ++;
+ fourxm->video_pts++;
/* skip the LIST-* tag and move on to the next fourcc */
avio_rl32(pb);
@@ -300,45 +312,45 @@ static int fourxm_read_packet(AVFormatContext *s,
if (size + 8 < size || av_new_packet(pkt, size + 8))
return AVERROR(EIO);
pkt->stream_index = fourxm->video_stream_index;
- pkt->pts = fourxm->video_pts;
- pkt->pos = avio_tell(s->pb);
+ pkt->pts = fourxm->video_pts;
+ pkt->pos = avio_tell(s->pb);
memcpy(pkt->data, header, 8);
ret = avio_read(s->pb, &pkt->data[8], size);
- if (ret < 0){
+ if (ret < 0) {
av_free_packet(pkt);
- }else
+ } else {
packet_read = 1;
+ av_shrink_packet(pkt, ret + 8);
+ }
break;
case snd__TAG:
track_number = avio_rl32(pb);
avio_skip(pb, 4);
- size-=8;
+ size -= 8;
- if (track_number < fourxm->track_count && fourxm->tracks[track_number].channels>0) {
- ret= av_get_packet(s->pb, pkt, size);
- if(ret<0)
+ if (track_number < fourxm->track_count &&
+ fourxm->tracks[track_number].channels > 0) {
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret < 0)
return AVERROR(EIO);
pkt->stream_index =
fourxm->tracks[track_number].stream_index;
- pkt->pts = fourxm->tracks[track_number].audio_pts;
+ pkt->pts = fourxm->tracks[track_number].audio_pts;
packet_read = 1;
/* pts accounting */
audio_frame_count = size;
if (fourxm->tracks[track_number].adpcm)
- audio_frame_count -=
- 2 * (fourxm->tracks[track_number].channels);
- audio_frame_count /=
- fourxm->tracks[track_number].channels;
- if (fourxm->tracks[track_number].adpcm){
+ audio_frame_count -= 2 * (fourxm->tracks[track_number].channels);
+ audio_frame_count /= fourxm->tracks[track_number].channels;
+ if (fourxm->tracks[track_number].adpcm) {
audio_frame_count *= 2;
- }else
+ } else
audio_frame_count /=
- (fourxm->tracks[track_number].bits / 8);
+ (fourxm->tracks[track_number].bits / 8);
fourxm->tracks[track_number].audio_pts += audio_frame_count;
-
} else {
avio_skip(pb, size);
}
diff --git a/ffmpeg/libavformat/Makefile b/ffmpeg/libavformat/Makefile
index bc6ea16..dc8cac6 100644
--- a/ffmpeg/libavformat/Makefile
+++ b/ffmpeg/libavformat/Makefile
@@ -11,6 +11,7 @@ OBJS = allformats.o \
avio.o \
aviobuf.o \
cutils.o \
+ format.o \
id3v1.o \
id3v2.o \
metadata.o \
@@ -20,9 +21,12 @@ OBJS = allformats.o \
riff.o \
sdp.o \
seek.o \
+ url.o \
utils.o \
OBJS-$(CONFIG_NETWORK) += network.o
+OBJS-$(CONFIG_RIFFDEC) += riffdec.o
+OBJS-$(CONFIG_RIFFENC) += riffenc.o
OBJS-$(CONFIG_RTPDEC) += rdt.o \
rtp.o \
rtpdec.o \
@@ -50,14 +54,15 @@ OBJS-$(CONFIG_SHARED) += log2_tab.o
# muxers/demuxers
OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o
-OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o rawdec.o
+OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o apetag.o img2.o rawdec.o
OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o
OBJS-$(CONFIG_AC3_MUXER) += rawenc.o
OBJS-$(CONFIG_ACT_DEMUXER) += act.o
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
+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 \
@@ -91,6 +96,7 @@ OBJS-$(CONFIG_BINTEXT_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_BIT_DEMUXER) += bit.o
OBJS-$(CONFIG_BIT_MUXER) += bit.o
OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o
+OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o
OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o
OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o
OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \
@@ -102,6 +108,8 @@ OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o
OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o
OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
+OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o
+OBJS-$(CONFIG_DATA_MUXER) += rawdec.o
OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o
OBJS-$(CONFIG_DAUD_MUXER) += daud.o
OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o
@@ -128,6 +136,7 @@ OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o
OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o
OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o
OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \
+ flac_picture.o \
oggparsevorbis.o \
vorbiscomment.o
OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
@@ -155,8 +164,11 @@ OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o
OBJS-$(CONFIG_H263_MUXER) += rawenc.o
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_HLS_DEMUXER) += hls.o
-OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o mpegtsenc.o
+OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o
+OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o
OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o
OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
@@ -191,7 +203,7 @@ OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \
isom.o rmsipr.o
OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
- flacenc_header.o avlanguage.o
+ flacenc_header.o avlanguage.o wv.o
OBJS-$(CONFIG_MD5_MUXER) += md5enc.o
OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o
OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o
@@ -249,11 +261,14 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
oggparsespeex.o \
oggparsetheora.o \
oggparsevorbis.o \
- vorbiscomment.o
+ vorbiscomment.o \
+ flac_picture.o
OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \
vorbiscomment.o
OBJS-$(CONFIG_OMA_DEMUXER) += omadec.o pcm.o oma.o
OBJS-$(CONFIG_OMA_MUXER) += omaenc.o rawenc.o oma.o id3v2enc.o
+OBJS-$(CONFIG_OPUS_MUXER) += oggenc.o \
+ vorbiscomment.o
OBJS-$(CONFIG_PAF_DEMUXER) += paf.o
OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_ALAW_MUXER) += pcmenc.o rawenc.o
@@ -304,11 +319,13 @@ OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o
OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o
OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o
+OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o
OBJS-$(CONFIG_RL2_DEMUXER) += rl2.o
OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o
OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o
OBJS-$(CONFIG_ROQ_DEMUXER) += idroqdec.o
OBJS-$(CONFIG_ROQ_MUXER) += idroqenc.o rawenc.o
+OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o
OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o
OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o
OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o
@@ -348,6 +365,8 @@ OBJS-$(CONFIG_SOX_DEMUXER) += soxdec.o pcm.o
OBJS-$(CONFIG_SOX_MUXER) += soxenc.o rawenc.o
OBJS-$(CONFIG_SPDIF_DEMUXER) += spdif.o spdifdec.o
OBJS-$(CONFIG_SPDIF_MUXER) += spdif.o spdifenc.o
+OBJS-$(CONFIG_SPEEX_MUXER) += oggenc.o \
+ vorbiscomment.o
OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o
OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
@@ -364,10 +383,11 @@ OBJS-$(CONFIG_MKVTIMESTAMP_V2_MUXER) += mkvtimestamp_v2.o
OBJS-$(CONFIG_TMV_DEMUXER) += tmv.o
OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o
OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o
-OBJS-$(CONFIG_TTA_DEMUXER) += tta.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_VC1_DEMUXER) += rawdec.o
+OBJS-$(CONFIG_VC1_MUXER) += rawenc.o
OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o
OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o
OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o
@@ -384,15 +404,16 @@ OBJS-$(CONFIG_WAV_MUXER) += wavenc.o
OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o
OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
- flacenc_header.o avlanguage.o
+ flacenc_header.o avlanguage.o wv.o
OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o
+OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o
OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o
-OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv.o asfdec.o asf.o asfcrypt.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.o asf.o asfenc.o
-OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o img2.o
-OBJS-$(CONFIG_WV_MUXER) += wvenc.o apetagenc.o
+OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o asf.o asfenc.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
OBJS-$(CONFIG_XBIN_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o
@@ -402,10 +423,13 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o
# external libraries
+OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o
OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o
OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o
OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o
+OBJS-$(CONFIG_LIBQUVI_DEMUXER) += libquvi.o
OBJS-$(CONFIG_LIBRTMP) += librtmp.o
+OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
# protocols I/O
OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o
@@ -417,6 +441,7 @@ OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o
OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
+OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o
OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o
OBJS-$(CONFIG_HLS_PROTOCOL) += hlsproto.o
OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o urldecode.o
@@ -438,14 +463,21 @@ OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
+OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
+
+OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
-TESTPROGS = noproxy \
- seek \
+TESTPROGS = seek \
srtp \
url \
+TESTPROGS-$(CONFIG_NETWORK) += noproxy
+
TOOLS = aviocat \
ismindex \
pktdumper \
diff --git a/ffmpeg/libavformat/aacdec.c b/ffmpeg/libavformat/aacdec.c
index 7c17dd0..d93e75e 100644
--- a/ffmpeg/libavformat/aacdec.c
+++ b/ffmpeg/libavformat/aacdec.c
@@ -25,7 +25,7 @@
#include "internal.h"
#include "rawdec.h"
#include "id3v1.h"
-
+#include "apetag.h"
static int adts_aac_probe(AVProbeData *p)
{
@@ -55,9 +55,9 @@ static int adts_aac_probe(AVProbeData *p)
if(buf == buf0)
first_frames= frames;
}
- if (first_frames>=3) return AVPROBE_SCORE_MAX/2+1;
- else if(max_frames>500)return AVPROBE_SCORE_MAX/2;
- else if(max_frames>=3) return AVPROBE_SCORE_MAX/4;
+ 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;
}
@@ -75,6 +75,12 @@ static int adts_aac_read_header(AVFormatContext *s)
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
ff_id3v1_read(s);
+ if (s->pb->seekable &&
+ !av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ int64_t cur = avio_tell(s->pb);
+ ff_ape_parse_tag(s);
+ avio_seek(s->pb, cur, SEEK_SET);
+ }
//LCM of all possible ADTS sample rates
avpriv_set_pts_info(st, 64, 1, 28224000);
diff --git a/ffmpeg/libavformat/ac3dec.c b/ffmpeg/libavformat/ac3dec.c
index c531f8a..3db2339 100644
--- a/ffmpeg/libavformat/ac3dec.c
+++ b/ffmpeg/libavformat/ac3dec.c
@@ -79,9 +79,9 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
if(codec_id != expected_codec_id) return 0;
// keep this in sync with mp3 probe, both need to avoid
// issues with MPEG-files!
- if (first_frames>=4) return AVPROBE_SCORE_MAX/2+1;
- else if(max_frames>200)return AVPROBE_SCORE_MAX/2;
- else if(max_frames>=4) return AVPROBE_SCORE_MAX/4;
+ 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>=1) return 1;
else return 0;
}
diff --git a/ffmpeg/libavformat/act.c b/ffmpeg/libavformat/act.c
index 78f1d3b..3f223d5 100644
--- a/ffmpeg/libavformat/act.c
+++ b/ffmpeg/libavformat/act.c
@@ -42,7 +42,7 @@ static int probe(AVProbeData *p)
(AV_RL32(&p->buf[16]) != 16))
return 0;
- //We cant be sure that this is ACT and not regular WAV
+ //We can't be sure that this is ACT and not regular WAV
if (p->buf_size<512)
return 0;
diff --git a/ffmpeg/libavformat/adtsenc.c b/ffmpeg/libavformat/adtsenc.c
index 14c72a8..f25f966 100644
--- a/ffmpeg/libavformat/adtsenc.c
+++ b/ffmpeg/libavformat/adtsenc.c
@@ -24,16 +24,20 @@
#include "libavcodec/put_bits.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavutil/opt.h"
#include "avformat.h"
+#include "apetag.h"
#define ADTS_HEADER_SIZE 7
typedef struct {
+ AVClass *class;
int write_adts;
int objecttype;
int sample_rate_index;
int channel_conf;
int pce_size;
+ int apetag;
uint8_t pce_data[MAX_PCE_SIZE];
} ADTSContext;
@@ -158,11 +162,34 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
}
}
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
return 0;
}
+static int adts_write_trailer(AVFormatContext *s)
+{
+ ADTSContext *adts = s->priv_data;
+
+ if (adts->apetag)
+ ff_ape_write_tag(s);
+
+ return 0;
+}
+
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+#define OFFSET(obj) offsetof(ADTSContext, obj)
+static const AVOption options[] = {
+ { "write_apetag", "Enable APE tag writing", OFFSET(apetag), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC},
+ { NULL },
+};
+
+static const AVClass adts_muxer_class = {
+ .class_name = "ADTS muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_adts_muxer = {
.name = "adts",
.long_name = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"),
@@ -173,4 +200,6 @@ AVOutputFormat ff_adts_muxer = {
.video_codec = AV_CODEC_ID_NONE,
.write_header = adts_write_header,
.write_packet = adts_write_packet,
+ .write_trailer = adts_write_trailer,
+ .priv_class = &adts_muxer_class,
};
diff --git a/ffmpeg/libavformat/adxdec.c b/ffmpeg/libavformat/adxdec.c
index 49e1930..fe22c3a 100644
--- a/ffmpeg/libavformat/adxdec.c
+++ b/ffmpeg/libavformat/adxdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -78,14 +78,8 @@ static int adx_read_header(AVFormatContext *s)
c->header_size = avio_rb16(s->pb) + 4;
avio_seek(s->pb, -4, SEEK_CUR);
- avctx->extradata = av_mallocz(c->header_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ 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/ffmpeg/libavformat/afc.c b/ffmpeg/libavformat/afc.c
index 183a8e0..8dbd232 100644
--- a/ffmpeg/libavformat/afc.c
+++ b/ffmpeg/libavformat/afc.c
@@ -39,10 +39,8 @@ static int afc_read_header(AVFormatContext *s)
st->codec->codec_id = AV_CODEC_ID_ADPCM_AFC;
st->codec->channels = 2;
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- st->codec->extradata_size = 1;
- st->codec->extradata = av_mallocz(1 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 1))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 8 * st->codec->channels;
diff --git a/ffmpeg/libavformat/aiff.h b/ffmpeg/libavformat/aiff.h
index b3ef577..4470254 100644
--- a/ffmpeg/libavformat/aiff.h
+++ b/ffmpeg/libavformat/aiff.h
@@ -45,7 +45,8 @@ static const AVCodecTag ff_codec_aiff_tags[] = {
{ AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') },
{ AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') },
{ AV_CODEC_ID_GSM, MKTAG('G','S','M',' ') },
- { AV_CODEC_ID_ADPCM_G726, MKTAG('G','7','2','6') },
+ { AV_CODEC_ID_ADPCM_G722, MKTAG('G','7','2','2') },
+ { AV_CODEC_ID_ADPCM_G726LE, MKTAG('G','7','2','6') },
{ AV_CODEC_ID_PCM_S16BE, MKTAG('t','w','o','s') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') },
{ AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
diff --git a/ffmpeg/libavformat/aiffdec.c b/ffmpeg/libavformat/aiffdec.c
index 8d466fa..c362071 100644
--- a/ffmpeg/libavformat/aiffdec.c
+++ b/ffmpeg/libavformat/aiffdec.c
@@ -141,15 +141,15 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size,
case AV_CODEC_ID_MACE3:
codec->block_align = 2*codec->channels;
break;
+ case AV_CODEC_ID_ADPCM_G726LE:
+ codec->bits_per_coded_sample = 5;
+ case AV_CODEC_ID_ADPCM_G722:
case AV_CODEC_ID_MACE6:
codec->block_align = 1*codec->channels;
break;
case AV_CODEC_ID_GSM:
codec->block_align = 33;
break;
- case AV_CODEC_ID_QCELP:
- codec->block_align = 35;
- break;
default:
aiff->block_duration = 1;
break;
@@ -192,7 +192,7 @@ static int aiff_probe(AVProbeData *p)
static int aiff_read_header(AVFormatContext *s)
{
int ret, size, filesize;
- int64_t offset = 0;
+ int64_t offset = 0, position;
uint32_t tag;
unsigned version = AIFF_C_VERSION1;
AVIOContext *pb = s->pb;
@@ -236,6 +236,7 @@ static int aiff_read_header(AVFormatContext *s)
goto got_sound;
break;
case MKTAG('I', 'D', '3', ' '):
+ position = avio_tell(pb);
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (id3v2_extra_meta)
if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) {
@@ -243,6 +244,8 @@ static int aiff_read_header(AVFormatContext *s)
return ret;
}
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+ if (position + size > avio_tell(pb))
+ avio_skip(pb, position + size - avio_tell(pb));
break;
case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */
version = avio_rb32(pb);
@@ -275,14 +278,26 @@ static int aiff_read_header(AVFormatContext *s)
case MKTAG('w', 'a', 'v', 'e'):
if ((uint64_t)size > (1<<30))
return -1;
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = size;
- 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);
+ } else if (st->codec->codec_id == AV_CODEC_ID_QCELP) {
+ char rate = 0;
+ if (size >= 25)
+ rate = st->codec->extradata[24];
+ switch (rate) {
+ case 'H': // RATE_HALF
+ st->codec->block_align = 17;
+ break;
+ case 'F': // RATE_FULL
+ default:
+ st->codec->block_align = 35;
+ }
+ aiff->block_duration = 160;
+ st->codec->bit_rate = st->codec->sample_rate * (st->codec->block_align << 3) /
+ aiff->block_duration;
}
break;
case MKTAG('C','H','A','N'):
@@ -329,7 +344,7 @@ static int aiff_read_packet(AVFormatContext *s,
return AVERROR_EOF;
/* Now for that packet */
- if (st->codec->block_align >= 33) // GSM, QCLP, IMA4
+ if (st->codec->block_align >= 17) // GSM, QCLP, IMA4
size = st->codec->block_align;
else
size = (MAX_SIZE / st->codec->block_align) * st->codec->block_align;
diff --git a/ffmpeg/libavformat/aiffenc.c b/ffmpeg/libavformat/aiffenc.c
index 7c0b4fb..6e3d8bc 100644
--- a/ffmpeg/libavformat/aiffenc.c
+++ b/ffmpeg/libavformat/aiffenc.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "libavutil/intfloat.h"
#include "libavutil/opt.h"
#include "avformat.h"
diff --git a/ffmpeg/libavformat/allformats.c b/ffmpeg/libavformat/allformats.c
index 8c746ff..f1039dd 100644
--- a/ffmpeg/libavformat/allformats.c
+++ b/ffmpeg/libavformat/allformats.c
@@ -45,8 +45,7 @@
{ \
extern URLProtocol ff_##x##_protocol; \
if (CONFIG_##X##_PROTOCOL) \
- ffurl_register_protocol(&ff_##x##_protocol, \
- sizeof(ff_##x##_protocol)); \
+ ffurl_register_protocol(&ff_##x##_protocol); \
}
void av_register_all(void)
@@ -65,6 +64,7 @@ void av_register_all(void)
REGISTER_MUXDEMUX(AC3, ac3);
REGISTER_DEMUXER (ACT, act);
REGISTER_DEMUXER (ADF, adf);
+ REGISTER_DEMUXER (ADP, adp);
REGISTER_MUXER (ADTS, adts);
REGISTER_MUXDEMUX(ADX, adx);
REGISTER_DEMUXER (AEA, aea);
@@ -92,6 +92,7 @@ void av_register_all(void)
REGISTER_MUXDEMUX(BIT, bit);
REGISTER_DEMUXER (BMV, bmv);
REGISTER_DEMUXER (BRSTM, brstm);
+ REGISTER_DEMUXER (BOA, boa);
REGISTER_DEMUXER (C93, c93);
REGISTER_MUXDEMUX(CAF, caf);
REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo);
@@ -99,6 +100,7 @@ void av_register_all(void)
REGISTER_DEMUXER (CDXL, cdxl);
REGISTER_DEMUXER (CONCAT, concat);
REGISTER_MUXER (CRC, crc);
+ REGISTER_MUXDEMUX(DATA, data);
REGISTER_MUXDEMUX(DAUD, daud);
REGISTER_DEMUXER (DFA, dfa);
REGISTER_MUXDEMUX(DIRAC, dirac);
@@ -132,7 +134,10 @@ void av_register_all(void)
REGISTER_MUXDEMUX(H261, h261);
REGISTER_MUXDEMUX(H263, h263);
REGISTER_MUXDEMUX(H264, h264);
+ REGISTER_MUXER (HDS, hds);
+ REGISTER_DEMUXER (HEVC, hevc);
REGISTER_MUXDEMUX(HLS, hls);
+ REGISTER_DEMUXER (HNM, hnm);
REGISTER_MUXDEMUX(ICO, ico);
REGISTER_DEMUXER (IDCIN, idcin);
REGISTER_DEMUXER (IDF, idf);
@@ -200,6 +205,7 @@ void av_register_all(void)
REGISTER_DEMUXER (NUV, nuv);
REGISTER_MUXDEMUX(OGG, ogg);
REGISTER_MUXDEMUX(OMA, oma);
+ REGISTER_MUXER (OPUS, opus);
REGISTER_DEMUXER (PAF, paf);
REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw);
REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw);
@@ -230,10 +236,12 @@ void av_register_all(void)
REGISTER_DEMUXER (R3D, r3d);
REGISTER_MUXDEMUX(RAWVIDEO, rawvideo);
REGISTER_DEMUXER (REALTEXT, realtext);
+ REGISTER_DEMUXER (REDSPARK, redspark);
REGISTER_DEMUXER (RL2, rl2);
REGISTER_MUXDEMUX(RM, rm);
REGISTER_MUXDEMUX(ROQ, roq);
REGISTER_DEMUXER (RPL, rpl);
+ REGISTER_DEMUXER (RSD, rsd);
REGISTER_MUXDEMUX(RSO, rso);
REGISTER_MUXDEMUX(RTP, rtp);
REGISTER_MUXDEMUX(RTSP, rtsp);
@@ -242,8 +250,8 @@ void av_register_all(void)
REGISTER_DEMUXER (SBG, sbg);
REGISTER_DEMUXER (SDP, sdp);
#if CONFIG_RTPDEC
- av_register_rtp_dynamic_payload_handlers();
- av_register_rdt_dynamic_payload_handlers();
+ ff_register_rtp_dynamic_payload_handlers();
+ ff_register_rdt_dynamic_payload_handlers();
#endif
REGISTER_DEMUXER (SEGAFILM, segafilm);
REGISTER_MUXER (SEGMENT, segment);
@@ -257,13 +265,14 @@ void av_register_all(void)
REGISTER_DEMUXER (SOL, sol);
REGISTER_MUXDEMUX(SOX, sox);
REGISTER_MUXDEMUX(SPDIF, spdif);
+ REGISTER_MUXER (SPEEX, speex);
REGISTER_MUXDEMUX(SRT, srt);
REGISTER_DEMUXER (STR, str);
REGISTER_DEMUXER (SUBVIEWER1, subviewer1);
REGISTER_DEMUXER (SUBVIEWER, subviewer);
REGISTER_MUXDEMUX(SWF, swf);
REGISTER_DEMUXER (TAK, tak);
- REGISTER_MUXER (TEE, tee);
+ REGISTER_MUXER (TEE, tee);
REGISTER_DEMUXER (TEDCAPTIONS, tedcaptions);
REGISTER_MUXER (TG2, tg2);
REGISTER_MUXER (TGP, tgp);
@@ -287,7 +296,7 @@ void av_register_all(void)
REGISTER_MUXDEMUX(WAV, wav);
REGISTER_DEMUXER (WC3, wc3);
REGISTER_MUXER (WEBM, webm);
- REGISTER_DEMUXER (WEBVTT, webvtt);
+ REGISTER_MUXDEMUX(WEBVTT, webvtt);
REGISTER_DEMUXER (WSAUD, wsaud);
REGISTER_DEMUXER (WSVQA, wsvqa);
REGISTER_MUXDEMUX(WTV, wtv);
@@ -308,6 +317,7 @@ void av_register_all(void)
REGISTER_PROTOCOL(FFRTMPCRYPT, ffrtmpcrypt);
REGISTER_PROTOCOL(FFRTMPHTTP, ffrtmphttp);
REGISTER_PROTOCOL(FILE, file);
+ REGISTER_PROTOCOL(FTP, ftp);
REGISTER_PROTOCOL(GOPHER, gopher);
REGISTER_PROTOCOL(HLS, hls);
REGISTER_PROTOCOL(HTTP, http);
@@ -329,13 +339,17 @@ void av_register_all(void)
REGISTER_PROTOCOL(TCP, tcp);
REGISTER_PROTOCOL(TLS, tls);
REGISTER_PROTOCOL(UDP, udp);
+ REGISTER_PROTOCOL(UNIX, unix);
/* external libraries */
+ REGISTER_DEMUXER (LIBGME, libgme);
REGISTER_DEMUXER (LIBMODPLUG, libmodplug);
REGISTER_MUXDEMUX(LIBNUT, libnut);
+ REGISTER_DEMUXER (LIBQUVI, libquvi);
REGISTER_PROTOCOL(LIBRTMP, librtmp);
REGISTER_PROTOCOL(LIBRTMPE, librtmpe);
REGISTER_PROTOCOL(LIBRTMPS, librtmps);
REGISTER_PROTOCOL(LIBRTMPT, librtmpt);
REGISTER_PROTOCOL(LIBRTMPTE, librtmpte);
+ REGISTER_PROTOCOL(LIBSSH, libssh);
}
diff --git a/ffmpeg/libavformat/amr.c b/ffmpeg/libavformat/amr.c
index 07ab1ba..db9bb4e 100644
--- a/ffmpeg/libavformat/amr.c
+++ b/ffmpeg/libavformat/amr.c
@@ -56,7 +56,6 @@ static int amr_write_header(AVFormatContext *s)
static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
#endif /* CONFIG_AMR_MUXER */
@@ -133,8 +132,6 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
};
size = packed_size[mode];
- } else {
- av_assert0(0);
}
if (!size || av_new_packet(pkt, size))
diff --git a/ffmpeg/libavformat/apc.c b/ffmpeg/libavformat/apc.c
index bb28a62..21bb514 100644
--- a/ffmpeg/libavformat/apc.c
+++ b/ffmpeg/libavformat/apc.c
@@ -23,6 +23,7 @@
#include "libavutil/channel_layout.h"
#include "avformat.h"
+#include "internal.h"
static int apc_probe(AVProbeData *p)
{
@@ -51,14 +52,9 @@ static int apc_read_header(AVFormatContext *s)
avio_rl32(pb); /* number of samples */
st->codec->sample_rate = avio_rl32(pb);
- st->codec->extradata_size = 2 * 4;
- st->codec->extradata = av_malloc(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- 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/ffmpeg/libavformat/ape.c b/ffmpeg/libavformat/ape.c
index 09ed9c5..b677ba9 100644
--- a/ffmpeg/libavformat/ape.c
+++ b/ffmpeg/libavformat/ape.c
@@ -28,7 +28,7 @@
#include "apetag.h"
/* The earliest and latest file formats supported by this library */
-#define APE_MIN_VERSION 3930
+#define APE_MIN_VERSION 3800
#define APE_MAX_VERSION 3990
#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE]
@@ -81,14 +81,19 @@ typedef struct {
/* Seektable */
uint32_t *seektable;
+ uint8_t *bittable;
} APEContext;
static int ape_probe(AVProbeData * p)
{
- if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ')
- return AVPROBE_SCORE_MAX;
+ int version = AV_RL16(p->buf+4);
+ if (AV_RL32(p->buf) != MKTAG('M', 'A', 'C', ' '))
+ return 0;
- return 0;
+ if (version < APE_MIN_VERSION || version > APE_MAX_VERSION)
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx)
@@ -128,9 +133,13 @@ static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx)
} else {
for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) {
if (i < ape_ctx->totalframes - 1) {
- av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)\n",
+ av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)",
i, ape_ctx->seektable[i],
ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]);
+ if (ape_ctx->bittable)
+ av_log(s, AV_LOG_DEBUG, " + %2d bits\n",
+ ape_ctx->bittable[i]);
+ av_log(s, AV_LOG_DEBUG, "\n");
} else {
av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32"\n", i, ape_ctx->seektable[i]);
}
@@ -253,7 +262,7 @@ static int ape_read_header(AVFormatContext * s)
ape->totalframes);
return AVERROR_INVALIDDATA;
}
- if (ape->seektablelength && (ape->seektablelength / sizeof(*ape->seektable)) < ape->totalframes) {
+ 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",
ape->seektablelength / sizeof(*ape->seektable), ape->totalframes);
@@ -263,6 +272,8 @@ static int ape_read_header(AVFormatContext * s)
if(!ape->frames)
return AVERROR(ENOMEM);
ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength;
+ if (ape->fileversion < 3810)
+ ape->firstframe += ape->totalframes;
ape->currentframe = 0;
@@ -271,14 +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); i++)
+ for (i = 0; i < ape->seektablelength / sizeof(uint32_t) && !pb->eof_reached; i++)
ape->seektable[i] = avio_rl32(pb);
- }else{
- av_log(s, AV_LOG_ERROR, "Missing seektable\n");
- return AVERROR_INVALIDDATA;
+ if (ape->fileversion < 3810) {
+ 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;
@@ -309,7 +326,14 @@ static int ape_read_header(AVFormatContext * s)
}
ape->frames[i].size = (ape->frames[i].size + 3) & ~3;
}
-
+ if (ape->fileversion < 3810) {
+ for (i = 0; i < ape->totalframes; i++) {
+ if (i < ape->totalframes - 1 && ape->bittable[i + 1])
+ ape->frames[i].size += 4;
+ ape->frames[i].skip <<= 3;
+ ape->frames[i].skip += ape->bittable[i];
+ }
+ }
ape_dumpinfo(s, ape);
@@ -336,8 +360,8 @@ static int ape_read_header(AVFormatContext * s)
st->duration = total_blocks;
avpriv_set_pts_info(st, 64, 1, ape->samplerate);
- st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE);
- st->codec->extradata_size = APE_EXTRADATA_SIZE;
+ if (ff_alloc_extradata(st->codec, APE_EXTRADATA_SIZE))
+ return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata + 0, ape->fileversion);
AV_WL16(st->codec->extradata + 2, ape->compressiontype);
AV_WL16(st->codec->extradata + 4, ape->formatflags);
@@ -393,6 +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) {
+ av_free_packet(pkt);
+ return ret;
+ }
pkt->pts = ape->frames[ape->currentframe].pts;
pkt->stream_index = 0;
@@ -412,6 +440,7 @@ static int ape_read_close(AVFormatContext * s)
av_freep(&ape->frames);
av_freep(&ape->seektable);
+ av_freep(&ape->bittable);
return 0;
}
diff --git a/ffmpeg/libavformat/apetag.c b/ffmpeg/libavformat/apetag.c
index a445c84..6e59bc7 100644
--- a/ffmpeg/libavformat/apetag.c
+++ b/ffmpeg/libavformat/apetag.c
@@ -23,10 +23,12 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "apetag.h"
#include "internal.h"
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
+#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
@@ -86,14 +88,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 {
- st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ 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);
- return AVERROR(EIO);
- }
- st->codec->extradata_size = size;
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
}
} else {
@@ -114,7 +110,7 @@ static int ape_tag_read_field(AVFormatContext *s)
int64_t ff_ape_parse_tag(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
- int file_size = avio_size(pb);
+ int64_t file_size = avio_size(pb);
uint32_t val, fields, tag_bytes;
uint8_t buf[8];
int64_t tag_start;
@@ -167,3 +163,73 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
return tag_start;
}
+
+static int string_is_ascii(const uint8_t *str)
+{
+ while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
+ return !*str;
+}
+
+int ff_ape_write_tag(AVFormatContext *s)
+{
+ AVDictionaryEntry *e = NULL;
+ int size, ret, count = 0;
+ AVIOContext *dyn_bc = NULL;
+ uint8_t *dyn_buf = NULL;
+
+ if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
+ goto end;
+
+ // flags
+ avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
+ APE_TAG_FLAG_IS_HEADER);
+ ffio_fill(dyn_bc, 0, 8); // reserved
+
+ while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ int val_len;
+
+ if (!string_is_ascii(e->key)) {
+ av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
+ continue;
+ }
+
+ val_len = strlen(e->value);
+ avio_wl32(dyn_bc, val_len); // value length
+ avio_wl32(dyn_bc, 0); // item flags
+ avio_put_str(dyn_bc, e->key); // key
+ avio_write(dyn_bc, e->value, val_len); // value
+ count++;
+ }
+ if (!count)
+ goto end;
+
+ size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ if (size <= 0)
+ goto end;
+ size += 20;
+
+ // header
+ avio_write(s->pb, "APETAGEX", 8); // id
+ avio_wl32(s->pb, APE_TAG_VERSION); // version
+ avio_wl32(s->pb, size);
+ avio_wl32(s->pb, count);
+
+ avio_write(s->pb, dyn_buf, size - 20);
+
+ // footer
+ avio_write(s->pb, "APETAGEX", 8); // id
+ avio_wl32(s->pb, APE_TAG_VERSION); // version
+ avio_wl32(s->pb, size); // size
+ avio_wl32(s->pb, count); // tag count
+
+ // flags
+ avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER);
+ ffio_fill(s->pb, 0, 8); // reserved
+
+end:
+ if (dyn_bc && !dyn_buf)
+ avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ av_freep(&dyn_buf);
+
+ return ret;
+}
diff --git a/ffmpeg/libavformat/apetag.h b/ffmpeg/libavformat/apetag.h
index 0330c89..cf2a5f8 100644
--- a/ffmpeg/libavformat/apetag.h
+++ b/ffmpeg/libavformat/apetag.h
@@ -37,8 +37,8 @@
int64_t ff_ape_parse_tag(AVFormatContext *s);
/**
- * Write an APEv2 tag
+ * Write an APE tag into a file.
*/
-void ff_ape_write(AVFormatContext *s);
+int ff_ape_write_tag(AVFormatContext *s);
#endif /* AVFORMAT_APETAG_H */
diff --git a/ffmpeg/libavformat/apetagenc.c b/ffmpeg/libavformat/apetagenc.c
deleted file mode 100644
index 42f5836..0000000
--- a/ffmpeg/libavformat/apetagenc.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * APE tag writer
- * Copyright (c) 2012 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/dict.h"
-#include "avio_internal.h"
-#include "avformat.h"
-#include "apetag.h"
-
-static int string_is_ascii(const uint8_t *str)
-{
- while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
- return !*str;
-}
-
-void ff_ape_write(AVFormatContext *s)
-{
- int64_t tag_bytes;
- AVDictionaryEntry *t = NULL;
- AVIOContext *pb = s->pb;
- int tags = 0, vlen;
-
- tag_bytes = avio_tell(s->pb);
- while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
- if (!string_is_ascii(t->key)) {
- av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
- continue;
- }
-
- vlen = strlen(t->value);
- avio_wl32(pb, vlen + 1);
- avio_wl32(pb, 0); // flags
- avio_put_str(pb, t->key);
- avio_put_str(pb, t->value);
- tags++;
- }
- tag_bytes = avio_tell(s->pb) - tag_bytes;
-
- if (!tags)
- return;
-
- avio_write(pb, APE_TAG_PREAMBLE, 8);
- avio_wl32(pb, APE_TAG_VERSION);
- avio_wl32(pb, tag_bytes + APE_TAG_FOOTER_BYTES);
- avio_wl32(pb, tags); // item count
- avio_wl32(pb, 0); // global flags
- ffio_fill(pb, 0, 8); // reserved
-}
diff --git a/ffmpeg/libavformat/aqtitledec.c b/ffmpeg/libavformat/aqtitledec.c
index 325946c..810f95b 100644
--- a/ffmpeg/libavformat/aqtitledec.c
+++ b/ffmpeg/libavformat/aqtitledec.c
@@ -43,7 +43,7 @@ static int aqt_probe(AVProbeData *p)
const char *ptr = p->buf;
if (sscanf(ptr, "-->> %d", &frame) == 1)
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
return 0;
}
@@ -70,7 +70,7 @@ static int aqt_read_header(AVFormatContext *s)
line[strcspn(line, "\r\n")] = 0;
- if (sscanf(line, "-->> %"PRId64, &frame) == 1) {
+ if (sscanf(line, "-->> %"SCNd64, &frame) == 1) {
new_event = 1;
pos = avio_tell(s->pb);
if (sub) {
diff --git a/ffmpeg/libavformat/asf.c b/ffmpeg/libavformat/asf.c
index dd64a3f..80d24db 100644
--- a/ffmpeg/libavformat/asf.c
+++ b/ffmpeg/libavformat/asf.c
@@ -117,6 +117,10 @@ const ff_asf_guid ff_asf_marker_header = {
0x01, 0xCD, 0x87, 0xF4, 0x51, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65
};
+const ff_asf_guid ff_asf_reserved_4 = {
+ 0x20, 0xdb, 0xfe, 0x4c, 0xf6, 0x75, 0xCF, 0x11, 0x9c, 0x0f, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
+};
+
/* I am not a number !!! This GUID is the one found on the PC used to
* generate the stream */
const ff_asf_guid ff_asf_my_guid = {
diff --git a/ffmpeg/libavformat/asf.h b/ffmpeg/libavformat/asf.h
index 5ffc746..acad64d 100644
--- a/ffmpeg/libavformat/asf.h
+++ b/ffmpeg/libavformat/asf.h
@@ -39,8 +39,11 @@ typedef struct ASFStream {
/* use for reading */
AVPacket pkt;
int frag_offset;
+ int packet_obj_size;
int timestamp;
int64_t duration;
+ int skip_to_key;
+ int pkt_clean;
int ds_span; /* descrambling */
int ds_packet_size;
@@ -86,6 +89,8 @@ typedef struct ASFMainHeader {
typedef struct ASFIndex {
uint32_t packet_number;
uint16_t packet_count;
+ uint64_t send_time;
+ uint64_t offset;
} ASFIndex;
extern const ff_asf_guid ff_asf_header;
@@ -112,6 +117,7 @@ extern const ff_asf_guid ff_asf_ext_stream_audio_stream;
extern const ff_asf_guid ff_asf_metadata_header;
extern const ff_asf_guid ff_asf_metadata_library_header;
extern const ff_asf_guid ff_asf_marker_header;
+extern const ff_asf_guid ff_asf_reserved_4;
extern const ff_asf_guid ff_asf_my_guid;
extern const ff_asf_guid ff_asf_language_guid;
extern const ff_asf_guid ff_asf_content_encryption;
diff --git a/ffmpeg/libavformat/asfdec.c b/ffmpeg/libavformat/asfdec.c
index 1d7f26c..1f8b25c 100644
--- a/ffmpeg/libavformat/asfdec.c
+++ b/ffmpeg/libavformat/asfdec.c
@@ -19,14 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-//#define DEBUG
-
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bswap.h"
#include "libavutil/common.h"
#include "libavutil/dict.h"
+#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "avformat.h"
@@ -69,7 +68,6 @@ typedef struct {
unsigned int packet_frag_size;
int64_t packet_frag_timestamp;
int packet_multi_size;
- int packet_obj_size;
int packet_time_delta;
int packet_time_start;
int64_t packet_pos;
@@ -368,14 +366,8 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
- asf_st = av_mallocz(sizeof(ASFStream));
- if (!asf_st)
- return AVERROR(ENOMEM);
- st->priv_data = asf_st;
start_time = asf->hdr.preroll;
- asf_st->stream_language_index = 128; // invalid stream index means no language info
-
if (!(asf->hdr.flags & 0x01)) { // if we aren't streaming...
int64_t fsize = avio_size(pb);
if (fsize <= 0 || (int64_t)asf->hdr.file_size <= 0 || FFABS(fsize - (int64_t)asf->hdr.file_size) < 10000)
@@ -407,6 +399,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
st->id = avio_rl16(pb) & 0x7f; /* stream id */
// mapping of asf ID to AV stream ID;
asf->asfid2avid[st->id] = s->nb_streams - 1;
+ asf_st = &asf->streams[st->id];
avio_rl32(pb);
@@ -472,6 +465,8 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
st->codec->extradata_size = ffio_limit(pb, sizeX - 40);
st->codec->extradata = av_mallocz(st->codec->extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, st->codec->extradata_size);
}
@@ -684,6 +679,7 @@ static int asf_read_metadata(AVFormatContext *s, int64_t size)
static int asf_read_marker(AVFormatContext *s, int64_t size)
{
AVIOContext *pb = s->pb;
+ ASFContext *asf = s->priv_data;
int i, count, name_len, ret;
char name[1024];
@@ -701,6 +697,7 @@ static int asf_read_marker(AVFormatContext *s, int64_t size)
avio_rl64(pb); // offset, 8 bytes
pres_time = avio_rl64(pb); // presentation time
+ pres_time -= asf->hdr.preroll * 10000;
avio_rl16(pb); // entry length
avio_rl32(pb); // send time
avio_rl32(pb); // flags
@@ -731,6 +728,10 @@ static int asf_read_header(AVFormatContext *s)
avio_r8(pb);
avio_r8(pb);
memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
+
+ for (i = 0; i<128; i++)
+ asf->streams[i].stream_language_index = 128; // invalid stream index means no language info
+
for (;;) {
uint64_t gpos = avio_tell(pb);
ff_get_guid(pb, &g);
@@ -753,7 +754,9 @@ static int asf_read_header(AVFormatContext *s)
if (ret < 0)
return ret;
} else if (!ff_guidcmp(&g, &ff_asf_stream_header)) {
- asf_read_stream_properties(s, gsize);
+ int ret = asf_read_stream_properties(s, gsize);
+ if (ret < 0)
+ return ret;
} else if (!ff_guidcmp(&g, &ff_asf_comment_header)) {
asf_read_content_desc(s, gsize);
} else if (!ff_guidcmp(&g, &ff_asf_language_guid)) {
@@ -883,7 +886,7 @@ static int asf_read_header(AVFormatContext *s)
* @param pb context to read data from
* @return 0 on success, <0 on error
*/
-static int ff_asf_get_packet(AVFormatContext *s, AVIOContext *pb)
+static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
{
ASFContext *asf = s->priv_data;
uint32_t packet_length, padsize;
@@ -1009,10 +1012,10 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
if (asf->packet_replic_size >= 8) {
int64_t end = avio_tell(pb) + asf->packet_replic_size;
AVRational aspect;
- asf->packet_obj_size = avio_rl32(pb);
- if (asf->packet_obj_size >= (1 << 24) || asf->packet_obj_size <= 0) {
+ asfst->packet_obj_size = avio_rl32(pb);
+ if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size <= 0) {
av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n");
- asf->packet_obj_size = 0;
+ asfst->packet_obj_size = 0;
return AVERROR_INVALIDDATA;
}
asf->packet_frag_timestamp = avio_rl32(pb); // timestamp
@@ -1110,7 +1113,7 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
* @return 0 if data was stored in pkt, <0 on error or 1 if more ASF
* packets need to be loaded (through asf_get_packet())
*/
-static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
+static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
ASFStream *asf_st = 0;
@@ -1119,8 +1122,7 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
if (url_feof(pb))
return AVERROR_EOF;
- if (asf->packet_size_left < FRAME_HEADER_SIZE ||
- asf->packet_segments < 1) {
+ if (asf->packet_size_left < FRAME_HEADER_SIZE) {
int ret = asf->packet_size_left + asf->packet_padsize;
assert(ret >= 0);
@@ -1135,13 +1137,13 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
}
if (asf->packet_time_start == 0) {
if (asf_read_frame_header(s, pb) < 0) {
- asf->packet_segments = 0;
+ asf->packet_time_start = asf->packet_segments = 0;
continue;
}
if (asf->stream_index < 0 ||
s->streams[asf->stream_index]->discard >= AVDISCARD_ALL ||
(!asf->packet_key_frame &&
- s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY)) {
+ (s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY || asf->streams[s->streams[asf->stream_index]->id].skip_to_key))) {
asf->packet_time_start = 0;
/* unhandled packet (should not happen) */
avio_skip(pb, asf->packet_frag_size);
@@ -1151,7 +1153,8 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
asf->packet_frag_size);
continue;
}
- asf->asf_st = s->streams[asf->stream_index]->priv_data;
+ asf->asf_st = &asf->streams[s->streams[asf->stream_index]->id];
+ asf->asf_st->skip_to_key = 0;
}
asf_st = asf->asf_st;
av_assert0(asf_st);
@@ -1160,41 +1163,35 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
// frag_offset is here used as the beginning timestamp
asf->packet_frag_timestamp = asf->packet_time_start;
asf->packet_time_start += asf->packet_time_delta;
- asf->packet_obj_size = asf->packet_frag_size = avio_r8(pb);
+ asf_st->packet_obj_size = asf->packet_frag_size = avio_r8(pb);
asf->packet_size_left--;
asf->packet_multi_size--;
- if (asf->packet_multi_size < asf->packet_obj_size) {
+ if (asf->packet_multi_size < asf_st->packet_obj_size) {
asf->packet_time_start = 0;
avio_skip(pb, asf->packet_multi_size);
asf->packet_size_left -= asf->packet_multi_size;
continue;
}
- asf->packet_multi_size -= asf->packet_obj_size;
- }
- if (asf_st->frag_offset + asf->packet_frag_size <= asf_st->pkt.size &&
- asf_st->frag_offset + asf->packet_frag_size > asf->packet_obj_size) {
- av_log(s, AV_LOG_INFO, "ignoring invalid packet_obj_size (%d %d %d %d)\n",
- asf_st->frag_offset, asf->packet_frag_size,
- asf->packet_obj_size, asf_st->pkt.size);
- asf->packet_obj_size = asf_st->pkt.size;
+ asf->packet_multi_size -= asf_st->packet_obj_size;
}
- if (asf_st->pkt.size != asf->packet_obj_size ||
+ if (asf_st->pkt.size != asf_st->packet_obj_size ||
// FIXME is this condition sufficient?
asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) {
if (asf_st->pkt.data) {
av_log(s, AV_LOG_INFO,
"freeing incomplete packet size %d, new %d\n",
- asf_st->pkt.size, asf->packet_obj_size);
+ asf_st->pkt.size, asf_st->packet_obj_size);
asf_st->frag_offset = 0;
av_free_packet(&asf_st->pkt);
}
/* new packet */
- av_new_packet(&asf_st->pkt, asf->packet_obj_size);
+ av_new_packet(&asf_st->pkt, asf_st->packet_obj_size);
asf_st->seq = asf->packet_seq;
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;
@@ -1211,7 +1208,7 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
asf->stream_index, asf->packet_key_frame,
asf_st->pkt.flags & AV_PKT_FLAG_KEY,
s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO,
- asf->packet_obj_size);
+ asf_st->packet_obj_size);
if (s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
asf->packet_key_frame = 1;
if (asf->packet_key_frame)
@@ -1235,6 +1232,11 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
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) {
@@ -1310,7 +1312,9 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
asf_st->frag_offset = 0;
*pkt = asf_st->pkt;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
asf_st->pkt.destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
asf_st->pkt.buf = 0;
asf_st->pkt.size = 0;
@@ -1331,9 +1335,9 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
int ret;
/* parse cached packets, if any */
- if ((ret = ff_asf_parse_packet(s, s->pb, pkt)) <= 0)
+ if ((ret = asf_parse_packet(s, s->pb, pkt)) <= 0)
return ret;
- if ((ret = ff_asf_get_packet(s, s->pb)) < 0)
+ if ((ret = asf_get_packet(s, s->pb)) < 0)
assert(asf->packet_size_left < FRAME_HEADER_SIZE ||
asf->packet_segments < 1);
asf->packet_time_start = 0;
@@ -1350,7 +1354,6 @@ static void asf_reset_header(AVFormatContext *s)
int i;
asf->packet_size_left = 0;
- asf->packet_segments = 0;
asf->packet_flags = 0;
asf->packet_property = 0;
asf->packet_timestamp = 0;
@@ -1364,21 +1367,34 @@ static void asf_reset_header(AVFormatContext *s)
asf->packet_frag_size = 0;
asf->packet_frag_timestamp = 0;
asf->packet_multi_size = 0;
- asf->packet_obj_size = 0;
asf->packet_time_delta = 0;
asf->packet_time_start = 0;
- for (i = 0; i < s->nb_streams; i++) {
- asf_st = s->streams[i]->priv_data;
- if (!asf_st)
- continue;
+ for (i = 0; i < 128; i++) {
+ asf_st = &asf->streams[i];
av_free_packet(&asf_st->pkt);
+ asf_st->packet_obj_size = 0;
asf_st->frag_offset = 0;
asf_st->seq = 0;
}
asf->asf_st = NULL;
}
+static void skip_to_key(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ int j = asf->asfid2avid[i];
+ ASFStream *asf_st = &asf->streams[i];
+ if (j < 0 || s->streams[j]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+
+ asf_st->skip_to_key = 1;
+ }
+}
+
static int asf_read_close(AVFormatContext *s)
{
asf_reset_header(s);
@@ -1389,6 +1405,7 @@ static int asf_read_close(AVFormatContext *s)
static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
int64_t *ppos, int64_t pos_limit)
{
+ ASFContext *asf = s->priv_data;
AVPacket pkt1, *pkt = &pkt1;
ASFStream *asf_st;
int64_t pts;
@@ -1407,6 +1424,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
+ ff_read_frame_flush(s);
asf_reset_header(s);
for (;;) {
if (av_read_frame(s, pkt) < 0) {
@@ -1420,8 +1438,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
if (pkt->flags & AV_PKT_FLAG_KEY) {
i = pkt->stream_index;
- asf_st = s->streams[i]->priv_data;
- av_assert0(asf_st);
+ asf_st = &asf->streams[s->streams[i]->id];
// assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0);
pos = asf_st->packet_pos;
@@ -1528,6 +1545,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
if(avio_seek(s->pb, pos, SEEK_SET) < 0)
return -1;
asf_reset_header(s);
+ skip_to_key(s);
return 0;
}
}
@@ -1535,6 +1553,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0)
return -1;
asf_reset_header(s);
+ skip_to_key(s);
return 0;
}
diff --git a/ffmpeg/libavformat/asfenc.c b/ffmpeg/libavformat/asfenc.c
index f3aec9c..8e343b3 100644
--- a/ffmpeg/libavformat/asfenc.c
+++ b/ffmpeg/libavformat/asfenc.c
@@ -19,7 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avassert.h"
#include "libavutil/dict.h"
+#include "libavutil/mathematics.h"
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
@@ -182,6 +184,8 @@
1 - /* Payload Flags */ \
2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS)
+#define DATA_HEADER_SIZE 50
+
typedef struct {
uint32_t seqno;
int is_streamed;
@@ -205,6 +209,7 @@ typedef struct {
uint16_t maximum_packet;
uint32_t next_packet_number;
uint16_t next_packet_count;
+ uint64_t next_packet_offset;
int next_start_sec;
int end_sec;
} ASFContext;
@@ -220,7 +225,7 @@ static const AVCodecTag codec_asf_bmp_tags[] = {
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
{
- assert(sizeof(*g) == 16);
+ av_assert0(sizeof(*g) == 16);
avio_write(s, *g, sizeof(*g));
}
@@ -287,6 +292,64 @@ static int64_t unix_to_file_time(int ti)
return t;
}
+static int32_t get_send_time(ASFContext *asf, int64_t pres_time, uint64_t *offset)
+{
+ int i;
+ int32_t send_time = 0;
+ *offset = asf->data_offset + DATA_HEADER_SIZE;
+ for (i = 0; i < asf->next_start_sec; i++) {
+ if (pres_time <= asf->index_ptr[i].send_time)
+ break;
+ send_time = asf->index_ptr[i].send_time;
+ *offset = asf->index_ptr[i].offset;
+ }
+
+ return send_time / 10000;
+}
+
+static int asf_write_markers(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i;
+ AVRational scale = {1, 10000000};
+ int64_t hpos = put_header(pb, &ff_asf_marker_header);
+
+ ff_put_guid(pb, &ff_asf_reserved_4);// ASF spec mandates this reserved value
+ avio_wl32(pb, s->nb_chapters); // markers count
+ avio_wl16(pb, 0); // ASF spec mandates 0 for this
+ avio_wl16(pb, 0); // name length 0, no name given
+
+ for (i = 0; i < s->nb_chapters; i++) {
+ AVChapter *c = s->chapters[i];
+ AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
+ int64_t pres_time = av_rescale_q(c->start, c->time_base, scale);
+ uint64_t offset;
+ int32_t send_time = get_send_time(asf, pres_time, &offset);
+ int len = 0;
+ uint8_t *buf;
+ AVIOContext *dyn_buf;
+ if (t) {
+ if (avio_open_dyn_buf(&dyn_buf) < 0)
+ return AVERROR(ENOMEM);
+ avio_put_str16le(dyn_buf, t->value);
+ len = avio_close_dyn_buf(dyn_buf, &buf);
+ }
+ avio_wl64(pb, offset); // offset of the packet with send_time
+ avio_wl64(pb, pres_time + PREROLL_TIME * 10000); // presentation time
+ avio_wl16(pb, 12 + len); // entry length
+ avio_wl32(pb, send_time); // send time
+ avio_wl32(pb, 0); // flags, should be 0
+ avio_wl32(pb, len / 2); // marker desc length in WCHARS!
+ if (t) {
+ avio_write(pb, buf, len); // marker desc
+ av_freep(&buf);
+ }
+ }
+ end_header(pb, hpos);
+ return 0;
+}
+
/* write the header (used two times if non streamed) */
static int asf_write_header1(AVFormatContext *s, int64_t file_size,
int64_t data_chunk_size)
@@ -388,7 +451,12 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
}
end_header(pb, hpos);
}
-
+ /* chapters using ASF markers */
+ if (!asf->is_streamed && s->nb_chapters) {
+ int ret;
+ if (ret = asf_write_markers(s))
+ return ret;
+ }
/* stream headers */
for (n = 0; n < s->nb_streams; n++) {
int64_t es_pos;
@@ -457,7 +525,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);
}
@@ -519,14 +587,14 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
cur_pos = avio_tell(pb);
header_size = cur_pos - header_offset;
if (asf->is_streamed) {
- header_size += 8 + 30 + 50;
+ header_size += 8 + 30 + DATA_HEADER_SIZE;
avio_seek(pb, header_offset - 10 - 30, SEEK_SET);
avio_wl16(pb, header_size);
avio_seek(pb, header_offset - 2 - 30, SEEK_SET);
avio_wl16(pb, header_size);
- header_size -= 8 + 30 + 50;
+ header_size -= 8 + 30 + DATA_HEADER_SIZE;
}
header_size += 24 + 6;
avio_seek(pb, header_offset - 14, SEEK_SET);
@@ -555,10 +623,10 @@ static int asf_write_header(AVFormatContext *s)
asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
asf->maximum_packet = 0;
- /* the data-chunk-size has to be 50, which is data_size - asf->data_offset
- * at the moment this function is done. It is needed to use asf as
- * streamable format. */
- if (asf_write_header1(s, 0, 50) < 0) {
+ /* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is
+ * data_size - asf->data_offset at the moment this function is done.
+ * It is needed to use asf as a streamable format. */
+ if (asf_write_header1(s, 0, DATA_HEADER_SIZE) < 0) {
//av_free(asf);
return -1;
}
@@ -600,7 +668,7 @@ static int put_payload_parsing_info(AVFormatContext *s,
padsize -= PACKET_HEADER_MIN_SIZE;
if (asf->multi_payloads_present)
padsize--;
- assert(padsize >= 0);
+ av_assert0(padsize >= 0);
avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS);
for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++)
@@ -639,7 +707,7 @@ static void flush_packet(AVFormatContext *s)
ASFContext *asf = s->priv_data;
int packet_hdr_size, packet_filled_size;
- assert(asf->packet_timestamp_end >= asf->packet_timestamp_start);
+ av_assert0(asf->packet_timestamp_end >= asf->packet_timestamp_start);
if (asf->is_streamed)
put_chunk(s, 0x4424, s->packet_size, 0);
@@ -651,7 +719,7 @@ static void flush_packet(AVFormatContext *s)
asf->packet_size_left);
packet_filled_size = PACKET_SIZE - asf->packet_size_left;
- assert(packet_hdr_size <= asf->packet_size_left);
+ av_assert0(packet_hdr_size <= asf->packet_size_left);
memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size);
@@ -759,8 +827,9 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
stream->seq++;
}
-static void update_index(AVFormatContext *s, int start_sec,
- uint32_t packet_number, uint16_t packet_count)
+static int update_index(AVFormatContext *s, int start_sec,
+ uint32_t packet_number, uint16_t packet_count,
+ uint64_t packet_offset)
{
ASFContext *asf = s->priv_data;
@@ -770,32 +839,48 @@ static void update_index(AVFormatContext *s, int start_sec,
if (!asf->next_start_sec) {
asf->next_packet_number = packet_number;
asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
}
if (start_sec > asf->nb_index_memory_alloc) {
+ int err;
asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
- asf->index_ptr = av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
+ if ((err = av_reallocp_array(&asf->index_ptr,
+ asf->nb_index_memory_alloc,
+ sizeof(*asf->index_ptr))) < 0) {
+ asf->nb_index_memory_alloc = 0;
+ return err;
+ }
}
for (i = asf->next_start_sec; i < start_sec; i++) {
asf->index_ptr[i].packet_number = asf->next_packet_number;
asf->index_ptr[i].packet_count = asf->next_packet_count;
+ asf->index_ptr[i].send_time = asf->next_start_sec * INT64_C(10000000);
+ asf->index_ptr[i].offset = asf->next_packet_offset;
+
}
}
asf->maximum_packet = FFMAX(asf->maximum_packet, packet_count);
asf->next_packet_number = packet_number;
asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
asf->next_start_sec = start_sec;
+
+ return 0;
}
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
ASFStream *stream;
AVCodecContext *codec;
uint32_t packet_number;
int64_t pts;
int start_sec;
int flags = pkt->flags;
+ int ret;
+ uint64_t offset = avio_tell(pb);
codec = s->streams[pkt->stream_index]->codec;
stream = &asf->streams[pkt->stream_index];
@@ -804,7 +889,7 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
flags &= ~AV_PKT_FLAG_KEY;
pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
- assert(pts != AV_NOPTS_VALUE);
+ av_assert0(pts != AV_NOPTS_VALUE);
pts *= 10000;
asf->duration = FFMAX(asf->duration, pts + pkt->duration * 10000);
@@ -818,7 +903,9 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
/* check index */
if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
uint16_t packet_count = asf->nb_packets - packet_number;
- update_index(s, start_sec, packet_number, packet_count);
+ ret = update_index(s, start_sec, packet_number, packet_count, offset);
+ if (ret < 0)
+ return ret;
}
asf->end_sec = start_sec;
@@ -849,6 +936,7 @@ static int asf_write_trailer(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
int64_t file_size, data_size;
+ int ret;
/* flush the current packet */
if (asf->pb.buf_ptr > asf->pb.buffer)
@@ -857,7 +945,8 @@ static int asf_write_trailer(AVFormatContext *s)
/* write index */
data_size = avio_tell(s->pb);
if (!asf->is_streamed && asf->next_start_sec) {
- update_index(s, asf->end_sec + 1, 0, 0);
+ if ((ret = update_index(s, asf->end_sec + 1, 0, 0, 0)) < 0)
+ return ret;
asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec);
}
avio_flush(s->pb);
@@ -871,7 +960,7 @@ static int asf_write_trailer(AVFormatContext *s)
asf_write_header1(s, file_size, data_size - asf->data_offset);
}
- av_free(asf->index_ptr);
+ av_freep(&asf->index_ptr);
return 0;
}
diff --git a/ffmpeg/libavformat/assdec.c b/ffmpeg/libavformat/assdec.c
index 35fcb51..c9bd63b 100644
--- a/ffmpeg/libavformat/assdec.c
+++ b/ffmpeg/libavformat/assdec.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "avformat.h"
#include "internal.h"
#include "subtitles.h"
diff --git a/ffmpeg/libavformat/assenc.c b/ffmpeg/libavformat/assenc.c
index bda507d..9fb9f23 100644
--- a/ffmpeg/libavformat/assenc.c
+++ b/ffmpeg/libavformat/assenc.c
@@ -20,9 +20,11 @@
*/
#include "avformat.h"
+#include "internal.h"
typedef struct ASSContext{
unsigned int extra_index;
+ int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like)
}ASSContext;
static int write_header(AVFormatContext *s)
@@ -31,10 +33,13 @@ static int write_header(AVFormatContext *s)
AVCodecContext *avctx= s->streams[0]->codec;
uint8_t *last= NULL;
- if(s->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_SSA){
+ if (s->nb_streams != 1 || (avctx->codec_id != AV_CODEC_ID_SSA &&
+ avctx->codec_id != AV_CODEC_ID_ASS)) {
av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n");
return -1;
}
+ ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS;
+ avpriv_set_pts_info(s->streams[0], 64, 1, 100);
while(ass->extra_index < avctx->extradata_size){
uint8_t *p = avctx->extradata + ass->extra_index;
@@ -57,9 +62,31 @@ static int write_header(AVFormatContext *s)
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
- avio_write(s->pb, pkt->data, pkt->size);
+ ASSContext *ass = s->priv_data;
- avio_flush(s->pb);
+ if (ass->write_ts) {
+ long int layer;
+ char *p;
+ int64_t start = pkt->pts;
+ int64_t end = start + pkt->duration;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ p = pkt->data + strcspn(pkt->data, ",") + 1; // skip ReadOrder
+ layer = strtol(p, &p, 10);
+ if (*p == ',')
+ p++;
+ hh1 = (int)(start / 360000); mm1 = (int)(start / 6000) % 60;
+ hh2 = (int)(end / 360000); mm2 = (int)(end / 6000) % 60;
+ ss1 = (int)(start / 100) % 60; ms1 = (int)(start % 100);
+ ss2 = (int)(end / 100) % 60; ms2 = (int)(end % 100);
+ if (hh1 > 9) hh1 = 9, mm1 = 59, ss1 = 59, ms1 = 99;
+ if (hh2 > 9) hh2 = 9, mm2 = 59, ss2 = 59, ms2 = 99;
+ avio_printf(s->pb, "Dialogue: %ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
+ layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p);
+ } else {
+ avio_write(s->pb, pkt->data, pkt->size);
+ }
return 0;
}
diff --git a/ffmpeg/libavformat/astdec.c b/ffmpeg/libavformat/astdec.c
index 8862744..3fa26dc 100644
--- a/ffmpeg/libavformat/astdec.c
+++ b/ffmpeg/libavformat/astdec.c
@@ -27,12 +27,15 @@
static int ast_probe(AVProbeData *p)
{
- if (AV_RL32(p->buf) == MKTAG('S','T','R','M') &&
- AV_RB16(p->buf + 10) &&
- AV_RB16(p->buf + 12) &&
- AV_RB32(p->buf + 16))
- return AVPROBE_SCORE_MAX / 3 * 2;
- return 0;
+ if (AV_RL32(p->buf) != MKTAG('S','T','R','M'))
+ return 0;
+
+ if (!AV_RB16(p->buf + 10) ||
+ !AV_RB16(p->buf + 12) || AV_RB16(p->buf + 12) > 256 ||
+ !AV_RB32(p->buf + 16) || AV_RB32(p->buf + 16) > 8*48000)
+ return AVPROBE_SCORE_MAX / 8;
+
+ return AVPROBE_SCORE_MAX / 3 * 2;
}
static int ast_read_header(AVFormatContext *s)
diff --git a/ffmpeg/libavformat/au.c b/ffmpeg/libavformat/au.c
index a29e802..edf0f32 100644
--- a/ffmpeg/libavformat/au.c
+++ b/ffmpeg/libavformat/au.c
@@ -2,6 +2,8 @@
* AU muxer and demuxer
* Copyright (c) 2001 Fabrice Bellard
*
+ * first version by Francois Revol <revol@free.fr>
+ *
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
@@ -20,8 +22,6 @@
*/
/*
- * First version by Francois Revol revol@free.fr
- *
* Reference documents:
* http://www.opengroup.org/public/pubs/external/auformat.html
* http://www.goice.co.jp/member/mo/formats/au.html
@@ -31,6 +31,7 @@
#include "internal.h"
#include "avio_internal.h"
#include "pcm.h"
+#include "libavutil/avassert.h"
/* if we don't know the size in advance */
#define AU_UNKNOWN_SIZE ((uint32_t)(~0))
@@ -45,8 +46,12 @@ static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_S32BE, 5 },
{ AV_CODEC_ID_PCM_F32BE, 6 },
{ AV_CODEC_ID_PCM_F64BE, 7 },
+ { AV_CODEC_ID_ADPCM_G726LE, 23 },
{ AV_CODEC_ID_ADPCM_G722,24 },
+ { AV_CODEC_ID_ADPCM_G726LE, 25 },
+ { AV_CODEC_ID_ADPCM_G726LE, 26 },
{ AV_CODEC_ID_PCM_ALAW, 27 },
+ { AV_CODEC_ID_ADPCM_G726LE, MKBETAG('7','2','6','2') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -101,7 +106,15 @@ static int au_read_header(AVFormatContext *s)
}
bps = av_get_bits_per_sample(codec);
- if (!bps) {
+ if (codec == AV_CODEC_ID_ADPCM_G726LE) {
+ if (id == MKBETAG('7','2','6','2')) {
+ bps = 2;
+ } else {
+ const uint8_t bpcss[] = {4, 0, 3, 5};
+ av_assert0(id >= 23 && id < 23 + 4);
+ bps = bpcss[id - 23];
+ }
+ } else if (!bps) {
avpriv_request_sample(s, "Unknown bits per sample");
return AVERROR_PATCHWELCOME;
}
@@ -124,6 +137,7 @@ static int au_read_header(AVFormatContext *s)
st->codec->codec_id = codec;
st->codec->channels = channels;
st->codec->sample_rate = rate;
+ st->codec->bits_per_coded_sample = bps;
st->codec->bit_rate = channels * rate * bps;
st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1);
if (data_size != AU_UNKNOWN_SIZE)
diff --git a/ffmpeg/libavformat/audiointerleave.c b/ffmpeg/libavformat/audiointerleave.c
index 35dd8d5..2aa95f3 100644
--- a/ffmpeg/libavformat/audiointerleave.c
+++ b/ffmpeg/libavformat/audiointerleave.c
@@ -74,8 +74,8 @@ int ff_audio_interleave_init(AVFormatContext *s,
return 0;
}
-static int ff_interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt,
- int stream_index, int flush)
+static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt,
+ int stream_index, int flush)
{
AVStream *st = s->streams[stream_index];
AudioInterleaveContext *aic = st->priv_data;
@@ -134,7 +134,7 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
AVPacket new_pkt;
int ret;
- while ((ret = ff_interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) {
+ while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) {
ret = ff_interleave_add_packet(s, &new_pkt, compare_ts);
if (ret < 0)
return ret;
diff --git a/ffmpeg/libavformat/avformat.h b/ffmpeg/libavformat/avformat.h
index 4b8731c..52eef0d 100644
--- a/ffmpeg/libavformat/avformat.h
+++ b/ffmpeg/libavformat/avformat.h
@@ -337,8 +337,10 @@ typedef struct AVProbeData {
int buf_size; /**< Size of buf except extra allocated bytes */
} AVProbeData;
-#define AVPROBE_SCORE_MAX 100 ///< maximum score, half of that is used for file-extension-based detection
#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4)
+#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension
+#define AVPROBE_SCORE_MAX 100 ///< maximum score
+
#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer
/// Demuxer will use avio_open, no opened file should be provided by the caller.
@@ -354,8 +356,8 @@ typedef struct AVProbeData {
#define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */
#define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */
#define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */
-#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fallback to binary search via read_timestamp */
-#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fallback to generic search */
+#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */
+#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */
#define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */
#define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */
#if LIBAVFORMAT_VERSION_MAJOR <= 54
@@ -366,6 +368,14 @@ typedef struct AVProbeData {
/**< Format does not require strictly
increasing timestamps, but they must
still be monotonic */
+#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative
+ timestamps. If not set the timestamp
+ will be shifted in av_write_frame and
+ av_interleaved_write_frame so they
+ start from 0.
+ The user or muxer can override this through
+ AVFormatContext.avoid_negative_ts
+ */
#define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */
@@ -626,6 +636,13 @@ typedef struct AVIndexEntry {
#define AV_DISPOSITION_ATTACHED_PIC 0x0400
/**
+ * To specify text track kind (different from subtitles default).
+ */
+#define AV_DISPOSITION_CAPTIONS 0x10000
+#define AV_DISPOSITION_DESCRIPTIONS 0x20000
+#define AV_DISPOSITION_METADATA 0x40000
+
+/**
* Options for behavior on timestamp wrap detection.
*/
#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap
@@ -723,19 +740,6 @@ typedef struct AVStream {
*/
AVPacket attached_pic;
- /**
- * Real base framerate of the stream.
- * This is the lowest framerate with which all timestamps can be
- * represented accurately (it is the least common multiple of all
- * framerates in the stream). Note, this value is just a guess!
- * For example, if the time base is 1/90000 and all frames have either
- * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
- *
- * Code outside avformat should access this field using:
- * av_stream_get/set_r_frame_rate(stream)
- */
- AVRational r_frame_rate;
-
/*****************************************************************
* 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
@@ -752,6 +756,7 @@ 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;
@@ -771,6 +776,11 @@ typedef struct AVStream {
int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
+#if FF_API_REFERENCE_DTS
+ /* a hack to keep ABI compatibility for ffmpeg and other applications, which accesses parser even
+ * though it should not */
+ int64_t do_not_use;
+#endif
// Timestamp generation support:
/**
* Timestamp corresponding to the last dts sync point.
@@ -779,7 +789,6 @@ typedef struct AVStream {
* a DTS is received from the underlying container. Otherwise set to
* AV_NOPTS_VALUE by default.
*/
- int64_t reference_dts;
int64_t first_dts;
int64_t cur_dts;
int64_t last_IP_pts;
@@ -796,16 +805,6 @@ typedef struct AVStream {
*/
int codec_info_nb_frames;
- /**
- * Stream Identifier
- * This is the MPEG-TS stream identifier +1
- * 0 means unknown
- */
- int stream_identifier;
-
- int64_t interleaver_chunk_size;
- int64_t interleaver_chunk_duration;
-
/* av_read_frame() support */
enum AVStreamParseType need_parsing;
struct AVCodecParserContext *parser;
@@ -824,6 +823,29 @@ typedef struct AVStream {
unsigned int index_entries_allocated_size;
/**
+ * Real base framerate of the stream.
+ * This is the lowest framerate with which all timestamps can be
+ * represented accurately (it is the least common multiple of all
+ * framerates in the stream). Note, this value is just a guess!
+ * For example, if the time base is 1/90000 and all frames have either
+ * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
+ *
+ * Code outside avformat should access this field using:
+ * av_stream_get/set_r_frame_rate(stream)
+ */
+ AVRational r_frame_rate;
+
+ /**
+ * Stream Identifier
+ * This is the MPEG-TS stream identifier +1
+ * 0 means unknown
+ */
+ int stream_identifier;
+
+ int64_t interleaver_chunk_size;
+ int64_t interleaver_chunk_duration;
+
+ /**
* stream probing state
* -1 -> probing finished
* 0 -> no probing requested
@@ -1026,6 +1048,7 @@ typedef struct AVFormatContext {
#define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible
#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.
#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)
@@ -1084,6 +1107,17 @@ typedef struct AVFormatContext {
*/
unsigned int max_picture_buffer;
+ /**
+ * Number of chapters in AVChapter array.
+ * When muxing, chapters are normally written in the file header,
+ * so nb_chapters should normally be initialized before write_header
+ * is called. Some muxers (e.g. mov and mkv) can also write chapters
+ * 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
+ */
unsigned int nb_chapters;
AVChapter **chapters;
@@ -1213,6 +1247,22 @@ typedef struct AVFormatContext {
*/
int seek2any;
+ /**
+ * Flush the I/O context after each packet.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int flush_packets;
+
+ /**
+ * format probing score.
+ * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
+ * the format.
+ * - encoding: unused
+ * - decoding: set by avformat, read by user via av_format_get_probe_score() (NO direct access)
+ */
+ int probe_score;
+
/*****************************************************************
* 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
@@ -1250,8 +1300,60 @@ typedef struct AVFormatContext {
*/
#define RAW_PACKET_BUFFER_SIZE 2500000
int raw_packet_buffer_remaining_size;
+
+ /**
+ * Offset to remap timestamps to be non-negative.
+ * Expressed in timebase units.
+ * @see AVStream.mux_ts_offset
+ */
+ int64_t offset;
+
+ /**
+ * Timebase for the timestamp offset.
+ */
+ AVRational offset_timebase;
+
+ /**
+ * IO repositioned flag.
+ * This is set by avformat when the underlaying IO context read pointer
+ * is repositioned, for example when doing byte based seeking.
+ * Demuxers can use the flag to detect such changes.
+ */
+ int io_repositioned;
+
+ /**
+ * Forced video codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_video_codec (NO direct access).
+ */
+ AVCodec *video_codec;
+
+ /**
+ * Forced audio codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_audio_codec (NO direct access).
+ */
+ AVCodec *audio_codec;
+
+ /**
+ * Forced subtitle codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access).
+ */
+ AVCodec *subtitle_codec;
} AVFormatContext;
+int av_format_get_probe_score(const AVFormatContext *s);
+AVCodec * av_format_get_video_codec(const AVFormatContext *s);
+void av_format_set_video_codec(AVFormatContext *s, AVCodec *c);
+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);
+
/**
* Returns the method used to set ctx->duration.
*
@@ -1361,6 +1463,9 @@ const AVClass *avformat_get_class(void);
*
* When muxing, should be called by the user before avformat_write_header().
*
+ * User is required to call avcodec_close() and avformat_free_context() to
+ * clean up the allocation by avformat_new_stream().
+ *
* @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.
@@ -1376,12 +1481,6 @@ AVProgram *av_new_program(AVFormatContext *s, int id);
*/
-#if FF_API_PKT_DUMP
-attribute_deprecated void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload);
-attribute_deprecated void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt,
- int dump_payload);
-#endif
-
#if FF_API_ALLOC_OUTPUT_CONTEXT
/**
* @deprecated deprecated in favor of avformat_alloc_output_context2()
@@ -1463,16 +1562,24 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score
* @param logctx the log context
* @param offset the offset within the bytestream to probe from
* @param max_probe_size the maximum probe buffer size (zero for default)
- * @return 0 in case of success, a negative value corresponding to an
+ * @return the score in case of success, a negative value corresponding to an
+ * the maximal score is AVPROBE_SCORE_MAX
* AVERROR code otherwise
*/
+int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
+ const char *filename, void *logctx,
+ unsigned int offset, unsigned int max_probe_size);
+
+/**
+ * Like av_probe_input_buffer2() but returns 0 on success
+ */
int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
const char *filename, void *logctx,
unsigned int offset, unsigned int max_probe_size);
/**
* Open an input stream and read the header. The codecs are not opened.
- * The stream must be closed with av_close_input_file().
+ * The stream must be closed with avformat_close_input().
*
* @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
* May be a pointer to NULL, in which case an AVFormatContext is allocated by this
@@ -1607,8 +1714,8 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt);
* information possible for decoding.
*
* If pkt->buf is NULL, then the packet is valid until the next
- * av_read_frame() or until av_close_input_file(). Otherwise the packet is valid
- * indefinitely. In both cases the packet must be freed with
+ * av_read_frame() or until avformat_close_input(). Otherwise the packet
+ * is valid indefinitely. In both cases the packet must be freed with
* av_free_packet when it is no longer needed. For video, the packet contains
* exactly one frame. For audio, it contains an integer number of frames if each
* frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames
@@ -1652,6 +1759,7 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
* or if stream_index is -1, in AV_TIME_BASE units.
* If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as
* keyframes (this may not be supported by all demuxers).
+ * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored.
*
* @param stream_index index of the stream which is used as time base reference
* @param min_ts smallest acceptable timestamp
@@ -1738,7 +1846,7 @@ void av_set_pts_info(AVStream *s, int pts_wrap_bits,
*
* @param s Media file handle, must be allocated with avformat_alloc_context().
* Its oformat field must be set to the desired output format;
- * Its pb field must be set to an already openened AVIOContext.
+ * Its pb field must be set to an already opened AVIOContext.
* @param options An AVDictionary filled with AVFormatContext and muxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
@@ -2101,6 +2209,16 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void);
AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame);
/**
+ * Guess the frame rate, based on both the container and codec information.
+ *
+ * @param ctx the format context which the stream is part of
+ * @param stream the stream which the frame is part of
+ * @param frame the frame for which the frame rate should be determined, may be NULL
+ * @return the guessed (valid) frame rate, 0/1 if no idea
+ */
+AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame);
+
+/**
* Check if the stream st contained in s is matched by the stream specifier
* spec.
*
diff --git a/ffmpeg/libavformat/avidec.c b/ffmpeg/libavformat/avidec.c
index f6eb71e..17eb245 100644
--- a/ffmpeg/libavformat/avidec.c
+++ b/ffmpeg/libavformat/avidec.c
@@ -19,36 +19,40 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/intreadwrite.h"
-#include "libavutil/mathematics.h"
+#include <stdint.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
#include "libavutil/bswap.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
-#include "libavutil/avstring.h"
-#include "libavutil/avassert.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mathematics.h"
#include "avformat.h"
-#include "internal.h"
#include "avi.h"
#include "dv.h"
+#include "internal.h"
#include "riff.h"
typedef struct AVIStream {
- int64_t frame_offset; /* current frame (video) or byte (audio) counter
- (used to compute the pts) */
+ int64_t frame_offset; /* current frame (video) or byte (audio) counter
+ * (used to compute the pts) */
int remaining;
int packet_size;
uint32_t scale;
uint32_t rate;
- int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */
-
- int64_t cum_len; /* temporary storage (used during seek) */
+ int sample_size; /* size of one sample (or packet)
+ * (in the rate/scale sense) in bytes */
- int prefix; ///< normally 'd'<<8 + 'c' or 'w'<<8 + 'b'
+ int64_t cum_len; /* temporary storage (used during seek) */
+ int prefix; /* normally 'd'<<8 + 'c' or 'w'<<8 + 'b' */
int prefix_count;
uint32_t pal[256];
int has_pal;
- int dshow_block_align; ///< block align variable used to emulate bugs in the MS dshow demuxer
+ int dshow_block_align; /* block align variable used to emulate bugs in
+ * the MS dshow demuxer */
AVFormatContext *sub_ctx;
AVPacket sub_pkt;
@@ -59,9 +63,9 @@ typedef struct AVIStream {
typedef struct {
const AVClass *class;
- int64_t riff_end;
- int64_t movi_end;
- int64_t fsize;
+ int64_t riff_end;
+ int64_t movi_end;
+ int64_t fsize;
int64_t io_fsize;
int64_t movi_list;
int64_t last_pkt_pos;
@@ -69,7 +73,7 @@ typedef struct {
int is_odml;
int non_interleaved;
int stream_index;
- DVDemuxContext* dv_demux;
+ DVDemuxContext *dv_demux;
int odml_depth;
int use_odml;
#define MAX_ODML_DEPTH 1000
@@ -92,11 +96,11 @@ static const AVClass demuxer_class = {
static const char avi_headers[][8] = {
- { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' },
- { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' },
- { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19},
- { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' },
- { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' },
+ { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' },
+ { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' },
+ { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19 },
+ { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' },
+ { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' },
{ 0 }
};
@@ -108,20 +112,21 @@ static const AVMetadataConv avi_metadata_conv[] = {
static int avi_load_index(AVFormatContext *s);
static int guess_ni_flag(AVFormatContext *s);
-#define print_tag(str, tag, size) \
- av_dlog(NULL, "%s: tag=%c%c%c%c size=0x%x\n", \
- str, tag & 0xff, \
- (tag >> 8) & 0xff, \
- (tag >> 16) & 0xff, \
- (tag >> 24) & 0xff, \
- size)
+#define print_tag(str, tag, size) \
+ av_dlog(NULL, "pos:%"PRIX64" %s: tag=%c%c%c%c size=0x%x\n", \
+ avio_tell(pb), str, tag & 0xff, \
+ (tag >> 8) & 0xff, \
+ (tag >> 16) & 0xff, \
+ (tag >> 24) & 0xff, \
+ size)
-static inline int get_duration(AVIStream *ast, int len){
- if(ast->sample_size){
+static inline int get_duration(AVIStream *ast, int len)
+{
+ if (ast->sample_size)
return len;
- }else if (ast->dshow_block_align){
- return (len + ast->dshow_block_align - 1)/ast->dshow_block_align;
- }else
+ else if (ast->dshow_block_align)
+ return (len + ast->dshow_block_align - 1) / ast->dshow_block_align;
+ else
return 1;
}
@@ -133,164 +138,180 @@ static int get_riff(AVFormatContext *s, AVIOContext *pb)
/* check RIFF header */
avio_read(pb, header, 4);
- avi->riff_end = avio_rl32(pb); /* RIFF chunk size */
+ avi->riff_end = avio_rl32(pb); /* RIFF chunk size */
avi->riff_end += avio_tell(pb); /* RIFF chunk end */
- avio_read(pb, header+4, 4);
+ avio_read(pb, header + 4, 4);
- for(i=0; avi_headers[i][0]; i++)
- if(!memcmp(header, avi_headers[i], 8))
+ for (i = 0; avi_headers[i][0]; i++)
+ if (!memcmp(header, avi_headers[i], 8))
break;
- if(!avi_headers[i][0])
+ if (!avi_headers[i][0])
return AVERROR_INVALIDDATA;
- if(header[7] == 0x19)
- av_log(s, AV_LOG_INFO, "This file has been generated by a totally broken muxer.\n");
+ if (header[7] == 0x19)
+ av_log(s, AV_LOG_INFO,
+ "This file has been generated by a totally broken muxer.\n");
return 0;
}
-static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){
- AVIContext *avi = s->priv_data;
- AVIOContext *pb = s->pb;
- int longs_pre_entry= avio_rl16(pb);
- int index_sub_type = avio_r8(pb);
- int index_type = avio_r8(pb);
- int entries_in_use = avio_rl32(pb);
- int chunk_id = avio_rl32(pb);
- int64_t base = avio_rl64(pb);
- int stream_id= 10*((chunk_id&0xFF) - '0') + (((chunk_id>>8)&0xFF) - '0');
+static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
+{
+ AVIContext *avi = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int longs_pre_entry = avio_rl16(pb);
+ int index_sub_type = avio_r8(pb);
+ int index_type = avio_r8(pb);
+ int entries_in_use = avio_rl32(pb);
+ int chunk_id = avio_rl32(pb);
+ int64_t base = avio_rl64(pb);
+ int stream_id = ((chunk_id & 0xFF) - '0') * 10 +
+ ((chunk_id >> 8 & 0xFF) - '0');
AVStream *st;
AVIStream *ast;
int i;
- int64_t last_pos= -1;
- int64_t filesize= avi->fsize;
-
- av_dlog(s, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n",
- longs_pre_entry,index_type, entries_in_use, chunk_id, base);
-
- if(stream_id >= s->nb_streams || stream_id < 0)
+ int64_t last_pos = -1;
+ int64_t filesize = avi->fsize;
+
+ av_dlog(s,
+ "longs_pre_entry:%d index_type:%d entries_in_use:%d "
+ "chunk_id:%X base:%16"PRIX64"\n",
+ longs_pre_entry,
+ index_type,
+ entries_in_use,
+ chunk_id,
+ base);
+
+ if (stream_id >= s->nb_streams || stream_id < 0)
return AVERROR_INVALIDDATA;
- st= s->streams[stream_id];
+ st = s->streams[stream_id];
ast = st->priv_data;
- if(index_sub_type)
+ if (index_sub_type)
return AVERROR_INVALIDDATA;
avio_rl32(pb);
- if(index_type && longs_pre_entry != 2)
+ if (index_type && longs_pre_entry != 2)
return AVERROR_INVALIDDATA;
- if(index_type>1)
+ if (index_type > 1)
return AVERROR_INVALIDDATA;
- if(filesize > 0 && base >= filesize){
+ if (filesize > 0 && base >= filesize) {
av_log(s, AV_LOG_ERROR, "ODML index invalid\n");
- if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF)
+ if (base >> 32 == (base & 0xFFFFFFFF) &&
+ (base & 0xFFFFFFFF) < filesize &&
+ filesize <= 0xFFFFFFFF)
base &= 0xFFFFFFFF;
else
return AVERROR_INVALIDDATA;
}
- for(i=0; i<entries_in_use; i++){
- if(index_type){
- int64_t pos= avio_rl32(pb) + base - 8;
- int len = avio_rl32(pb);
- int key= len >= 0;
+ for (i = 0; i < entries_in_use; i++) {
+ if (index_type) {
+ int64_t pos = avio_rl32(pb) + base - 8;
+ int len = avio_rl32(pb);
+ int key = len >= 0;
len &= 0x7FFFFFFF;
#ifdef DEBUG_SEEK
av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len);
#endif
- if(url_feof(pb))
+ if (url_feof(pb))
return AVERROR_INVALIDDATA;
- if(last_pos == pos || pos == base - 8)
- avi->non_interleaved= 1;
- if(last_pos != pos && (len || !ast->sample_size))
- av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0);
+ if (last_pos == pos || pos == base - 8)
+ avi->non_interleaved = 1;
+ if (last_pos != pos && (len || !ast->sample_size))
+ av_add_index_entry(st, pos, ast->cum_len, len, 0,
+ key ? AVINDEX_KEYFRAME : 0);
ast->cum_len += get_duration(ast, len);
- last_pos= pos;
- }else{
+ last_pos = pos;
+ } else {
int64_t offset, pos;
int duration;
offset = avio_rl64(pb);
avio_rl32(pb); /* size */
duration = avio_rl32(pb);
- if(url_feof(pb))
+ if (url_feof(pb))
return AVERROR_INVALIDDATA;
pos = avio_tell(pb);
- if(avi->odml_depth > MAX_ODML_DEPTH){
+ if (avi->odml_depth > MAX_ODML_DEPTH) {
av_log(s, AV_LOG_ERROR, "Too deeply nested ODML indexes\n");
return AVERROR_INVALIDDATA;
}
- if(avio_seek(pb, offset+8, SEEK_SET) < 0)
+ if (avio_seek(pb, offset + 8, SEEK_SET) < 0)
return -1;
avi->odml_depth++;
read_braindead_odml_indx(s, frame_num);
avi->odml_depth--;
frame_num += duration;
- if(avio_seek(pb, pos, SEEK_SET) < 0) {
+ if (avio_seek(pb, pos, SEEK_SET) < 0) {
av_log(s, AV_LOG_ERROR, "Failed to restore position after reading index\n");
return -1;
}
}
}
- avi->index_loaded=2;
+ avi->index_loaded = 2;
return 0;
}
-static void clean_index(AVFormatContext *s){
+static void clean_index(AVFormatContext *s)
+{
int i;
int64_t j;
- for(i=0; i<s->nb_streams; i++){
- AVStream *st = s->streams[i];
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
- int n= st->nb_index_entries;
- int max= ast->sample_size;
+ int n = st->nb_index_entries;
+ int max = ast->sample_size;
int64_t pos, size, ts;
- if(n != 1 || ast->sample_size==0)
+ if (n != 1 || ast->sample_size == 0)
continue;
- while(max < 1024) max+=max;
+ while (max < 1024)
+ max += max;
- pos= st->index_entries[0].pos;
- size= st->index_entries[0].size;
- ts= st->index_entries[0].timestamp;
+ pos = st->index_entries[0].pos;
+ size = st->index_entries[0].size;
+ ts = st->index_entries[0].timestamp;
- for(j=0; j<size; j+=max){
- av_add_index_entry(st, pos+j, ts+j, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME);
- }
+ for (j = 0; j < size; j += max)
+ av_add_index_entry(st, pos + j, ts + j, FFMIN(max, size - j), 0,
+ AVINDEX_KEYFRAME);
}
}
-static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag, uint32_t size)
+static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag,
+ uint32_t size)
{
AVIOContext *pb = s->pb;
- char key[5] = {0}, *value;
+ char key[5] = { 0 };
+ char *value;
size += (size & 1);
if (size == UINT_MAX)
return AVERROR(EINVAL);
- value = av_malloc(size+1);
+ value = av_malloc(size + 1);
if (!value)
return AVERROR(ENOMEM);
avio_read(pb, value, size);
- value[size]=0;
+ value[size] = 0;
AV_WL32(key, tag);
return av_dict_set(st ? &st->metadata : &s->metadata, key, value,
- AV_DICT_DONT_STRDUP_VAL);
+ AV_DICT_DONT_STRDUP_VAL);
}
static const char months[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -303,10 +324,10 @@ static void avi_metadata_creation_time(AVDictionary **metadata, char *date)
/* parse standard AVI date format (ie. "Mon Mar 10 15:04:43 2003") */
if (sscanf(date, "%*3s%*[ ]%3s%*[ ]%2d%*[ ]%8s%*[ ]%4d",
month, &day, time, &year) == 4) {
- for (i=0; i<12; i++)
+ for (i = 0; i < 12; i++)
if (!av_strcasecmp(month, months[i])) {
snprintf(buffer, sizeof(buffer), "%.4d-%.2d-%.2d %s",
- year, i+1, day, time);
+ year, i + 1, day, time);
av_dict_set(metadata, "creation_time", buffer, 0);
}
} else if (date[4] == '/' && date[7] == '/') {
@@ -321,19 +342,25 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end)
uint32_t tag = avio_rl32(s->pb);
uint32_t size = avio_rl32(s->pb);
switch (tag) {
- case MKTAG('n', 'c', 't', 'g'): { /* Nikon Tags */
+ case MKTAG('n', 'c', 't', 'g'): /* Nikon Tags */
+ {
uint64_t tag_end = avio_tell(s->pb) + size;
while (avio_tell(s->pb) < tag_end) {
- uint16_t tag = avio_rl16(s->pb);
- uint16_t size = avio_rl16(s->pb);
+ uint16_t tag = avio_rl16(s->pb);
+ uint16_t size = avio_rl16(s->pb);
const char *name = NULL;
- char buffer[64] = {0};
+ char buffer[64] = { 0 };
size -= avio_read(s->pb, buffer,
- FFMIN(size, sizeof(buffer)-1));
+ FFMIN(size, sizeof(buffer) - 1));
switch (tag) {
- case 0x03: name = "maker"; break;
- case 0x04: name = "model"; break;
- case 0x13: name = "creation_time";
+ case 0x03:
+ name = "maker";
+ break;
+ case 0x04:
+ name = "model";
+ break;
+ case 0x13:
+ name = "creation_time";
if (buffer[4] == ':' && buffer[7] == ':')
buffer[4] = buffer[7] = '-';
break;
@@ -360,13 +387,14 @@ static int avi_read_header(AVFormatContext *s)
unsigned int size;
int i;
AVStream *st;
- AVIStream *ast = NULL;
- int avih_width=0, avih_height=0;
- int amv_file_format=0;
- uint64_t list_end = 0;
+ AVIStream *ast = NULL;
+ int avih_width = 0, avih_height = 0;
+ int amv_file_format = 0;
+ uint64_t list_end = 0;
int ret;
+ AVDictionaryEntry *dict_entry;
- avi->stream_index= -1;
+ avi->stream_index = -1;
ret = get_riff(s, pb);
if (ret < 0)
@@ -375,22 +403,22 @@ static int avi_read_header(AVFormatContext *s)
av_log(avi, AV_LOG_DEBUG, "use odml:%d\n", avi->use_odml);
avi->io_fsize = avi->fsize = avio_size(pb);
- if(avi->fsize<=0 || avi->fsize < avi->riff_end)
- avi->fsize= avi->riff_end == 8 ? INT64_MAX : avi->riff_end;
+ if (avi->fsize <= 0 || avi->fsize < avi->riff_end)
+ avi->fsize = avi->riff_end == 8 ? INT64_MAX : avi->riff_end;
/* first list tag */
stream_index = -1;
- codec_type = -1;
+ codec_type = -1;
frame_period = 0;
- for(;;) {
+ for (;;) {
if (url_feof(pb))
goto fail;
- tag = avio_rl32(pb);
+ tag = avio_rl32(pb);
size = avio_rl32(pb);
print_tag("tag", tag, size);
- switch(tag) {
+ switch (tag) {
case MKTAG('L', 'I', 'S', 'T'):
list_end = avio_tell(pb) + size;
/* Ignored, except at start of video packets. */
@@ -400,21 +428,23 @@ static int avi_read_header(AVFormatContext *s)
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
avi->movi_list = avio_tell(pb) - 4;
- if(size) avi->movi_end = avi->movi_list + size + (size & 1);
- else avi->movi_end = avi->fsize;
+ if (size)
+ avi->movi_end = avi->movi_list + size + (size & 1);
+ else
+ avi->movi_end = avi->fsize;
av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end);
goto end_of_header;
- }
- else if (tag1 == MKTAG('I', 'N', 'F', 'O'))
+ } else if (tag1 == MKTAG('I', 'N', 'F', 'O'))
ff_read_riff_info(s, size - 4);
else if (tag1 == MKTAG('n', 'c', 'd', 't'))
avi_read_nikon(s, list_end);
break;
- case MKTAG('I', 'D', 'I', 'T'): {
- unsigned char date[64] = {0};
+ case MKTAG('I', 'D', 'I', 'T'):
+ {
+ unsigned char date[64] = { 0 };
size += (size & 1);
- size -= avio_read(pb, date, FFMIN(size, sizeof(date)-1));
+ size -= avio_read(pb, date, FFMIN(size, sizeof(date) - 1));
avio_skip(pb, size);
avi_metadata_creation_time(&s->metadata, date);
break;
@@ -424,7 +454,7 @@ static int avi_read_header(AVFormatContext *s)
avio_skip(pb, size + (size & 1));
break;
case MKTAG('a', 'm', 'v', 'h'):
- amv_file_format=1;
+ amv_file_format = 1;
case MKTAG('a', 'v', 'i', 'h'):
/* AVI header */
/* using frame_period is bad idea */
@@ -436,51 +466,51 @@ static int avi_read_header(AVFormatContext *s)
avio_skip(pb, 2 * 4);
avio_rl32(pb);
avio_rl32(pb);
- avih_width=avio_rl32(pb);
- avih_height=avio_rl32(pb);
+ avih_width = avio_rl32(pb);
+ avih_height = avio_rl32(pb);
avio_skip(pb, size - 10 * 4);
break;
case MKTAG('s', 't', 'r', 'h'):
/* stream header */
- tag1 = avio_rl32(pb);
+ tag1 = avio_rl32(pb);
handler = avio_rl32(pb); /* codec tag */
- if(tag1 == MKTAG('p', 'a', 'd', 's')){
+ if (tag1 == MKTAG('p', 'a', 'd', 's')) {
avio_skip(pb, size - 8);
break;
- }else{
+ } else {
stream_index++;
st = avformat_new_stream(s, NULL);
if (!st)
goto fail;
st->id = stream_index;
- ast = av_mallocz(sizeof(AVIStream));
+ ast = av_mallocz(sizeof(AVIStream));
if (!ast)
goto fail;
st->priv_data = ast;
}
- if(amv_file_format)
- tag1 = stream_index ? MKTAG('a','u','d','s') : MKTAG('v','i','d','s');
+ if (amv_file_format)
+ tag1 = stream_index ? MKTAG('a', 'u', 'd', 's')
+ : MKTAG('v', 'i', 'd', 's');
print_tag("strh", tag1, -1);
- if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){
+ if (tag1 == MKTAG('i', 'a', 'v', 's') ||
+ tag1 == MKTAG('i', 'v', 'a', 's')) {
int64_t dv_dur;
- /*
- * After some consideration -- I don't think we
- * have to support anything but DV in type1 AVIs.
- */
+ /* After some consideration -- I don't think we
+ * have to support anything but DV in type1 AVIs. */
if (s->nb_streams != 1)
goto fail;
if (handler != MKTAG('d', 'v', 's', 'd') &&
handler != MKTAG('d', 'v', 'h', 'd') &&
handler != MKTAG('d', 'v', 's', 'l'))
- goto fail;
+ goto fail;
ast = s->streams[0]->priv_data;
av_freep(&s->streams[0]->codec->extradata);
@@ -494,50 +524,53 @@ static int avi_read_header(AVFormatContext *s)
avi->dv_demux = avpriv_dv_init_demux(s);
if (!avi->dv_demux)
goto fail;
- }
+ } else
+ goto fail;
s->streams[0]->priv_data = ast;
avio_skip(pb, 3 * 4);
ast->scale = avio_rl32(pb);
- ast->rate = avio_rl32(pb);
+ ast->rate = avio_rl32(pb);
avio_skip(pb, 4); /* start time */
dv_dur = avio_rl32(pb);
if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) {
- dv_dur *= AV_TIME_BASE;
+ dv_dur *= AV_TIME_BASE;
s->duration = av_rescale(dv_dur, ast->scale, ast->rate);
}
- /*
- * else, leave duration alone; timing estimation in utils.c
- * will make a guess based on bitrate.
- */
+ /* else, leave duration alone; timing estimation in utils.c
+ * will make a guess based on bitrate. */
stream_index = s->nb_streams - 1;
- avio_skip(pb, size - 9*4);
+ avio_skip(pb, size - 9 * 4);
break;
}
av_assert0(stream_index < s->nb_streams);
- st->codec->stream_codec_tag= handler;
+ st->codec->stream_codec_tag = handler;
avio_rl32(pb); /* flags */
avio_rl16(pb); /* priority */
avio_rl16(pb); /* language */
avio_rl32(pb); /* initial frame */
ast->scale = avio_rl32(pb);
- ast->rate = avio_rl32(pb);
- if(!(ast->scale && ast->rate)){
- av_log(s, AV_LOG_WARNING, "scale/rate is %u/%u which is invalid. (This file has been generated by broken software.)\n", ast->scale, ast->rate);
- if(frame_period){
- ast->rate = 1000000;
+ ast->rate = avio_rl32(pb);
+ if (!(ast->scale && ast->rate)) {
+ av_log(s, AV_LOG_WARNING,
+ "scale/rate is %u/%u which is invalid. "
+ "(This file has been generated by broken software.)\n",
+ ast->scale,
+ ast->rate);
+ if (frame_period) {
+ ast->rate = 1000000;
ast->scale = frame_period;
- }else{
- ast->rate = 25;
+ } else {
+ ast->rate = 25;
ast->scale = 1;
}
}
avpriv_set_pts_info(st, 64, ast->scale, ast->rate);
- ast->cum_len=avio_rl32(pb); /* start */
+ ast->cum_len = avio_rl32(pb); /* start */
st->nb_frames = avio_rl32(pb);
st->start_time = 0;
@@ -548,11 +581,11 @@ static int avi_read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
ast->sample_size = avio_rl32(pb); /* sample ssize */
- ast->cum_len *= FFMAX(1, ast->sample_size);
+ ast->cum_len *= FFMAX(1, ast->sample_size);
av_dlog(s, "%"PRIu32" %"PRIu32" %d\n",
ast->rate, ast->scale, ast->sample_size);
- switch(tag1) {
+ switch (tag1) {
case MKTAG('v', 'i', 'd', 's'):
codec_type = AVMEDIA_TYPE_VIDEO;
@@ -570,14 +603,14 @@ static int avi_read_header(AVFormatContext *s)
default:
av_log(s, AV_LOG_INFO, "unknown stream type %X\n", tag1);
}
- if(ast->sample_size == 0) {
+ if (ast->sample_size == 0) {
st->duration = st->nb_frames;
if (st->duration > 0 && avi->io_fsize > 0 && avi->riff_end > avi->io_fsize) {
av_log(s, AV_LOG_DEBUG, "File is truncated adjusting duration\n");
st->duration = av_rescale(st->duration, avi->io_fsize, avi->riff_end);
}
}
- ast->frame_offset= ast->cum_len;
+ ast->frame_offset = ast->cum_len;
avio_skip(pb, size - 12 * 4);
break;
case MKTAG('s', 't', 'r', 'f'):
@@ -592,49 +625,56 @@ static int avi_read_header(AVFormatContext *s)
if (cur_pos < list_end)
size = FFMIN(size, list_end - cur_pos);
st = s->streams[stream_index];
- switch(codec_type) {
+ if (st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) {
+ avio_skip(pb, size);
+ break;
+ }
+ switch (codec_type) {
case AVMEDIA_TYPE_VIDEO:
- if(amv_file_format){
- st->codec->width=avih_width;
- st->codec->height=avih_height;
+ if (amv_file_format) {
+ st->codec->width = avih_width;
+ st->codec->height = avih_height;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_AMV;
+ st->codec->codec_id = AV_CODEC_ID_AMV;
avio_skip(pb, size);
break;
}
tag1 = ff_get_bmp_header(pb, st, &esize);
- if (tag1 == MKTAG('D', 'X', 'S', 'B') || tag1 == MKTAG('D','X','S','A')) {
+ if (tag1 == MKTAG('D', 'X', 'S', 'B') ||
+ tag1 == MKTAG('D', 'X', 'S', 'A')) {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- st->codec->codec_tag = tag1;
- st->codec->codec_id = AV_CODEC_ID_XSUB;
+ st->codec->codec_tag = tag1;
+ st->codec->codec_id = AV_CODEC_ID_XSUB;
break;
}
- if(size > 10*4 && size<(1<<30) && size < avi->fsize){
- if(esize == size-1 && (esize&1)) st->codec->extradata_size= esize - 10*4;
- else st->codec->extradata_size= size - 10*4;
- st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
- st->codec->extradata_size= 0;
+ if (size > 10 * 4 && size < (1 << 30) && size < avi->fsize) {
+ if (esize == size-1 && (esize&1)) {
+ st->codec->extradata_size = esize - 10 * 4;
+ } else
+ st->codec->extradata_size = size - 10 * 4;
+ 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);
}
- if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
+ // FIXME: check if the encoder really did this correctly
+ if (st->codec->extradata_size & 1)
avio_r8(pb);
- /* Extract palette from extradata if bpp <= 8. */
- /* This code assumes that extradata contains only palette. */
- /* This is true for all paletted codecs implemented in FFmpeg. */
- if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) {
+ /* Extract palette from extradata if bpp <= 8.
+ * This code assumes that extradata contains only palette.
+ * This is true for all paletted codecs implemented in
+ * FFmpeg. */
+ if (st->codec->extradata_size &&
+ (st->codec->bits_per_coded_sample <= 8)) {
int pal_size = (1 << st->codec->bits_per_coded_sample) << 2;
const uint8_t *pal_src;
pal_size = FFMIN(pal_size, st->codec->extradata_size);
- pal_src = st->codec->extradata + st->codec->extradata_size - pal_size;
- for (i = 0; i < pal_size/4; i++)
+ pal_src = st->codec->extradata +
+ st->codec->extradata_size - pal_size;
+ for (i = 0; i < pal_size / 4; i++)
ast->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
ast->has_pal = 1;
}
@@ -642,17 +682,26 @@ static int avi_read_header(AVFormatContext *s)
print_tag("video", tag1, 0);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_tag = tag1;
- st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag1);
- st->need_parsing = AVSTREAM_PARSE_HEADERS; // This is needed to get the pict type which is necessary for generating correct pts.
-
- if(st->codec->codec_tag==0 && st->codec->height > 0 && st->codec->extradata_size < 1U<<30){
- st->codec->extradata_size+= 9;
- st->codec->extradata= av_realloc_f(st->codec->extradata, 1, st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if(st->codec->extradata)
- memcpy(st->codec->extradata + st->codec->extradata_size - 9, "BottomUp", 9);
+ st->codec->codec_tag = tag1;
+ st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags,
+ tag1);
+ /* 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 == 0 && st->codec->height > 0 &&
+ st->codec->extradata_size < 1U << 30) {
+ st->codec->extradata_size += 9;
+ if ((ret = av_reallocp(&st->codec->extradata,
+ st->codec->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
+ st->codec->extradata_size = 0;
+ return ret;
+ } else
+ memcpy(st->codec->extradata + st->codec->extradata_size - 9,
+ "BottomUp", 9);
}
- st->codec->height= FFABS(st->codec->height);
+ st->codec->height = FFABS(st->codec->height);
// avio_skip(pb, size - 5 * 4);
break;
@@ -660,12 +709,19 @@ static int avi_read_header(AVFormatContext *s)
ret = ff_get_wav_header(pb, st->codec, size);
if (ret < 0)
return ret;
- ast->dshow_block_align= st->codec->block_align;
- if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){
- av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align);
- ast->sample_size= st->codec->block_align;
+ ast->dshow_block_align = st->codec->block_align;
+ if (ast->sample_size && st->codec->block_align &&
+ ast->sample_size != st->codec->block_align) {
+ av_log(s,
+ AV_LOG_WARNING,
+ "sample size (%d) != block align (%d)\n",
+ ast->sample_size,
+ st->codec->block_align);
+ ast->sample_size = st->codec->block_align;
}
- if (size&1) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
+ /* 2-aligned
+ * (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
+ if (size & 1)
avio_skip(pb, 1);
/* Force parsing as several audio frames can be in
* one packet and timestamps refer to packet start. */
@@ -673,24 +729,25 @@ static int avi_read_header(AVFormatContext *s)
/* ADTS header is in extradata, AAC without header must be
* stored as exact frames. Parser not needed and it will
* fail. */
- if (st->codec->codec_id == AV_CODEC_ID_AAC && st->codec->extradata_size)
+ if (st->codec->codec_id == AV_CODEC_ID_AAC &&
+ st->codec->extradata_size)
st->need_parsing = AVSTREAM_PARSE_NONE;
/* AVI files with Xan DPCM audio (wrongly) declare PCM
* audio in the header but have Axan as stream_code_tag. */
- if (st->codec->stream_codec_tag == AV_RL32("Axan")){
+ if (st->codec->stream_codec_tag == AV_RL32("Axan")) {
st->codec->codec_id = AV_CODEC_ID_XAN_DPCM;
st->codec->codec_tag = 0;
ast->dshow_block_align = 0;
}
- if (amv_file_format){
- st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV;
+ if (amv_file_format) {
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV;
ast->dshow_block_align = 0;
}
- if(st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align) {
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align) {
av_log(s, AV_LOG_DEBUG, "overriding invalid dshow_block_align of %d\n", ast->dshow_block_align);
ast->dshow_block_align = 0;
}
- if(st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 1024 && ast->sample_size == 1024 ||
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 1024 && ast->sample_size == 1024 ||
st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 4096 && ast->sample_size == 4096 ||
st->codec->codec_id == AV_CODEC_ID_MP3 && ast->dshow_block_align == 1152 && ast->sample_size == 1152) {
av_log(s, AV_LOG_DEBUG, "overriding sample_size\n");
@@ -704,15 +761,17 @@ static int avi_read_header(AVFormatContext *s)
break;
default:
st->codec->codec_type = AVMEDIA_TYPE_DATA;
- st->codec->codec_id= AV_CODEC_ID_NONE;
- st->codec->codec_tag= 0;
+ st->codec->codec_id = AV_CODEC_ID_NONE;
+ st->codec->codec_tag = 0;
avio_skip(pb, size);
break;
}
}
break;
case MKTAG('s', 't', 'r', 'd'):
- if (stream_index >= (unsigned)s->nb_streams || s->streams[stream_index]->codec->extradata_size) {
+ if (stream_index >= (unsigned)s->nb_streams
+ || s->streams[stream_index]->codec->extradata_size
+ || s->streams[stream_index]->codec->codec_tag == MKTAG('H','2','6','4')) {
avio_skip(pb, size);
} else {
uint64_t cur_pos = avio_tell(pb);
@@ -720,29 +779,26 @@ static int avi_read_header(AVFormatContext *s)
size = FFMIN(size, list_end - cur_pos);
st = s->streams[stream_index];
- if(size<(1<<30)){
- st->codec->extradata_size= size;
- st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
- st->codec->extradata_size= 0;
+ if (size<(1<<30)) {
+ 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
+ if (st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
avio_r8(pb);
}
break;
case MKTAG('i', 'n', 'd', 'x'):
- i= avio_tell(pb);
- if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && avi->use_odml &&
- read_braindead_odml_indx(s, 0) < 0 && (s->error_recognition & AV_EF_EXPLODE))
+ i = avio_tell(pb);
+ if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
+ avi->use_odml &&
+ read_braindead_odml_indx(s, 0) < 0 &&
+ (s->error_recognition & AV_EF_EXPLODE))
goto fail;
- avio_seek(pb, i+size, SEEK_SET);
+ avio_seek(pb, i + size, SEEK_SET);
break;
case MKTAG('v', 'p', 'r', 'p'):
- if(stream_index < (unsigned)s->nb_streams && size > 9*4){
+ if (stream_index < (unsigned)s->nb_streams && size > 9 * 4) {
AVRational active, active_aspect;
st = s->streams[stream_index];
@@ -752,33 +808,35 @@ static int avi_read_header(AVFormatContext *s)
avio_rl32(pb);
avio_rl32(pb);
- active_aspect.den= avio_rl16(pb);
- active_aspect.num= avio_rl16(pb);
- active.num = avio_rl32(pb);
- active.den = avio_rl32(pb);
- avio_rl32(pb); //nbFieldsPerFrame
+ active_aspect.den = avio_rl16(pb);
+ active_aspect.num = avio_rl16(pb);
+ active.num = avio_rl32(pb);
+ active.den = avio_rl32(pb);
+ avio_rl32(pb); // nbFieldsPerFrame
- if(active_aspect.num && active_aspect.den && active.num && active.den){
- st->sample_aspect_ratio= av_div_q(active_aspect, active);
+ if (active_aspect.num && active_aspect.den &&
+ active.num && active.den) {
+ st->sample_aspect_ratio = av_div_q(active_aspect, active);
av_dlog(s, "vprp %d/%d %d/%d\n",
active_aspect.num, active_aspect.den,
active.num, active.den);
}
- size -= 9*4;
+ size -= 9 * 4;
}
avio_skip(pb, size);
break;
case MKTAG('s', 't', 'r', 'n'):
- if(s->nb_streams){
- ret = avi_read_tag(s, s->streams[s->nb_streams-1], tag, size);
+ if (s->nb_streams) {
+ ret = avi_read_tag(s, s->streams[s->nb_streams - 1], tag, size);
if (ret < 0)
return ret;
break;
}
default:
- if(size > 1000000){
- av_log(s, AV_LOG_ERROR, "Something went wrong during header parsing, "
- "I will ignore it and try to continue anyway.\n");
+ if (size > 1000000) {
+ av_log(s, AV_LOG_ERROR,
+ "Something went wrong during header parsing, "
+ "I will ignore it and try to continue anyway.\n");
if (s->error_recognition & AV_EF_EXPLODE)
goto fail;
avi->movi_list = avio_tell(pb) - 4;
@@ -791,32 +849,45 @@ static int avi_read_header(AVFormatContext *s)
break;
}
}
- end_of_header:
+
+end_of_header:
/* check stream number */
if (stream_index != s->nb_streams - 1) {
- fail:
+
+fail:
return AVERROR_INVALIDDATA;
}
- if(!avi->index_loaded && pb->seekable)
+ if (!avi->index_loaded && pb->seekable)
avi_load_index(s);
- avi->index_loaded |= 1;
+ avi->index_loaded |= 1;
avi->non_interleaved |= guess_ni_flag(s) | (s->flags & AVFMT_FLAG_SORT_DTS);
- for(i=0; i<s->nb_streams; i++){
+
+ dict_entry = av_dict_get(s->metadata, "ISFT", NULL, 0);
+ if (dict_entry && !strcmp(dict_entry->value, "PotEncoder"))
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if ( st->codec->codec_id == AV_CODEC_ID_MPEG1VIDEO
+ || st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
- if(st->nb_index_entries)
+ if (st->nb_index_entries)
break;
}
// DV-in-AVI cannot be non-interleaved, if set this must be
// a mis-detection.
- if(avi->dv_demux)
- avi->non_interleaved=0;
- if(i==s->nb_streams && avi->non_interleaved) {
- av_log(s, AV_LOG_WARNING, "non-interleaved AVI without index, switching to interleaved\n");
- avi->non_interleaved=0;
+ if (avi->dv_demux)
+ avi->non_interleaved = 0;
+ if (i == s->nb_streams && avi->non_interleaved) {
+ av_log(s, AV_LOG_WARNING,
+ "Non-interleaved AVI without index, switching to interleaved\n");
+ avi->non_interleaved = 0;
}
- if(avi->non_interleaved) {
+ if (avi->non_interleaved) {
av_log(s, AV_LOG_INFO, "non-interleaved AVI\n");
clean_index(s);
}
@@ -827,16 +898,18 @@ static int avi_read_header(AVFormatContext *s)
return 0;
}
-static int read_gab2_sub(AVStream *st, AVPacket *pkt) {
- if (pkt->data && !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data+5) == 2) {
+static int read_gab2_sub(AVStream *st, AVPacket *pkt)
+{
+ if (pkt->size >= 7 &&
+ !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data + 5) == 2) {
uint8_t desc[256];
- int score = AVPROBE_SCORE_MAX / 2, ret;
+ int score = AVPROBE_SCORE_EXTENSION, ret;
AVIStream *ast = st->priv_data;
AVInputFormat *sub_demuxer;
AVRational time_base;
- AVIOContext *pb = avio_alloc_context( pkt->data + 7,
- pkt->size - 7,
- 0, NULL, NULL, NULL, NULL);
+ AVIOContext *pb = avio_alloc_context(pkt->data + 7,
+ pkt->size - 7,
+ 0, NULL, NULL, NULL, NULL);
AVProbeData pd;
unsigned int desc_len = avio_rl32(pb);
@@ -851,14 +924,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 };
+ pd = (AVProbeData) { .buf = pb->buf_ptr,
+ .buf_size = pb->buf_end - pb->buf_ptr };
if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score)))
goto error;
if (!(ast->sub_ctx = avformat_alloc_context()))
goto error;
- ast->sub_ctx->pb = pb;
+ ast->sub_ctx->pb = pb;
if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) {
ff_read_packet(ast->sub_ctx, &ast->sub_pkt);
*st->codec = *ast->sub_ctx->streams[0]->codec;
@@ -869,6 +943,7 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) {
ast->sub_buffer = pkt->data;
memset(pkt, 0, sizeof(*pkt));
return 1;
+
error:
av_freep(&pb);
}
@@ -886,7 +961,7 @@ static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st,
next_ts = av_rescale_q(next_ast->frame_offset, next_st->time_base,
AV_TIME_BASE_Q);
- for (i=0; i<s->nb_streams; i++) {
+ for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
ast = st->priv_data;
if (st->discard < AVDISCARD_ALL && ast && ast->sub_pkt.data) {
@@ -899,21 +974,23 @@ static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st,
}
if (sub_st) {
- ast = sub_st->priv_data;
- *pkt = ast->sub_pkt;
+ ast = sub_st->priv_data;
+ *pkt = ast->sub_pkt;
pkt->stream_index = sub_st->index;
+
if (ff_read_packet(ast->sub_ctx, &ast->sub_pkt) < 0)
ast->sub_pkt.data = NULL;
}
return sub_st;
}
-static int get_stream_idx(int *d){
- if( d[0] >= '0' && d[0] <= '9'
- && d[1] >= '0' && d[1] <= '9'){
+static int get_stream_idx(unsigned *d)
+{
+ if (d[0] >= '0' && d[0] <= '9' &&
+ d[1] >= '0' && d[1] <= '9') {
return (d[0] - '0') * 10 + (d[1] - '0');
- }else{
- return 100; //invalid stream ID
+ } else {
+ return 100; // invalid stream ID
}
}
@@ -932,52 +1009,53 @@ static int avi_sync(AVFormatContext *s, int exit_early)
start_sync:
memset(d, -1, sizeof(d));
- for(i=sync=avio_tell(pb); !url_feof(pb); i++) {
+ for (i = sync = avio_tell(pb); !url_feof(pb); i++) {
int j;
- for(j=0; j<7; j++)
- d[j]= d[j+1];
- d[7]= avio_r8(pb);
+ for (j = 0; j < 7; j++)
+ d[j] = d[j + 1];
+ d[7] = avio_r8(pb);
- size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24);
+ size = d[4] + (d[5] << 8) + (d[6] << 16) + (d[7] << 24);
- n= get_stream_idx(d+2);
+ n = get_stream_idx(d + 2);
av_dlog(s, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n);
- if(i + (uint64_t)size > avi->fsize || d[0] > 127)
+ if (i*(avi->io_fsize>0) + (uint64_t)size > avi->fsize || d[0] > 127)
continue;
- //parse ix##
- if( (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams)
- //parse JUNK
- ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')
- ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){
+ // parse ix##
+ if ((d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) ||
+ // parse JUNK
+ (d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K') ||
+ (d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')) {
avio_skip(pb, size);
goto start_sync;
}
- //parse stray LIST
- if(d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T'){
+ // parse stray LIST
+ if (d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T') {
avio_skip(pb, 4);
goto start_sync;
}
- n= get_stream_idx(d);
+ n = avi->dv_demux ? 0 : get_stream_idx(d);
- if(!((i-avi->last_pkt_pos)&1) && get_stream_idx(d+1) < s->nb_streams)
+ if (!((i - avi->last_pkt_pos) & 1) &&
+ get_stream_idx(d + 1) < s->nb_streams)
continue;
- //detect ##ix chunk and skip
- if(d[2] == 'i' && d[3] == 'x' && n < s->nb_streams){
+ // detect ##ix chunk and skip
+ if (d[2] == 'i' && d[3] == 'x' && n < s->nb_streams) {
avio_skip(pb, size);
goto start_sync;
}
- //parse ##dc/##wb
- if(n < s->nb_streams){
+ // parse ##dc/##wb
+ if (n < s->nb_streams) {
AVStream *st;
AVIStream *ast;
- st = s->streams[n];
+ st = s->streams[n];
ast = st->priv_data;
if (!ast) {
@@ -985,67 +1063,74 @@ start_sync:
continue;
}
- if(s->nb_streams>=2){
- AVStream *st1 = s->streams[1];
- AVIStream *ast1= st1->priv_data;
- //workaround for broken small-file-bug402.avi
- if( d[2] == 'w' && d[3] == 'b'
- && n==0
+ if (s->nb_streams >= 2) {
+ AVStream *st1 = s->streams[1];
+ AVIStream *ast1 = st1->priv_data;
+ // workaround for broken small-file-bug402.avi
+ if ( d[2] == 'w' && d[3] == 'b'
+ && n == 0
&& st ->codec->codec_type == AVMEDIA_TYPE_VIDEO
&& st1->codec->codec_type == AVMEDIA_TYPE_AUDIO
&& ast->prefix == 'd'*256+'c'
&& (d[2]*256+d[3] == ast1->prefix || !ast1->prefix_count)
- ){
- n=1;
- st = st1;
+ ) {
+ n = 1;
+ st = st1;
ast = ast1;
- av_log(s, AV_LOG_WARNING, "Invalid stream + prefix combination, assuming audio.\n");
+ av_log(s, AV_LOG_WARNING,
+ "Invalid stream + prefix combination, assuming audio.\n");
}
}
-
- if( (st->discard >= AVDISCARD_DEFAULT && size==0)
- /*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & AV_PKT_FLAG_KEY))*/ //FIXME needs a little reordering
- || st->discard >= AVDISCARD_ALL){
+ if (!avi->dv_demux &&
+ ((st->discard >= AVDISCARD_DEFAULT && size == 0) /* ||
+ // FIXME: needs a little reordering
+ (st->discard >= AVDISCARD_NONKEY &&
+ !(pkt->flags & AV_PKT_FLAG_KEY)) */
+ || st->discard >= AVDISCARD_ALL)) {
if (!exit_early) {
ast->frame_offset += get_duration(ast, size);
+ avio_skip(pb, size);
+ goto start_sync;
}
- avio_skip(pb, size);
- goto start_sync;
}
- if (d[2] == 'p' && d[3] == 'c' && size<=4*256+4) {
- int k = avio_r8(pb);
+ if (d[2] == 'p' && d[3] == 'c' && size <= 4 * 256 + 4) {
+ int k = avio_r8(pb);
int last = (k + avio_r8(pb) - 1) & 0xFF;
- avio_rl16(pb); //flags
+ avio_rl16(pb); // flags
+ // b + (g << 8) + (r << 16);
for (; k <= last; k++)
- ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8;// b + (g << 8) + (r << 16);
- ast->has_pal= 1;
- goto start_sync;
- } else if( ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) ||
- d[2]*256+d[3] == ast->prefix /*||
- (d[2] == 'd' && d[3] == 'c') ||
- (d[2] == 'w' && d[3] == 'b')*/) {
+ ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8;
+ ast->has_pal = 1;
+ goto start_sync;
+ } else if (((ast->prefix_count < 5 || sync + 9 > i) &&
+ d[2] < 128 && d[3] < 128) ||
+ d[2] * 256 + d[3] == ast->prefix /* ||
+ (d[2] == 'd' && d[3] == 'c') ||
+ (d[2] == 'w' && d[3] == 'b') */) {
if (exit_early)
return 0;
- if(d[2]*256+d[3] == ast->prefix)
+ if (d[2] * 256 + d[3] == ast->prefix)
ast->prefix_count++;
- else{
- ast->prefix= d[2]*256+d[3];
- ast->prefix_count= 0;
+ else {
+ ast->prefix = d[2] * 256 + d[3];
+ ast->prefix_count = 0;
}
- avi->stream_index= n;
- ast->packet_size= size + 8;
- ast->remaining= size;
+ avi->stream_index = n;
+ ast->packet_size = size + 8;
+ ast->remaining = size;
- if(size || !ast->sample_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){
- av_add_index_entry(st, pos, ast->frame_offset, size, 0, AVINDEX_KEYFRAME);
+ if (size || !ast->sample_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) {
+ av_add_index_entry(st, pos, ast->frame_offset, size,
+ 0, AVINDEX_KEYFRAME);
}
}
return 0;
@@ -1053,7 +1138,7 @@ start_sync:
}
}
- if(pb->error)
+ if (pb->error)
return pb->error;
return AVERROR_EOF;
}
@@ -1064,106 +1149,117 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
int err;
#if FF_API_DESTRUCT_PACKET
- void* dstr;
+ void *dstr;
#endif
if (CONFIG_DV_DEMUXER && avi->dv_demux) {
int size = avpriv_dv_get_packet(avi->dv_demux, pkt);
if (size >= 0)
return size;
+ else
+ goto resync;
}
- if(avi->non_interleaved){
+ if (avi->non_interleaved) {
int best_stream_index = 0;
- AVStream *best_st= NULL;
+ AVStream *best_st = NULL;
AVIStream *best_ast;
- int64_t best_ts= INT64_MAX;
+ int64_t best_ts = INT64_MAX;
int i;
- for(i=0; i<s->nb_streams; i++){
- AVStream *st = s->streams[i];
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
- int64_t ts= ast->frame_offset;
+ int64_t ts = ast->frame_offset;
int64_t last_ts;
- if(!st->nb_index_entries)
+ if (!st->nb_index_entries)
continue;
last_ts = st->index_entries[st->nb_index_entries - 1].timestamp;
- if(!ast->remaining && ts > last_ts)
+ if (!ast->remaining && ts > last_ts)
continue;
- ts = av_rescale_q(ts, st->time_base, (AVRational){FFMAX(1, ast->sample_size), AV_TIME_BASE});
+ ts = av_rescale_q(ts, st->time_base,
+ (AVRational) { FFMAX(1, ast->sample_size),
+ AV_TIME_BASE });
av_dlog(s, "%"PRId64" %d/%d %"PRId64"\n", ts,
st->time_base.num, st->time_base.den, ast->frame_offset);
- if(ts < best_ts){
- best_ts= ts;
- best_st= st;
- best_stream_index= i;
+ if (ts < best_ts) {
+ best_ts = ts;
+ best_st = st;
+ best_stream_index = i;
}
}
- if(!best_st)
+ if (!best_st)
return AVERROR_EOF;
best_ast = best_st->priv_data;
- best_ts = best_ast->frame_offset;
- if(best_ast->remaining)
- i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
- else{
- i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY);
- if(i>=0)
- best_ast->frame_offset= best_st->index_entries[i].timestamp;
+ best_ts = best_ast->frame_offset;
+ if (best_ast->remaining) {
+ i = av_index_search_timestamp(best_st,
+ best_ts,
+ AVSEEK_FLAG_ANY |
+ AVSEEK_FLAG_BACKWARD);
+ } else {
+ i = av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY);
+ if (i >= 0)
+ best_ast->frame_offset = best_st->index_entries[i].timestamp;
}
- if(i>=0){
- int64_t pos= best_st->index_entries[i].pos;
+ if (i >= 0) {
+ int64_t pos = best_st->index_entries[i].pos;
pos += best_ast->packet_size - best_ast->remaining;
- if(avio_seek(s->pb, pos + 8, SEEK_SET) < 0)
+ if (avio_seek(s->pb, pos + 8, SEEK_SET) < 0)
return AVERROR_EOF;
av_assert0(best_ast->remaining <= best_ast->packet_size);
- avi->stream_index= best_stream_index;
- if(!best_ast->remaining)
- best_ast->packet_size=
- best_ast->remaining= best_st->index_entries[i].size;
+ avi->stream_index = best_stream_index;
+ if (!best_ast->remaining)
+ best_ast->packet_size =
+ best_ast->remaining = best_st->index_entries[i].size;
}
else
return AVERROR_EOF;
}
resync:
- if(avi->stream_index >= 0){
- AVStream *st= s->streams[ avi->stream_index ];
- AVIStream *ast= st->priv_data;
+ if (avi->stream_index >= 0) {
+ AVStream *st = s->streams[avi->stream_index];
+ AVIStream *ast = st->priv_data;
int size, err;
- if(get_subtitle_pkt(s, st, pkt))
+ if (get_subtitle_pkt(s, st, pkt))
return 0;
- if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM
- size= INT_MAX;
- else if(ast->sample_size < 32)
+ // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM
+ if (ast->sample_size <= 1)
+ size = INT_MAX;
+ else if (ast->sample_size < 32)
// arbitrary multiplier to avoid tiny packets for raw PCM data
- size= 1024*ast->sample_size;
+ size = 1024 * ast->sample_size;
else
- size= ast->sample_size;
+ size = ast->sample_size;
- if(size > ast->remaining)
- size= ast->remaining;
- avi->last_pkt_pos= avio_tell(pb);
- err= av_get_packet(pb, pkt, size);
- if(err<0)
+ if (size > ast->remaining)
+ size = ast->remaining;
+ avi->last_pkt_pos = avio_tell(pb);
+ err = av_get_packet(pb, pkt, size);
+ if (err < 0)
return err;
size = err;
- if(ast->has_pal && pkt->size<(unsigned)INT_MAX/2){
+ if (ast->has_pal && pkt->size < (unsigned)INT_MAX / 2) {
uint8_t *pal;
- pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
- if(!pal){
- av_log(s, AV_LOG_ERROR, "Failed to allocate data for palette\n");
- }else{
+ pal = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_PALETTE,
+ AVPALETTE_SIZE);
+ if (!pal) {
+ av_log(s, AV_LOG_ERROR,
+ "Failed to allocate data for palette\n");
+ } else {
memcpy(pal, ast->pal, AVPALETTE_SIZE);
ast->has_pal = 0;
}
@@ -1172,50 +1268,61 @@ resync:
if (CONFIG_DV_DEMUXER && avi->dv_demux) {
AVBufferRef *avbuf = pkt->buf;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
dstr = pkt->destruct;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
size = avpriv_dv_produce_packet(avi->dv_demux, pkt,
- pkt->data, pkt->size, pkt->pos);
+ pkt->data, pkt->size, pkt->pos);
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = dstr;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
- pkt->buf = avbuf;
+ pkt->buf = avbuf;
pkt->flags |= AV_PKT_FLAG_KEY;
if (size < 0)
av_free_packet(pkt);
- } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE
- && !st->codec->codec_tag && read_gab2_sub(st, pkt)) {
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
+ !st->codec->codec_tag && read_gab2_sub(st, pkt)) {
ast->frame_offset++;
avi->stream_index = -1;
- ast->remaining = 0;
+ ast->remaining = 0;
goto resync;
} else {
/* XXX: How to handle B-frames in AVI? */
pkt->dts = ast->frame_offset;
// pkt->dts += ast->start;
- if(ast->sample_size)
+ if (ast->sample_size)
pkt->dts /= ast->sample_size;
- av_dlog(s, "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d base:%d st:%d size:%d\n",
- pkt->dts, ast->frame_offset, ast->scale, ast->rate,
- ast->sample_size, AV_TIME_BASE, avi->stream_index, size);
+ av_dlog(s,
+ "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d "
+ "base:%d st:%d size:%d\n",
+ pkt->dts,
+ ast->frame_offset,
+ ast->scale,
+ ast->rate,
+ ast->sample_size,
+ AV_TIME_BASE,
+ avi->stream_index,
+ size);
pkt->stream_index = avi->stream_index;
- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->index_entries) {
AVIndexEntry *e;
int index;
- av_assert0(st->index_entries);
- index= av_index_search_timestamp(st, ast->frame_offset, 0);
- e= &st->index_entries[index];
+ index = av_index_search_timestamp(st, ast->frame_offset, 0);
+ e = &st->index_entries[index];
- if(index >= 0 && e->timestamp == ast->frame_offset){
- if (index == st->nb_index_entries-1){
+ if (index >= 0 && e->timestamp == ast->frame_offset) {
+ if (index == st->nb_index_entries-1) {
int key=1;
int i;
uint32_t state=-1;
- for(i=0; i<FFMIN(size,256); i++){
- if(st->codec->codec_id == AV_CODEC_ID_MPEG4){
- if(state == 0x1B6){
+ for (i=0; i<FFMIN(size,256); i++) {
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4) {
+ if (state == 0x1B6) {
key= !(pkt->data[i]&0xC0);
break;
}
@@ -1223,7 +1330,7 @@ resync:
break;
state= (state<<8) + pkt->data[i];
}
- if(!key)
+ if (!key)
e->flags &= ~AVINDEX_KEYFRAME;
}
if (e->flags & AVINDEX_KEYFRAME)
@@ -1235,24 +1342,24 @@ resync:
ast->frame_offset += get_duration(ast, pkt->size);
}
ast->remaining -= err;
- if(!ast->remaining){
- avi->stream_index= -1;
- ast->packet_size= 0;
+ if (!ast->remaining) {
+ avi->stream_index = -1;
+ ast->packet_size = 0;
}
- if(!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos){
+ if (!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos) {
av_free_packet(pkt);
goto resync;
}
ast->seek_pos= 0;
- if(!avi->non_interleaved && st->nb_index_entries>1 && avi->index_loaded>1){
+ if (!avi->non_interleaved && st->nb_index_entries>1 && avi->index_loaded>1) {
int64_t dts= av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q);
- if(avi->dts_max - dts > 2*AV_TIME_BASE){
+ if (avi->dts_max - dts > 2*AV_TIME_BASE) {
avi->non_interleaved= 1;
av_log(s, AV_LOG_INFO, "Switching to NI mode, due to poor interleaving\n");
- }else if(avi->dts_max < dts)
+ }else if (avi->dts_max < dts)
avi->dts_max = dts;
}
@@ -1265,7 +1372,7 @@ resync:
}
/* XXX: We make the implicit supposition that the positions are sorted
- for each stream. */
+ * for each stream. */
static int avi_read_idx1(AVFormatContext *s, int size)
{
AVIContext *avi = s->priv_data;
@@ -1274,8 +1381,8 @@ static int avi_read_idx1(AVFormatContext *s, int size)
AVStream *st;
AVIStream *ast;
unsigned int index, tag, flags, pos, len, first_packet = 1;
- unsigned last_pos= -1;
- unsigned last_idx= -1;
+ unsigned last_pos = -1;
+ unsigned last_idx = -1;
int64_t idx1_pos, first_packet_pos = 0, data_offset = 0;
int anykey = 0;
@@ -1284,39 +1391,38 @@ static int avi_read_idx1(AVFormatContext *s, int size)
return AVERROR_INVALIDDATA;
idx1_pos = avio_tell(pb);
- avio_seek(pb, avi->movi_list+4, SEEK_SET);
- if (avi_sync(s, 1) == 0) {
+ avio_seek(pb, avi->movi_list + 4, SEEK_SET);
+ if (avi_sync(s, 1) == 0)
first_packet_pos = avio_tell(pb) - 8;
- }
avi->stream_index = -1;
avio_seek(pb, idx1_pos, SEEK_SET);
- if (s->nb_streams == 1 && s->streams[0]->codec->codec_tag == AV_RL32("MMES")){
+ if (s->nb_streams == 1 && s->streams[0]->codec->codec_tag == AV_RL32("MMES")) {
first_packet_pos = 0;
data_offset = avi->movi_list;
}
/* Read the entries and sort them in each stream component. */
- for(i = 0; i < nb_index_entries; i++) {
- if(url_feof(pb))
+ for (i = 0; i < nb_index_entries; i++) {
+ if (url_feof(pb))
return -1;
- tag = avio_rl32(pb);
+ tag = avio_rl32(pb);
flags = avio_rl32(pb);
- pos = avio_rl32(pb);
- len = avio_rl32(pb);
+ pos = avio_rl32(pb);
+ len = avio_rl32(pb);
av_dlog(s, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/",
i, tag, flags, pos, len);
- index = ((tag & 0xff) - '0') * 10;
- index += ((tag >> 8) & 0xff) - '0';
+ index = ((tag & 0xff) - '0') * 10;
+ index += (tag >> 8 & 0xff) - '0';
if (index >= s->nb_streams)
continue;
- st = s->streams[index];
+ st = s->streams[index];
ast = st->priv_data;
- if(first_packet && first_packet_pos && len) {
- data_offset = first_packet_pos - pos;
+ if (first_packet && first_packet_pos) {
+ data_offset = first_packet_pos - pos;
first_packet = 0;
}
pos += data_offset;
@@ -1325,15 +1431,16 @@ static int avi_read_idx1(AVFormatContext *s, int size)
// even if we have only a single stream, we should
// switch to non-interleaved to get correct timestamps
- if(last_pos == pos)
- avi->non_interleaved= 1;
- if(last_idx != pos && len) {
- av_add_index_entry(st, pos, ast->cum_len, len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
+ if (last_pos == pos)
+ avi->non_interleaved = 1;
+ if (last_idx != pos && len) {
+ av_add_index_entry(st, pos, ast->cum_len, len, 0,
+ (flags & AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
last_idx= pos;
}
ast->cum_len += get_duration(ast, len);
- last_pos= pos;
- anykey |= flags&AVIIF_INDEX;
+ last_pos = pos;
+ anykey |= flags&AVIIF_INDEX;
}
if (!anykey) {
for (index = 0; index < s->nb_streams; index++) {
@@ -1345,56 +1452,60 @@ static int avi_read_idx1(AVFormatContext *s, int size)
return 0;
}
-static int guess_ni_flag(AVFormatContext *s){
+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);
+ 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++){
+ for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
- int n= st->nb_index_entries;
+ int n = st->nb_index_entries;
unsigned int size;
- if(n <= 0)
+ if (n <= 0)
continue;
- if(n >= 2){
- int64_t pos= st->index_entries[0].pos;
+ if (n >= 2) {
+ int64_t pos = st->index_entries[0].pos;
avio_seek(s->pb, pos + 4, SEEK_SET);
- size= avio_rl32(s->pb);
- if(pos + size > st->index_entries[1].pos)
- last_start= INT64_MAX;
+ size = avio_rl32(s->pb);
+ if (pos + size > st->index_entries[1].pos)
+ last_start = INT64_MAX;
}
- if(st->index_entries[0].pos > last_start)
- last_start= st->index_entries[0].pos;
- if(st->index_entries[n-1].pos < first_end)
- first_end= st->index_entries[n-1].pos;
+ if (st->index_entries[0].pos > last_start)
+ last_start = st->index_entries[0].pos;
+ if (st->index_entries[n - 1].pos < first_end)
+ first_end = st->index_entries[n - 1].pos;
}
avio_seek(s->pb, oldpos, SEEK_SET);
if (last_start > first_end)
return 1;
- idx= av_mallocz(sizeof(*idx) * s->nb_streams);
+ 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, st->time_base, AV_TIME_BASE_Q));
+ 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, st->time_base, AV_TIME_BASE_Q));
+ 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) {
+ if (max_dts - min_dts > 2*AV_TIME_BASE) {
av_free(idx);
return 1;
}
@@ -1408,15 +1519,15 @@ static int avi_load_index(AVFormatContext *s)
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
uint32_t tag, size;
- int64_t pos= avio_tell(pb);
+ int64_t pos = avio_tell(pb);
int64_t next;
- int ret = -1;
+ int ret = -1;
if (avio_seek(pb, avi->movi_end, SEEK_SET) < 0)
goto the_end; // maybe truncated file
av_dlog(s, "movi_end=0x%"PRIx64"\n", avi->movi_end);
- for(;;) {
- tag = avio_rl32(pb);
+ for (;;) {
+ tag = avio_rl32(pb);
size = avio_rl32(pb);
if (url_feof(pb))
break;
@@ -1433,18 +1544,19 @@ static int avi_load_index(AVFormatContext *s)
avi_read_idx1(s, size) >= 0) {
avi->index_loaded=2;
ret = 0;
- }else if(tag == MKTAG('L', 'I', 'S', 'T')) {
+ }else if (tag == MKTAG('L', 'I', 'S', 'T')) {
uint32_t tag1 = avio_rl32(pb);
if (tag1 == MKTAG('I', 'N', 'F', 'O'))
ff_read_riff_info(s, size - 4);
- }else if(!ret)
+ }else if (!ret)
break;
if (avio_seek(pb, next, SEEK_SET) < 0)
break; // something is wrong here
}
- the_end:
+
+the_end:
avio_seek(pb, pos, SEEK_SET);
return ret;
}
@@ -1452,14 +1564,15 @@ static int avi_load_index(AVFormatContext *s)
static void seek_subtitle(AVStream *st, AVStream *st2, int64_t timestamp)
{
AVIStream *ast2 = st2->priv_data;
- int64_t ts2 = av_rescale_q(timestamp, st->time_base, st2->time_base);
+ int64_t ts2 = av_rescale_q(timestamp, st->time_base, st2->time_base);
av_free_packet(&ast2->sub_pkt);
if (avformat_seek_file(ast2->sub_ctx, 0, INT64_MIN, ts2, ts2, 0) >= 0 ||
avformat_seek_file(ast2->sub_ctx, 0, ts2, ts2, INT64_MAX, 0) >= 0)
ff_read_packet(ast2->sub_ctx, &ast2->sub_pkt);
}
-static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+static int avi_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
{
AVIContext *avi = s->priv_data;
AVStream *st;
@@ -1467,17 +1580,25 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
int64_t pos, pos_min;
AVIStream *ast;
+ /* Does not matter which stream is requested dv in avi has the
+ * stream information in the first video stream.
+ */
+ if (avi->dv_demux)
+ stream_index = 0;
+
if (!avi->index_loaded) {
/* we only load the index on demand */
avi_load_index(s);
avi->index_loaded |= 1;
}
- av_assert0(stream_index>= 0);
-
- st = s->streams[stream_index];
- ast= st->priv_data;
- index= av_index_search_timestamp(st, timestamp * FFMAX(ast->sample_size, 1), flags);
- if (index<0) {
+ av_assert0(stream_index >= 0);
+
+ st = s->streams[stream_index];
+ ast = st->priv_data;
+ index = av_index_search_timestamp(st,
+ timestamp * FFMAX(ast->sample_size, 1),
+ flags);
+ if (index < 0) {
if (st->nb_index_entries > 0)
av_log(s, AV_LOG_DEBUG, "Failed to find timestamp %"PRId64 " in index %"PRId64 " .. %"PRId64 "\n",
timestamp * FFMAX(ast->sample_size, 1),
@@ -1487,7 +1608,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
}
/* find the position */
- pos = st->index_entries[index].pos;
+ pos = st->index_entries[index].pos;
timestamp = st->index_entries[index].timestamp / FFMAX(ast->sample_size, 1);
av_dlog(s, "XX %"PRId64" %d %"PRId64"\n",
@@ -1497,26 +1618,25 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
/* One and only one real stream for DV in AVI, and it has video */
/* offsets. Calling with other stream indexes should have failed */
/* the av_index_search_timestamp call above. */
- av_assert0(stream_index == 0);
- if(avio_seek(s->pb, pos, SEEK_SET) < 0)
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return -1;
/* Feed the DV video stream version of the timestamp to the */
/* DV demux so it can synthesize correct timestamps. */
ff_dv_offset_reset(avi->dv_demux, timestamp);
- avi->stream_index= -1;
+ avi->stream_index = -1;
return 0;
}
- pos_min= pos;
- for(i = 0; i < s->nb_streams; i++) {
- AVStream *st2 = s->streams[i];
+ pos_min = pos;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st2 = s->streams[i];
AVIStream *ast2 = st2->priv_data;
- ast2->packet_size=
- ast2->remaining= 0;
+ ast2->packet_size =
+ ast2->remaining = 0;
if (ast2->sub_ctx) {
seek_subtitle(st, st2, timestamp);
@@ -1527,17 +1647,22 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
continue;
// av_assert1(st2->codec->block_align);
- av_assert0((int64_t)st2->time_base.num*ast2->rate == (int64_t)st2->time_base.den*ast2->scale);
- index = av_index_search_timestamp(
- st2,
- av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1),
- flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0));
- if(index<0)
- index=0;
- ast2->seek_pos= st2->index_entries[index].pos;
- pos_min= FFMIN(pos_min,ast2->seek_pos);
+ av_assert0((int64_t)st2->time_base.num * ast2->rate ==
+ (int64_t)st2->time_base.den * ast2->scale);
+ index = av_index_search_timestamp(st2,
+ av_rescale_q(timestamp,
+ st->time_base,
+ st2->time_base) *
+ FFMAX(ast2->sample_size, 1),
+ flags |
+ AVSEEK_FLAG_BACKWARD |
+ (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0));
+ if (index < 0)
+ index = 0;
+ ast2->seek_pos = st2->index_entries[index].pos;
+ pos_min = FFMIN(pos_min,ast2->seek_pos);
}
- for(i = 0; i < s->nb_streams; i++) {
+ for (i = 0; i < s->nb_streams; i++) {
AVStream *st2 = s->streams[i];
AVIStream *ast2 = st2->priv_data;
@@ -1548,9 +1673,9 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
st2,
av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1),
flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0));
- if(index<0)
- index=0;
- while(!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min)
+ if (index < 0)
+ index = 0;
+ while (!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min)
index--;
ast2->frame_offset = st2->index_entries[index].timestamp;
}
@@ -1560,8 +1685,8 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
av_log(s, AV_LOG_ERROR, "Seek failed\n");
return -1;
}
- avi->stream_index= -1;
- avi->dts_max= INT_MIN;
+ avi->stream_index = -1;
+ avi->dts_max = INT_MIN;
return 0;
}
@@ -1570,8 +1695,8 @@ static int avi_read_close(AVFormatContext *s)
int i;
AVIContext *avi = s->priv_data;
- for(i=0;i<s->nb_streams;i++) {
- AVStream *st = s->streams[i];
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
if (ast) {
if (ast->sub_ctx) {
@@ -1593,9 +1718,9 @@ static int avi_probe(AVProbeData *p)
int i;
/* check file header */
- for(i=0; avi_headers[i][0]; i++)
- if(!memcmp(p->buf , avi_headers[i] , 4) &&
- !memcmp(p->buf+8, avi_headers[i]+4, 4))
+ for (i = 0; avi_headers[i][0]; i++)
+ if (!memcmp(p->buf, avi_headers[i], 4) &&
+ !memcmp(p->buf + 8, avi_headers[i] + 4, 4))
return AVPROBE_SCORE_MAX;
return 0;
diff --git a/ffmpeg/libavformat/avienc.c b/ffmpeg/libavformat/avienc.c
index 15f0794..95e4e7e 100644
--- a/ffmpeg/libavformat/avienc.c
+++ b/ffmpeg/libavformat/avienc.c
@@ -26,6 +26,8 @@
#include "avi.h"
#include "avio_internal.h"
#include "riff.h"
+#include "libavformat/avlanguage.h"
+#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/avassert.h"
@@ -57,7 +59,7 @@ typedef struct {
typedef struct {
int64_t frames_hdr_strm;
- int audio_strm_length;
+ int64_t audio_strm_length;
int packet_count;
int entry;
@@ -291,7 +293,7 @@ static int avi_write_header(AVFormatContext *s)
// 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);
+ ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0);
break;
case AVMEDIA_TYPE_AUDIO:
if ((ret = ff_put_wav_header(pb, stream)) < 0) {
@@ -309,6 +311,16 @@ static int avi_write_header(AVFormatContext *s)
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) {
@@ -523,7 +535,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
int size= pkt->size;
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){
+ 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){
@@ -567,8 +579,11 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
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)
+ if (!idx->cluster) {
+ idx->ents_allocated = 0;
+ idx->entry = 0;
return AVERROR(ENOMEM);
+ }
idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry));
if (!idx->cluster[cl])
return AVERROR(ENOMEM);
@@ -587,7 +602,6 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
if (size & 1)
avio_w8(pb, 0);
- avio_flush(pb);
return 0;
}
@@ -637,7 +651,7 @@ 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_free(avist->indexes.cluster[j]);
+ av_freep(&avist->indexes.cluster[j]);
av_freep(&avist->indexes.cluster);
avist->indexes.ents_allocated = avist->indexes.entry = 0;
}
@@ -659,5 +673,4 @@ AVOutputFormat ff_avi_muxer = {
.codec_tag = (const AVCodecTag* const []){
ff_codec_bmp_tags, ff_codec_wav_tags, 0
},
- .flags = AVFMT_VARIABLE_FPS,
};
diff --git a/ffmpeg/libavformat/avio.c b/ffmpeg/libavformat/avio.c
index f6af0cb..225d982 100644
--- a/ffmpeg/libavformat/avio.c
+++ b/ffmpeg/libavformat/avio.c
@@ -42,8 +42,10 @@ URLProtocol *ffurl_protocol_next(URLProtocol *prev)
static const char *urlcontext_to_name(void *ptr)
{
URLContext *h = (URLContext *)ptr;
- if(h->prot) return h->prot->name;
- else return "NULL";
+ if (h->prot)
+ return h->prot->name;
+ else
+ return "NULL";
}
static void *urlcontext_child_next(void *obj, void *prev)
@@ -68,49 +70,44 @@ static const AVClass *urlcontext_child_class_next(const AVClass *prev)
if (p->priv_data_class)
return p->priv_data_class;
return NULL;
-
}
-static const AVOption options[] = {{NULL}};
+static const AVOption options[] = { { NULL } };
const AVClass ffurl_context_class = {
- .class_name = "URLContext",
- .item_name = urlcontext_to_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
- .child_next = urlcontext_child_next,
+ .class_name = "URLContext",
+ .item_name = urlcontext_to_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .child_next = urlcontext_child_next,
.child_class_next = urlcontext_child_class_next,
};
/*@}*/
-
const char *avio_enum_protocols(void **opaque, int output)
{
URLProtocol *p;
*opaque = ffurl_protocol_next(*opaque);
- if (!(p = *opaque)) return NULL;
+ if (!(p = *opaque))
+ return NULL;
if ((output && p->url_write) || (!output && p->url_read))
return p->name;
return avio_enum_protocols(opaque, output);
}
-int ffurl_register_protocol(URLProtocol *protocol, int size)
+int ffurl_register_protocol(URLProtocol *protocol)
{
URLProtocol **p;
- if (size < sizeof(URLProtocol)) {
- URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
- memcpy(temp, protocol, size);
- protocol = temp;
- }
p = &first_protocol;
- while (*p != NULL) p = &(*p)->next;
- *p = protocol;
+ while (*p != NULL)
+ p = &(*p)->next;
+ *p = protocol;
protocol->next = NULL;
return 0;
}
-static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
- const char *filename, int flags,
- const AVIOInterruptCB *int_cb)
+static int url_alloc_for_protocol(URLContext **puc, struct URLProtocol *up,
+ const char *filename, int flags,
+ const AVIOInterruptCB *int_cb)
{
URLContext *uc;
int err;
@@ -135,18 +132,22 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
goto fail;
}
uc->av_class = &ffurl_context_class;
- uc->filename = (char *) &uc[1];
+ uc->filename = (char *)&uc[1];
strcpy(uc->filename, filename);
- uc->prot = up;
- uc->flags = flags;
- uc->is_streamed = 0; /* default = not streamed */
+ uc->prot = up;
+ uc->flags = flags;
+ uc->is_streamed = 0; /* default = not streamed */
uc->max_packet_size = 0; /* default: stream file */
if (up->priv_data_size) {
uc->priv_data = av_mallocz(up->priv_data_size);
+ if (!uc->priv_data) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
if (up->priv_data_class) {
int proto_len= strlen(up->name);
char *start = strchr(uc->filename, ',');
- *(const AVClass**)uc->priv_data = up->priv_data_class;
+ *(const AVClass **)uc->priv_data = up->priv_data_class;
av_opt_set_defaults(uc->priv_data);
if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
int ret= 0;
@@ -178,8 +179,11 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
*puc = uc;
return 0;
- fail:
+fail:
*puc = NULL;
+ if (uc)
+ av_freep(&uc->priv_data);
+ av_freep(&uc);
#if CONFIG_NETWORK
if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
ff_network_close();
@@ -187,19 +191,22 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
return err;
}
-int ffurl_connect(URLContext* uc, AVDictionary **options)
+int ffurl_connect(URLContext *uc, AVDictionary **options)
{
int err =
- uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
+ uc->prot->url_open2 ? uc->prot->url_open2(uc,
+ uc->filename,
+ uc->flags,
+ options) :
uc->prot->url_open(uc, uc->filename, uc->flags);
if (err)
return err;
uc->is_connected = 1;
- //We must be careful here as ffurl_seek() could be slow, for example for http
- if( (uc->flags & AVIO_FLAG_WRITE)
- || !strcmp(uc->prot->name, "file"))
- if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
- uc->is_streamed= 1;
+ /* We must be careful here as ffurl_seek() could be slow,
+ * for example for http */
+ if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file"))
+ if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
+ uc->is_streamed = 1;
return 0;
}
@@ -225,7 +232,8 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
is_dos_path(filename))
strcpy(proto_str, "file");
else
- av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
+ av_strlcpy(proto_str, filename,
+ FFMIN(proto_len + 1, sizeof(proto_str)));
if ((ptr = strchr(proto_str, ',')))
*ptr = '\0';
@@ -235,12 +243,14 @@ 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);
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
!strcmp(proto_nested, up->name))
- return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
}
*puc = NULL;
+ if (!strcmp("https", proto_str))
+ av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n");
return AVERROR_PROTOCOL_NOT_FOUND;
}
@@ -262,8 +272,11 @@ fail:
return ret;
}
-static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
- int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
+static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
+ int size, int size_min,
+ int (*transfer_func)(URLContext *h,
+ uint8_t *buf,
+ int size))
{
int ret, len;
int fast_retries = 5;
@@ -271,7 +284,9 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int
len = 0;
while (len < size_min) {
- ret = transfer_func(h, buf+len, size-len);
+ if (ff_check_interrupt(&h->interrupt_callback))
+ return AVERROR_EXIT;
+ ret = transfer_func(h, buf + len, size - len);
if (ret == AVERROR(EINTR))
continue;
if (h->flags & AVIO_FLAG_NONBLOCK)
@@ -290,12 +305,10 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int
av_usleep(1000);
}
} else if (ret < 1)
- return ret < 0 ? ret : len;
+ return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
if (ret)
- fast_retries = FFMAX(fast_retries, 2);
+ fast_retries = FFMAX(fast_retries, 2);
len += ret;
- if (len < size && ff_check_interrupt(&h->interrupt_callback))
- return AVERROR_EXIT;
}
return len;
}
@@ -339,7 +352,8 @@ int ffurl_closep(URLContext **hh)
{
URLContext *h= *hh;
int ret = 0;
- if (!h) return 0; /* can happen when ffurl_open fails */
+ if (!h)
+ return 0; /* can happen when ffurl_open fails */
if (h->is_connected && h->prot->url_close)
ret = h->prot->url_close(h);
@@ -385,8 +399,8 @@ int64_t ffurl_size(URLContext *h)
{
int64_t pos, size;
- size= ffurl_seek(h, 0, AVSEEK_SIZE);
- if(size<0){
+ size = ffurl_seek(h, 0, AVSEEK_SIZE);
+ if (size < 0) {
pos = ffurl_seek(h, 0, SEEK_CUR);
if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
return size;
diff --git a/ffmpeg/libavformat/avio.h b/ffmpeg/libavformat/avio.h
index 8de28bf..4f4ac3c 100644
--- a/ffmpeg/libavformat/avio.h
+++ b/ffmpeg/libavformat/avio.h
@@ -120,26 +120,32 @@ typedef struct AVIOContext {
* max filesize, used to limit allocations
* This field is internal to libavformat and access from outside is not allowed.
*/
- int64_t maxsize;
+ int64_t maxsize;
- /**
- * avio_read and avio_write should if possible be satisfied directly
- * instead of going through a buffer, and avio_seek will always
- * call the underlying seek function directly.
- */
- int direct;
+ /**
+ * avio_read and avio_write should if possible be satisfied directly
+ * instead of going through a buffer, and avio_seek will always
+ * call the underlying seek function directly.
+ */
+ int direct;
/**
* Bytes read statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
- int64_t bytes_read;
+ int64_t bytes_read;
/**
* seek statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
- int seek_count;
+ int seek_count;
+
+ /**
+ * writeout statistic
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int writeout_count;
} AVIOContext;
/* unbuffered I/O */
@@ -362,7 +368,7 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
* In case of failure the pointed to value is set to NULL.
* @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
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open(AVIOContext **s, const char *url, int flags);
@@ -381,7 +387,7 @@ int avio_open(AVIOContext **s, const char *url, int flags);
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open2(AVIOContext **s, const char *url, int flags,
diff --git a/ffmpeg/libavformat/avio_internal.h b/ffmpeg/libavformat/avio_internal.h
index cf36764..8441d49 100644
--- a/ffmpeg/libavformat/avio_internal.h
+++ b/ffmpeg/libavformat/avio_internal.h
@@ -38,6 +38,23 @@ int ffio_init_context(AVIOContext *s,
/**
+ * Read size bytes from AVIOContext, returning a pointer.
+ * Note that the data pointed at by the returned pointer is only
+ * valid until the next call that references the same IO context.
+ * @param s IO context
+ * @param buf pointer to buffer into which to assemble the requested
+ * data if it is not available in contiguous addresses in the
+ * underlying buffer
+ * @param size number of bytes requested
+ * @param data address at which to store pointer: this will be a
+ * a direct pointer into the underlying buffer if the requested
+ * number of bytes are available at contiguous addresses, otherwise
+ * will be a copy of buf
+ * @return number of bytes read or AVERROR
+ */
+int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data);
+
+/**
* Read size bytes from AVIOContext into buf.
* This reads at most 1 packet. If that is not enough fewer bytes will be
* returned.
@@ -61,7 +78,7 @@ static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
* @param s The read-only AVIOContext to rewind
* @param buf The probe buffer containing the first buf_size bytes of the file
* @param buf_size The size of buf
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **buf, int buf_size);
@@ -71,6 +88,15 @@ uint64_t ffio_read_varlen(AVIOContext *bc);
/** @warning must be called before any I/O */
int ffio_set_buf_size(AVIOContext *s, int buf_size);
+/**
+ * Ensures that the requested seekback buffer size will be available
+ *
+ * Will ensure that when reading sequentially up to buf_size, seeking
+ * within the current pos and pos+buf_size is possible.
+ * Once the stream position moves outside this window this gurantee is lost.
+ */
+int ffio_ensure_seekback(AVIOContext *s, int buf_size);
+
int ffio_limit(AVIOContext *s, int size);
void ffio_init_checksum(AVIOContext *s,
@@ -99,9 +125,27 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size);
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffio_fdopen(AVIOContext **s, URLContext *h);
+/**
+ * Open a write-only fake memory stream. The written data is not stored
+ * anywhere - this is only used for measuring the amount of data
+ * written.
+ *
+ * @param s new IO context
+ * @return zero if no error.
+ */
+int ffio_open_null_buf(AVIOContext **s);
+
+/**
+ * Close a null buffer.
+ *
+ * @param s an IO context opened by ffio_open_null_buf
+ * @return the number of bytes written to the null buffer
+ */
+int ffio_close_null_buf(AVIOContext *s);
+
#endif /* AVFORMAT_AVIO_INTERNAL_H */
diff --git a/ffmpeg/libavformat/aviobuf.c b/ffmpeg/libavformat/aviobuf.c
index 7a73a17..eb5a6e5 100644
--- a/ffmpeg/libavformat/aviobuf.c
+++ b/ffmpeg/libavformat/aviobuf.c
@@ -92,7 +92,7 @@ int ffio_init_context(AVIOContext *s,
s->must_flush = 0;
s->eof_reached = 0;
s->error = 0;
- s->seekable = AVIO_SEEKABLE_NORMAL;
+ s->seekable = seek ? AVIO_SEEKABLE_NORMAL : 0;
s->max_packet_size = 0;
s->update_checksum = NULL;
@@ -131,6 +131,7 @@ static void writeout(AVIOContext *s, const uint8_t *data, int len)
s->error = ret;
}
}
+ s->writeout_count ++;
s->pos += len;
}
@@ -318,15 +319,22 @@ int avio_put_str16le(AVIOContext *s, const char *str)
{
const uint8_t *q = str;
int ret = 0;
+ int err = 0;
while (*q) {
uint32_t ch;
uint16_t tmp;
- GET_UTF8(ch, *q++, break;)
+ GET_UTF8(ch, *q++, goto invalid;)
PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;)
+ continue;
+invalid:
+ av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16le\n");
+ err = AVERROR(EINVAL);
}
avio_wl16(s, 0);
+ if (err)
+ return err;
ret += 2;
return ret;
}
@@ -391,12 +399,11 @@ void avio_wb24(AVIOContext *s, unsigned int val)
static void fill_buffer(AVIOContext *s)
{
- uint8_t *dst = !s->max_packet_size &&
- s->buf_end - s->buffer < s->buffer_size ?
- s->buf_end : s->buffer;
- int len = s->buffer_size - (dst - s->buffer);
int max_buffer_size = s->max_packet_size ?
s->max_packet_size : IO_BUFFER_SIZE;
+ uint8_t *dst = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ?
+ s->buf_end : s->buffer;
+ int len = s->buffer_size - (dst - s->buffer);
/* can't fill the buffer without read_packet, just set EOF if appropriate */
if (!s->read_packet && s->buf_ptr >= s->buf_end)
@@ -415,10 +422,13 @@ 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) {
- ffio_set_buf_size(s, max_buffer_size);
+ if (dst == s->buffer) {
+ ffio_set_buf_size(s, max_buffer_size);
- s->checksum_ptr = dst = s->buffer;
- len = s->buffer_size;
+ s->checksum_ptr = dst = s->buffer;
+ }
+ av_assert0(len >= max_buffer_size);
+ len = max_buffer_size;
}
if (s->read_packet)
@@ -522,6 +532,18 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
return size1 - size;
}
+int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data)
+{
+ if (s->buf_end - s->buf_ptr >= size && !s->write_flag) {
+ *data = s->buf_ptr;
+ s->buf_ptr += size;
+ return size;
+ } else {
+ *data = buf;
+ return avio_read(s, buf, size);
+ }
+}
+
int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size)
{
int len;
@@ -722,6 +744,31 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
return 0;
}
+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;
+
+ buf_size += s->buf_ptr - s->buffer + max_buffer_size;
+
+ if (buf_size < s->buffer_size || s->seekable)
+ return 0;
+ av_assert0(!s->write_flag);
+
+ buffer = av_malloc(buf_size);
+ if (!buffer)
+ return AVERROR(ENOMEM);
+
+ memcpy(buffer, s->buffer, s->buffer_size);
+ av_free(s->buffer);
+ s->buf_ptr = buffer + (s->buf_ptr - s->buffer);
+ s->buf_end = buffer + (s->buf_end - s->buffer);
+ s->buffer = buffer;
+ s->buffer_size = buf_size;
+ return 0;
+}
+
int ffio_set_buf_size(AVIOContext *s, int buf_size)
{
uint8_t *buffer;
@@ -827,7 +874,9 @@ int avio_close(AVIOContext *s)
avio_flush(s);
h = s->opaque;
av_freep(&s->buffer);
- if (!s->write_flag)
+ if (s->write_flag)
+ av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count);
+ else
av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
av_free(s);
return ffurl_close(h);
@@ -907,9 +956,12 @@ static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size)
}
if (new_allocated_size > d->allocated_size) {
- d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size);
- if(d->buffer == NULL)
- return AVERROR(ENOMEM);
+ int err;
+ if ((err = av_reallocp(&d->buffer, new_allocated_size)) < 0) {
+ d->allocated_size = 0;
+ d->size = 0;
+ return err;
+ }
d->allocated_size = new_allocated_size;
}
memcpy(d->buffer + d->pos, buf, buf_size);
@@ -984,11 +1036,17 @@ 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;
+ if (!s) {
+ *pbuffer = NULL;
+ return 0;
+ }
+ d = s->opaque;
+
/* don't attempt to pad fixed-size packet buffers */
if (!s->max_packet_size) {
avio_write(s, padbuf, sizeof(padbuf));
@@ -1003,3 +1061,36 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
av_free(s);
return size - padding;
}
+
+static int null_buf_write(void *opaque, uint8_t *buf, int buf_size)
+{
+ DynBuffer *d = opaque;
+
+ d->pos += buf_size;
+ if (d->pos > d->size)
+ d->size = d->pos;
+ return buf_size;
+}
+
+int ffio_open_null_buf(AVIOContext **s)
+{
+ int ret = url_open_dyn_buf_internal(s, 0);
+ if (ret >= 0) {
+ AVIOContext *pb = *s;
+ pb->write_packet = null_buf_write;
+ }
+ return ret;
+}
+
+int ffio_close_null_buf(AVIOContext *s)
+{
+ DynBuffer *d = s->opaque;
+ int size;
+
+ avio_flush(s);
+
+ size = d->size;
+ av_free(d);
+ av_free(s);
+ return size;
+}
diff --git a/ffmpeg/libavformat/avisynth.c b/ffmpeg/libavformat/avisynth.c
index d31031d..2f438d9 100644
--- a/ffmpeg/libavformat/avisynth.c
+++ b/ffmpeg/libavformat/avisynth.c
@@ -1,5 +1,5 @@
/*
- * Avi/AvxSynth support
+ * AviSynth/AvxSynth support
* Copyright (c) 2012 AvxSynth Team.
*
* This file is part of FFmpeg
@@ -18,72 +18,62 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/internal.h"
+#include "libavcodec/internal.h"
#include "avformat.h"
#include "internal.h"
-#include "libavcodec/internal.h"
-// Enable function pointer definitions for runtime loading.
+/* Enable function pointer definitions for runtime loading. */
#define AVSC_NO_DECLSPEC
-// Shut up ffmpeg error messages.
-// avisynth_c.h contains inline functions that call these functions.
-#undef malloc
-#undef free
-#undef printf
-
-// Platform-specific directives for AviSynth vs AvxSynth.
+/* Platform-specific directives for AviSynth vs AvxSynth. */
#ifdef _WIN32
#include <windows.h>
#undef EXTERN_C
#include "compat/avisynth/avisynth_c.h"
+ #include "compat/avisynth/avisynth_c_25.h"
#define AVISYNTH_LIB "avisynth"
+ #define USING_AVISYNTH
#else
#include <dlfcn.h>
#include "compat/avisynth/avxsynth_c.h"
- #if defined (__APPLE__)
- #define AVISYNTH_LIB "libavxsynth.dylib"
- #else
- #define AVISYNTH_LIB "libavxsynth.so"
- #endif
+ #if defined (__APPLE__)
+ #define AVISYNTH_LIB "libavxsynth.dylib"
+ #else
+ #define AVISYNTH_LIB "libavxsynth.so"
+ #endif
#define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL)
#define GetProcAddress dlsym
#define FreeLibrary dlclose
#endif
-// AvxSynth doesn't have these colorspaces, so disable them
-#ifndef _WIN32
-#define avs_is_yv24(vi) 0
-#define avs_is_yv16(vi) 0
-#define avs_is_yv411(vi) 0
-#define avs_is_y8(vi) 0
-#endif
-
-typedef struct {
+typedef struct AviSynthLibrary {
void *library;
-#define AVSC_DECLARE_FUNC(name) name##_func name
+#define AVSC_DECLARE_FUNC(name) name ## _func name
+ AVSC_DECLARE_FUNC(avs_bit_blt);
+ AVSC_DECLARE_FUNC(avs_clip_get_error);
AVSC_DECLARE_FUNC(avs_create_script_environment);
AVSC_DECLARE_FUNC(avs_delete_script_environment);
+ AVSC_DECLARE_FUNC(avs_get_audio);
AVSC_DECLARE_FUNC(avs_get_error);
- AVSC_DECLARE_FUNC(avs_clip_get_error);
- AVSC_DECLARE_FUNC(avs_invoke);
- AVSC_DECLARE_FUNC(avs_release_value);
+ AVSC_DECLARE_FUNC(avs_get_frame);
+ AVSC_DECLARE_FUNC(avs_get_version);
AVSC_DECLARE_FUNC(avs_get_video_info);
- AVSC_DECLARE_FUNC(avs_take_clip);
+ AVSC_DECLARE_FUNC(avs_invoke);
AVSC_DECLARE_FUNC(avs_release_clip);
- AVSC_DECLARE_FUNC(avs_bit_blt);
- AVSC_DECLARE_FUNC(avs_get_audio);
- AVSC_DECLARE_FUNC(avs_get_frame);
+ AVSC_DECLARE_FUNC(avs_release_value);
AVSC_DECLARE_FUNC(avs_release_video_frame);
+ AVSC_DECLARE_FUNC(avs_take_clip);
#undef AVSC_DECLARE_FUNC
} AviSynthLibrary;
-struct AviSynthContext {
+typedef struct AviSynthContext {
AVS_ScriptEnvironment *env;
AVS_Clip *clip;
const AVS_VideoInfo *vi;
- // avisynth_read_packet_video() iterates over this.
+ /* avisynth_read_packet_video() iterates over this. */
int n_planes;
const int *planes;
@@ -93,103 +83,96 @@ struct AviSynthContext {
int error;
- // Linked list pointers.
+ /* Linked list pointers. */
struct AviSynthContext *next;
-};
-typedef struct AviSynthContext AviSynthContext;
+} AviSynthContext;
-static const int avs_planes_packed[1] = {0};
-static const int avs_planes_grey[1] = {AVS_PLANAR_Y};
-static const int avs_planes_yuv[3] = {AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V};
+static const int avs_planes_packed[1] = { 0 };
+static const int avs_planes_grey[1] = { AVS_PLANAR_Y };
+static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U,
+ AVS_PLANAR_V };
-// A conflict between C++ global objects, atexit, and dynamic loading requires
-// us to register our own atexit handler to prevent double freeing.
-static AviSynthLibrary *avs_library = NULL;
-static int avs_atexit_called = 0;
+/* A conflict between C++ global objects, atexit, and dynamic loading requires
+ * us to register our own atexit handler to prevent double freeing. */
+static AviSynthLibrary avs_library;
+static int avs_atexit_called = 0;
-// Linked list of AviSynthContexts. An atexit handler destroys this list.
+/* Linked list of AviSynthContexts. An atexit handler destroys this list. */
static AviSynthContext *avs_ctx_list = NULL;
static av_cold void avisynth_atexit_handler(void);
-static av_cold int avisynth_load_library(void) {
- avs_library = av_mallocz(sizeof(AviSynthLibrary));
- if (!avs_library)
+static av_cold int avisynth_load_library(void)
+{
+ avs_library.library = LoadLibrary(AVISYNTH_LIB);
+ if (!avs_library.library)
return AVERROR_UNKNOWN;
- avs_library->library = LoadLibrary(AVISYNTH_LIB);
- if (!avs_library->library)
- goto init_fail;
+#define LOAD_AVS_FUNC(name, continue_on_fail) \
+ avs_library.name = \
+ (void *)GetProcAddress(avs_library.library, #name); \
+ if (!continue_on_fail && !avs_library.name) \
+ goto fail;
-#define LOAD_AVS_FUNC(name, continue_on_fail) \
-{ \
- avs_library->name = (void*)GetProcAddress(avs_library->library, #name); \
- if(!continue_on_fail && !avs_library->name) \
- goto fail; \
-}
+ LOAD_AVS_FUNC(avs_bit_blt, 0);
+ LOAD_AVS_FUNC(avs_clip_get_error, 0);
LOAD_AVS_FUNC(avs_create_script_environment, 0);
LOAD_AVS_FUNC(avs_delete_script_environment, 0);
+ LOAD_AVS_FUNC(avs_get_audio, 0);
LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
- LOAD_AVS_FUNC(avs_clip_get_error, 0);
- LOAD_AVS_FUNC(avs_invoke, 0);
- LOAD_AVS_FUNC(avs_release_value, 0);
+ LOAD_AVS_FUNC(avs_get_frame, 0);
+ LOAD_AVS_FUNC(avs_get_version, 0);
LOAD_AVS_FUNC(avs_get_video_info, 0);
- LOAD_AVS_FUNC(avs_take_clip, 0);
+ LOAD_AVS_FUNC(avs_invoke, 0);
LOAD_AVS_FUNC(avs_release_clip, 0);
- LOAD_AVS_FUNC(avs_bit_blt, 0);
- LOAD_AVS_FUNC(avs_get_audio, 0);
- LOAD_AVS_FUNC(avs_get_frame, 0);
+ LOAD_AVS_FUNC(avs_release_value, 0);
LOAD_AVS_FUNC(avs_release_video_frame, 0);
+ LOAD_AVS_FUNC(avs_take_clip, 0);
#undef LOAD_AVS_FUNC
atexit(avisynth_atexit_handler);
return 0;
fail:
- FreeLibrary(avs_library->library);
-init_fail:
- av_freep(&avs_library);
+ FreeLibrary(avs_library.library);
return AVERROR_UNKNOWN;
}
-// Note that avisynth_context_create and avisynth_context_destroy
-// do not allocate or free the actual context! That is taken care of
-// by libavformat.
-static av_cold int avisynth_context_create(AVFormatContext *s) {
- AviSynthContext *avs = (AviSynthContext *)s->priv_data;
+/* Note that avisynth_context_create and avisynth_context_destroy
+ * do not allocate or free the actual context! That is taken care of
+ * by libavformat. */
+static av_cold int avisynth_context_create(AVFormatContext *s)
+{
+ AviSynthContext *avs = s->priv_data;
int ret;
- if (!avs_library) {
+ if (!avs_library.library)
if (ret = avisynth_load_library())
return ret;
- }
- if (!avs)
- return AVERROR_UNKNOWN;
+ avs->env = avs_library.avs_create_script_environment(3);
+ if (avs_library.avs_get_error) {
+ const char *error = avs_library.avs_get_error(avs->env);
+ if (error) {
+ av_log(s, AV_LOG_ERROR, "%s\n", error);
+ return AVERROR_UNKNOWN;
+ }
+ }
if (!avs_ctx_list) {
avs_ctx_list = avs;
} else {
- avs->next = avs_ctx_list;
+ avs->next = avs_ctx_list;
avs_ctx_list = avs;
}
- avs->env = avs_library->avs_create_script_environment(3);
- if (avs_library->avs_get_error) {
- const char *error = avs_library->avs_get_error(avs->env);
- if (error) {
- av_log(s, AV_LOG_ERROR, "%s\n", error);
- av_free(avs);
- return AVERROR_UNKNOWN;
- }
- }
-
return 0;
}
-static av_cold void avisynth_context_destroy(AviSynthContext *avs) {
+static av_cold void avisynth_context_destroy(AviSynthContext *avs)
+{
if (avs_atexit_called)
- return;
+ return;
if (avs == avs_ctx_list) {
avs_ctx_list = avs->next;
@@ -201,16 +184,17 @@ static av_cold void avisynth_context_destroy(AviSynthContext *avs) {
}
if (avs->clip) {
- avs_library->avs_release_clip(avs->clip);
+ avs_library.avs_release_clip(avs->clip);
avs->clip = NULL;
}
if (avs->env) {
- avs_library->avs_delete_script_environment(avs->env);
+ avs_library.avs_delete_script_environment(avs->env);
avs->env = NULL;
}
}
-static av_cold void avisynth_atexit_handler(void) {
+static av_cold void avisynth_atexit_handler(void)
+{
AviSynthContext *avs = avs_ctx_list;
while (avs) {
@@ -218,66 +202,69 @@ static av_cold void avisynth_atexit_handler(void) {
avisynth_context_destroy(avs);
avs = next;
}
- FreeLibrary(avs_library->library);
- av_freep(&avs_library);
+ FreeLibrary(avs_library.library);
avs_atexit_called = 1;
}
-// Create AVStream from audio and video data.
-static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) {
+/* Create AVStream from audio and video data. */
+static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st)
+{
AviSynthContext *avs = s->priv_data;
int planar = 0; // 0: packed, 1: YUV, 2: Y8
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = CODEC_ID_RAWVIDEO;
- st->codec->width = avs->vi->width;
- st->codec->height = avs->vi->height;
-
- st->time_base = (AVRational) {avs->vi->fps_denominator, avs->vi->fps_numerator};
- st->avg_frame_rate = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
- st->start_time = 0;
- st->duration = avs->vi->num_frames;
- st->nb_frames = avs->vi->num_frames;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = avs->vi->width;
+ st->codec->height = avs->vi->height;
+
+ st->time_base = (AVRational) { avs->vi->fps_denominator,
+ avs->vi->fps_numerator };
+ st->avg_frame_rate = (AVRational) { avs->vi->fps_numerator,
+ avs->vi->fps_denominator };
+ st->start_time = 0;
+ st->duration = avs->vi->num_frames;
+ st->nb_frames = avs->vi->num_frames;
switch (avs->vi->pixel_type) {
-#ifdef _WIN32
+#ifdef USING_AVISYNTH
case AVS_CS_YV24:
- st->codec->pix_fmt = PIX_FMT_YUV444P;
- planar = 1;
+ st->codec->pix_fmt = AV_PIX_FMT_YUV444P;
+ planar = 1;
break;
case AVS_CS_YV16:
- st->codec->pix_fmt = PIX_FMT_YUV422P;
- planar = 1;
+ st->codec->pix_fmt = AV_PIX_FMT_YUV422P;
+ planar = 1;
break;
case AVS_CS_YV411:
- st->codec->pix_fmt = PIX_FMT_YUV411P;
- planar = 1;
+ st->codec->pix_fmt = AV_PIX_FMT_YUV411P;
+ planar = 1;
break;
case AVS_CS_Y8:
- st->codec->pix_fmt = PIX_FMT_GRAY8;
- planar = 2;
+ st->codec->pix_fmt = AV_PIX_FMT_GRAY8;
+ planar = 2;
break;
#endif
case AVS_CS_BGR24:
- st->codec->pix_fmt = PIX_FMT_RGB24;
+ st->codec->pix_fmt = AV_PIX_FMT_BGR24;
break;
case AVS_CS_BGR32:
- st->codec->pix_fmt = PIX_FMT_RGB32;
+ st->codec->pix_fmt = AV_PIX_FMT_RGB32;
break;
case AVS_CS_YUY2:
- st->codec->pix_fmt = PIX_FMT_YUYV422;
+ st->codec->pix_fmt = AV_PIX_FMT_YUYV422;
break;
case AVS_CS_YV12:
- st->codec->pix_fmt = PIX_FMT_YUV420P;
- planar = 1;
+ st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
+ planar = 1;
break;
case AVS_CS_I420: // Is this even used anywhere?
- st->codec->pix_fmt = PIX_FMT_YUV420P;
- planar = 1;
+ st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
+ planar = 1;
break;
default:
- av_log(s, AV_LOG_ERROR, "unknown AviSynth colorspace %d\n", avs->vi->pixel_type);
+ av_log(s, AV_LOG_ERROR,
+ "unknown AviSynth colorspace %d\n", avs->vi->pixel_type);
avs->error = 1;
return AVERROR_UNKNOWN;
}
@@ -285,52 +272,56 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) {
switch (planar) {
case 2: // Y8
avs->n_planes = 1;
- avs->planes = avs_planes_grey;
+ avs->planes = avs_planes_grey;
break;
case 1: // YUV
avs->n_planes = 3;
- avs->planes = avs_planes_yuv;
+ avs->planes = avs_planes_yuv;
break;
default:
avs->n_planes = 1;
- avs->planes = avs_planes_packed;
+ avs->planes = avs_planes_packed;
}
return 0;
}
-static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) {
+static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st)
+{
AviSynthContext *avs = s->priv_data;
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = avs->vi->audio_samples_per_second;
- st->codec->channels = avs->vi->nchannels;
- st->time_base = (AVRational) {1, avs->vi->audio_samples_per_second};
+ st->codec->channels = avs->vi->nchannels;
+ st->time_base = (AVRational) { 1,
+ avs->vi->audio_samples_per_second };
switch (avs->vi->sample_type) {
case AVS_SAMPLE_INT8:
- st->codec->codec_id = CODEC_ID_PCM_U8;
+ st->codec->codec_id = AV_CODEC_ID_PCM_U8;
break;
case AVS_SAMPLE_INT16:
- st->codec->codec_id = CODEC_ID_PCM_S16LE;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
break;
case AVS_SAMPLE_INT24:
- st->codec->codec_id = CODEC_ID_PCM_S24LE;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S24LE;
break;
case AVS_SAMPLE_INT32:
- st->codec->codec_id = CODEC_ID_PCM_S32LE;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S32LE;
break;
case AVS_SAMPLE_FLOAT:
- st->codec->codec_id = CODEC_ID_PCM_F32LE;
+ st->codec->codec_id = AV_CODEC_ID_PCM_F32LE;
break;
default:
- av_log(s, AV_LOG_ERROR, "unknown AviSynth sample type %d\n", avs->vi->sample_type);
+ av_log(s, AV_LOG_ERROR,
+ "unknown AviSynth sample type %d\n", avs->vi->sample_type);
avs->error = 1;
return AVERROR_UNKNOWN;
}
return 0;
}
-static int avisynth_create_stream(AVFormatContext *s) {
+static int avisynth_create_stream(AVFormatContext *s)
+{
AviSynthContext *avs = s->priv_data;
AVStream *st;
int ret;
@@ -355,32 +346,45 @@ static int avisynth_create_stream(AVFormatContext *s) {
return 0;
}
-static int avisynth_open_file(AVFormatContext *s) {
- AviSynthContext *avs = (AviSynthContext *)s->priv_data;
+static int avisynth_open_file(AVFormatContext *s)
+{
+ AviSynthContext *avs = s->priv_data;
AVS_Value arg, val;
int ret;
+#ifdef USING_AVISYNTH
+ char filename_ansi[MAX_PATH * 4];
+ wchar_t filename_wc[MAX_PATH * 4];
+#endif
if (ret = avisynth_context_create(s))
return ret;
+#ifdef USING_AVISYNTH
+ /* Convert UTF-8 to ANSI code page */
+ MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
+ WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi,
+ MAX_PATH * 4, NULL, NULL);
+ arg = avs_new_value_string(filename_ansi);
+#else
arg = avs_new_value_string(s->filename);
- val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
+#endif
+ val = avs_library.avs_invoke(avs->env, "Import", arg, 0);
if (avs_is_error(val)) {
av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val));
ret = AVERROR_UNKNOWN;
goto fail;
}
if (!avs_is_clip(val)) {
- av_log(s, AV_LOG_ERROR, "%s\n", "AviSynth script did not return a clip");
+ av_log(s, AV_LOG_ERROR, "AviSynth script did not return a clip\n");
ret = AVERROR_UNKNOWN;
goto fail;
}
- avs->clip = avs_library->avs_take_clip(val, avs->env);
- avs->vi = avs_library->avs_get_video_info(avs->clip);
+ avs->clip = avs_library.avs_take_clip(val, avs->env);
+ avs->vi = avs_library.avs_get_video_info(avs->clip);
- // Release the AVS_Value as it will go out of scope.
- avs_library->avs_release_value(val);
+ /* Release the AVS_Value as it will go out of scope. */
+ avs_library.avs_release_value(val);
if (ret = avisynth_create_stream(s))
goto fail;
@@ -392,7 +396,9 @@ fail:
return ret;
}
-static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pkt, int *discard) {
+static void avisynth_next_stream(AVFormatContext *s, AVStream **st,
+ AVPacket *pkt, int *discard)
+{
AviSynthContext *avs = s->priv_data;
pkt->stream_index = avs->curr_stream++;
@@ -407,50 +413,59 @@ static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pk
return;
}
-// Copy AviSynth clip data into an AVPacket.
-static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int discard) {
+/* Copy AviSynth clip data into an AVPacket. */
+static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt,
+ int discard)
+{
AviSynthContext *avs = s->priv_data;
AVS_VideoFrame *frame;
- unsigned char* dst_p;
- const unsigned char* src_p;
- int i, plane, rowsize, planeheight, pitch, bits;
- const char* error;
+ unsigned char *dst_p;
+ const unsigned char *src_p;
+ int n, i, plane, rowsize, planeheight, pitch, bits;
+ const char *error;
if (avs->curr_frame >= avs->vi->num_frames)
return AVERROR_EOF;
- // This must happen even if the stream is discarded to prevent desync.
- avs->curr_frame++;
+ /* This must happen even if the stream is discarded to prevent desync. */
+ n = avs->curr_frame++;
if (discard)
return 0;
- pkt->pts = avs->curr_frame;
- pkt->dts = avs->curr_frame;
+ pkt->pts = n;
+ pkt->dts = n;
pkt->duration = 1;
- // Define the bpp values for the new AviSynth 2.6 colorspaces
- if (avs_is_yv24(avs->vi)) {
+#ifdef USING_AVISYNTH
+ /* Define the bpp values for the new AviSynth 2.6 colorspaces.
+ * Since AvxSynth doesn't have these functions, special-case
+ * it in order to avoid implicit declaration errors. */
+
+ if (avs_is_yv24(avs->vi))
bits = 24;
- } else if (avs_is_yv16(avs->vi)) {
+ else if (avs_is_yv16(avs->vi))
bits = 16;
- } else if (avs_is_yv411(avs->vi)) {
+ else if (avs_is_yv411(avs->vi))
bits = 12;
- } else if (avs_is_y8(avs->vi)) {
+ else if (avs_is_y8(avs->vi))
bits = 8;
- } else {
+ else
+#endif
bits = avs_bits_per_pixel(avs->vi);
- }
- // Without cast to int64_t, calculation overflows at about 9k x 9k resolution.
- pkt->size = (((int64_t)avs->vi->width * (int64_t)avs->vi->height) * bits) / 8;
+ /* Without the cast to int64_t, calculation overflows at about 9k x 9k
+ * resolution. */
+ pkt->size = (((int64_t)avs->vi->width *
+ (int64_t)avs->vi->height) * bits) / 8;
if (!pkt->size)
return AVERROR_UNKNOWN;
- pkt->data = av_malloc(pkt->size);
- if (!pkt->data)
- return AVERROR_UNKNOWN;
+ if (av_new_packet(pkt, (int)pkt->size) < 0) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
- frame = avs_library->avs_get_frame(avs->clip, avs->curr_frame);
- error = avs_library->avs_clip_get_error(avs->clip);
+ 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;
@@ -462,48 +477,64 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int dis
for (i = 0; i < avs->n_planes; i++) {
plane = avs->planes[i];
src_p = avs_get_read_ptr_p(frame, plane);
- rowsize = avs_get_row_size_p(frame, plane);
- planeheight = avs_get_height_p(frame, plane);
pitch = avs_get_pitch_p(frame, plane);
- // Flip RGB video.
+#ifdef USING_AVISYNTH
+ if (avs_library.avs_get_version(avs->clip) == 3) {
+ rowsize = avs_get_row_size_p_25(frame, plane);
+ planeheight = avs_get_height_p_25(frame, plane);
+ } else {
+ rowsize = avs_get_row_size_p(frame, plane);
+ planeheight = avs_get_height_p(frame, plane);
+ }
+#else
+ rowsize = avs_get_row_size_p(frame, plane);
+ planeheight = avs_get_height_p(frame, plane);
+#endif
+
+ /* Flip RGB video. */
if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
src_p = src_p + (planeheight - 1) * pitch;
pitch = -pitch;
}
- avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, rowsize, planeheight);
+ avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch,
+ rowsize, planeheight);
dst_p += rowsize * planeheight;
}
- avs_library->avs_release_video_frame(frame);
+ avs_library.avs_release_video_frame(frame);
return 0;
}
-static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int discard) {
+static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt,
+ int discard)
+{
AviSynthContext *avs = s->priv_data;
AVRational fps, samplerate;
int samples;
- const char* error;
+ int64_t n;
+ const char *error;
if (avs->curr_sample >= avs->vi->num_audio_samples)
return AVERROR_EOF;
- fps.num = avs->vi->fps_numerator;
- fps.den = avs->vi->fps_denominator;
+ fps.num = avs->vi->fps_numerator;
+ fps.den = avs->vi->fps_denominator;
samplerate.num = avs->vi->audio_samples_per_second;
samplerate.den = 1;
if (avs_has_video(avs->vi)) {
if (avs->curr_frame < avs->vi->num_frames)
- samples = av_rescale_q(avs->curr_frame, samplerate, fps) - avs->curr_sample;
+ samples = av_rescale_q(avs->curr_frame, samplerate, fps) -
+ avs->curr_sample;
else
samples = av_rescale_q(1, samplerate, fps);
} else {
samples = 1000;
}
- // After seeking, audio may catch up with video.
+ /* After seeking, audio may catch up with video. */
if (samples <= 0) {
pkt->size = 0;
pkt->data = NULL;
@@ -513,24 +544,26 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int dis
if (avs->curr_sample + samples > avs->vi->num_audio_samples)
samples = avs->vi->num_audio_samples - avs->curr_sample;
- // This must happen even if the stream is discarded to prevent desync.
+ /* This must happen even if the stream is discarded to prevent desync. */
+ n = avs->curr_sample;
avs->curr_sample += samples;
if (discard)
return 0;
- pkt->pts = avs->curr_sample;
- pkt->dts = avs->curr_sample;
+ pkt->pts = n;
+ pkt->dts = n;
pkt->duration = samples;
- pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels;
+ 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)
- return AVERROR_UNKNOWN;
+ return AVERROR(ENOMEM);
- avs_library->avs_get_audio(avs->clip, pkt->data, avs->curr_sample, samples);
- error = avs_library->avs_clip_get_error(avs->clip);
+ 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;
@@ -540,7 +573,8 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int dis
return 0;
}
-static av_cold int avisynth_read_header(AVFormatContext *s) {
+static av_cold int avisynth_read_header(AVFormatContext *s)
+{
int ret;
// Calling library must implement a lock for thread-safe opens.
@@ -556,7 +590,8 @@ static av_cold int avisynth_read_header(AVFormatContext *s) {
return 0;
}
-static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
+static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
AviSynthContext *avs = s->priv_data;
AVStream *st;
int discard = 0;
@@ -565,9 +600,10 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
if (avs->error)
return AVERROR_UNKNOWN;
- pkt->destruct = av_destruct_packet;
+ av_free_packet(pkt);
- // If either stream reaches EOF, try to read the other one before giving up.
+ /* If either stream reaches EOF, try to read the other one before
+ * giving up. */
avisynth_next_stream(s, &st, pkt, &discard);
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
ret = avisynth_read_packet_video(s, pkt, discard);
@@ -575,18 +611,19 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
avisynth_next_stream(s, &st, pkt, &discard);
return avisynth_read_packet_audio(s, pkt, discard);
}
- return ret;
} else {
ret = avisynth_read_packet_audio(s, pkt, discard);
if (ret == AVERROR_EOF && avs_has_video(avs->vi)) {
avisynth_next_stream(s, &st, pkt, &discard);
return avisynth_read_packet_video(s, pkt, discard);
}
- return ret;
}
+
+ return ret;
}
-static av_cold int avisynth_read_close(AVFormatContext *s) {
+static av_cold int avisynth_read_close(AVFormatContext *s)
+{
if (avpriv_lock_avformat())
return AVERROR_UNKNOWN;
@@ -595,7 +632,9 @@ static av_cold int avisynth_read_close(AVFormatContext *s) {
return 0;
}
-static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) {
+static int avisynth_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
AviSynthContext *avs = s->priv_data;
AVStream *st;
AVRational fps, samplerate;
@@ -603,13 +642,16 @@ static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t time
if (avs->error)
return AVERROR_UNKNOWN;
- fps = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
- samplerate = (AVRational) {avs->vi->audio_samples_per_second, 1};
+ fps = (AVRational) { avs->vi->fps_numerator,
+ avs->vi->fps_denominator };
+ samplerate = (AVRational) { avs->vi->audio_samples_per_second, 1 };
st = s->streams[stream_index];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- // AviSynth frame counts are signed int.
- if ((timestamp >= avs->vi->num_frames) || (timestamp > INT_MAX) || (timestamp < 0))
+ /* AviSynth frame counts are signed int. */
+ if ((timestamp >= avs->vi->num_frames) ||
+ (timestamp > INT_MAX) ||
+ (timestamp < 0))
return AVERROR_EOF;
avs->curr_frame = timestamp;
if (avs_has_audio(avs->vi))
@@ -617,9 +659,9 @@ static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t time
} else {
if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0))
return AVERROR_EOF;
- // Force frame granularity for seeking.
+ /* Force frame granularity for seeking. */
if (avs_has_video(avs->vi)) {
- avs->curr_frame = av_rescale_q(timestamp, fps, samplerate);
+ avs->curr_frame = av_rescale_q(timestamp, fps, samplerate);
avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps);
} else {
avs->curr_sample = timestamp;
diff --git a/ffmpeg/libavformat/avr.c b/ffmpeg/libavformat/avr.c
index 473136e..a33134e 100644
--- a/ffmpeg/libavformat/avr.c
+++ b/ffmpeg/libavformat/avr.c
@@ -26,9 +26,15 @@
static int avr_probe(AVProbeData *p)
{
- if (AV_RL32(p->buf) == MKTAG('2', 'B', 'I', 'T'))
- return AVPROBE_SCORE_MAX / 2;
- return 0;
+ if (AV_RL32(p->buf) != MKTAG('2', 'B', 'I', 'T'))
+ return 0;
+
+ if (!AV_RB16(p->buf+12) || AV_RB16(p->buf+12) > 256) // channels
+ return AVPROBE_SCORE_EXTENSION/2;
+ if (AV_RB16(p->buf+14) > 256) // bps
+ return AVPROBE_SCORE_EXTENSION/2;
+
+ return AVPROBE_SCORE_EXTENSION;
}
static int avr_read_header(AVFormatContext *s)
@@ -69,16 +75,9 @@ static int avr_read_header(AVFormatContext *s)
avio_skip(s->pb, 20);
avio_skip(s->pb, 64);
- if (!sign && bps == 8) {
- st->codec->codec_id = AV_CODEC_ID_PCM_U8;
- } else if (!sign && bps == 16) {
- st->codec->codec_id = AV_CODEC_ID_PCM_U16BE;
- } else if (sign == 0xFFFFu && bps == 8) {
- st->codec->codec_id = AV_CODEC_ID_PCM_S8;
- } else if (sign == 0xFFFFu && bps == 16) {
- st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
- } else {
- avpriv_request_sample(s, "bits per sample %d", bps);
+ st->codec->codec_id = ff_get_pcm_codec_id(bps, 0, 1, sign);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) {
+ avpriv_request_sample(s, "Bps %d and sign %d", bps, sign);
return AVERROR_PATCHWELCOME;
}
diff --git a/ffmpeg/libavformat/avs.c b/ffmpeg/libavformat/avs.c
index ec9198b..7814301 100644
--- a/ffmpeg/libavformat/avs.c
+++ b/ffmpeg/libavformat/avs.c
@@ -50,7 +50,9 @@ static int avs_probe(AVProbeData * p)
d = p->buf;
if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0)
- return 55;
+ /* Ensure the buffer probe scores higher than the extension probe.
+ * This avoids problems with misdetection as AviSynth scripts. */
+ return AVPROBE_SCORE_EXTENSION + 5;
return 0;
}
diff --git a/ffmpeg/libavformat/bethsoftvid.c b/ffmpeg/libavformat/bethsoftvid.c
index b8f08c1..6b84b79 100644
--- a/ffmpeg/libavformat/bethsoftvid.c
+++ b/ffmpeg/libavformat/bethsoftvid.c
@@ -61,6 +61,9 @@ static int vid_probe(AVProbeData *p)
if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
return 0;
+ if (p->buf[4] != 2)
+ return AVPROBE_SCORE_MAX / 4;
+
return AVPROBE_SCORE_MAX;
}
diff --git a/ffmpeg/libavformat/bfi.c b/ffmpeg/libavformat/bfi.c
index a28e09a..b65a582 100644
--- a/ffmpeg/libavformat/bfi.c
+++ b/ffmpeg/libavformat/bfi.c
@@ -81,6 +81,8 @@ static int bfi_read_header(AVFormatContext * s)
/*Load the palette to extradata */
avio_skip(pb, 8);
vstream->codec->extradata = av_malloc(768);
+ if (!vstream->codec->extradata)
+ return AVERROR(ENOMEM);
vstream->codec->extradata_size = 768;
avio_read(pb, vstream->codec->extradata,
vstream->codec->extradata_size);
@@ -134,6 +136,10 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
video_offset = avio_rl32(pb);
audio_size = video_offset - audio_offset;
bfi->video_size = chunk_size - video_offset;
+ if (audio_size < 0 || bfi->video_size < 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid audio/video offsets or chunk size\n");
+ return AVERROR_INVALIDDATA;
+ }
//Tossing an audio packet at the audio decoder.
ret = av_get_packet(pb, pkt, audio_size);
@@ -142,9 +148,7 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
pkt->pts = bfi->audio_frame;
bfi->audio_frame += ret;
- }
-
- else {
+ } else if (bfi->video_size > 0) {
//Tossing a video packet at the video decoder.
ret = av_get_packet(pb, pkt, bfi->video_size);
@@ -152,10 +156,13 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
return ret;
pkt->pts = bfi->video_frame;
- bfi->video_frame += bfi->video_size ? ret / bfi->video_size : 1;
+ bfi->video_frame += ret / bfi->video_size;
/* One less frame to read. A cursory decrement. */
bfi->nframes--;
+ } else {
+ /* Empty video packet */
+ ret = AVERROR(EAGAIN);
}
bfi->avflag = !bfi->avflag;
diff --git a/ffmpeg/libavformat/bink.c b/ffmpeg/libavformat/bink.c
index 887f70a..95b615a 100644
--- a/ffmpeg/libavformat/bink.c
+++ b/ffmpeg/libavformat/bink.c
@@ -116,11 +116,8 @@ static int read_header(AVFormatContext *s)
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = AV_CODEC_ID_BINKVIDEO;
- vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!vst->codec->extradata)
+ if (ff_get_extradata(vst->codec, pb, 4) < 0)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 4;
- avio_read(pb, vst->codec->extradata, 4);
bink->num_audio_tracks = avio_rl32(pb);
@@ -152,10 +149,8 @@ static int read_header(AVFormatContext *s)
ast->codec->channels = 1;
ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
}
- ast->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!ast->codec->extradata)
+ if (ff_alloc_extradata(ast->codec, 4))
return AVERROR(ENOMEM);
- ast->codec->extradata_size = 4;
AV_WL32(ast->codec->extradata, vst->codec->codec_tag);
}
diff --git a/ffmpeg/libavformat/bintext.c b/ffmpeg/libavformat/bintext.c
index 91f95f3..d50a8d9 100644
--- a/ffmpeg/libavformat/bintext.c
+++ b/ffmpeg/libavformat/bintext.c
@@ -43,8 +43,8 @@ typedef struct {
int chars_per_frame; /**< characters to send decoder per frame;
set by private options as characters per second, and then
converted to characters per frame at runtime */
- char *video_size; /**< video size (WxH pixels) (private option) */
- char *framerate; /**< frames per second (private option) */
+ int width, height; /**< video size (WxH pixels) (private option) */
+ AVRational framerate; /**< frames per second (private option) */
uint64_t fsize; /**< file size less metadata buffer */
} BinDemuxContext;
@@ -57,29 +57,15 @@ static AVStream * init_stream(AVFormatContext *s)
st->codec->codec_tag = 0;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- if (bin->video_size) {
- if (av_parse_video_size(&st->codec->width, &st->codec->height, bin->video_size) < 0) {
- av_log(s, AV_LOG_ERROR, "Could not parse video size: '%s'\n", bin->video_size);
- return NULL;
- }
- } else {
+ if (!bin->width) {
st->codec->width = (80<<3);
st->codec->height = (25<<4);
}
- if (bin->framerate) {
- AVRational framerate;
- if (av_parse_video_rate(&framerate, bin->framerate) < 0) {
- av_log(s, AV_LOG_ERROR, "Could not parse framerate: '%s'\n", bin->framerate);
- return NULL;
- }
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
- } else {
- avpriv_set_pts_info(st, 60, 1, 25);
- }
+ avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num);
/* simulate tty display speed */
- bin->chars_per_frame = FFMAX(av_q2d(st->time_base) * bin->chars_per_frame, 1);
+ bin->chars_per_frame = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX);
return st;
}
@@ -150,9 +136,7 @@ static int bintext_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_BINTEXT;
- st->codec->extradata_size = 2;
- st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 2))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = 0;
@@ -162,7 +146,7 @@ static int bintext_read_header(AVFormatContext *s)
bin->fsize = avio_size(pb);
if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
next_tag_read(s, &bin->fsize);
- if (!bin->video_size) {
+ if (!bin->width) {
predict_width(st->codec, bin->fsize, got_width);
calculate_height(st->codec, bin->fsize);
}
@@ -208,8 +192,7 @@ static int xbin_read_header(AVFormatContext *s)
st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
- st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, st->codec->extradata_size))
return AVERROR(ENOMEM);
st->codec->extradata[0] = fontheight;
st->codec->extradata[1] = flags;
@@ -241,9 +224,7 @@ static int adf_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_BINTEXT;
- st->codec->extradata_size = 2 + 48 + 4096;
- st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
@@ -261,7 +242,7 @@ static int adf_read_header(AVFormatContext *s)
bin->fsize = avio_size(pb) - 1 - 192 - 4096;
st->codec->width = 80<<3;
ff_sauce_read(s, &bin->fsize, &got_width, 0);
- if (!bin->video_size)
+ if (!bin->width)
calculate_height(st->codec, bin->fsize);
avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
}
@@ -298,9 +279,7 @@ static int idf_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_IDF;
- st->codec->extradata_size = 2 + 48 + 4096;
- st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
@@ -314,7 +293,7 @@ static int idf_read_header(AVFormatContext *s)
bin->fsize = avio_size(pb) - 12 - 4096 - 48;
ff_sauce_read(s, &bin->fsize, &got_width, 0);
- if (!bin->video_size)
+ if (!bin->width)
calculate_height(st->codec, bin->fsize);
avio_seek(pb, 12, SEEK_SET);
return 0;
@@ -346,8 +325,8 @@ static int read_packet(AVFormatContext *s,
#define OFFSET(x) offsetof(BinDemuxContext, x)
static const AVOption options[] = {
{ "linespeed", "set simulated line speed (bytes per second)", OFFSET(chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
- { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
- { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
diff --git a/ffmpeg/libavformat/bit.c b/ffmpeg/libavformat/bit.c
index 9f6ea4a..0be471a 100644
--- a/ffmpeg/libavformat/bit.c
+++ b/ffmpeg/libavformat/bit.c
@@ -44,7 +44,7 @@ static int probe(AVProbeData *p)
return 0;
i+=j;
}
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int read_header(AVFormatContext *s)
@@ -139,7 +139,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
init_get_bits(&gb, pkt->data, 8*10);
for(i=0; i< 8 * 10; i++)
avio_wl16(pb, get_bits1(&gb) ? BIT_1 : BIT_0);
- avio_flush(pb);
return 0;
}
diff --git a/ffmpeg/libavformat/bmv.c b/ffmpeg/libavformat/bmv.c
index ce157e8..f7a6068 100644
--- a/ffmpeg/libavformat/bmv.c
+++ b/ffmpeg/libavformat/bmv.c
@@ -2,20 +2,20 @@
* Discworld II BMV demuxer
* Copyright (c) 2011 Konstantin Shishkov.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,8 +71,7 @@ static int bmv_read_header(AVFormatContext *s)
static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
BMVContext *c = s->priv_data;
- int type;
- void *tmp;
+ int type, err;
while (c->get_next) {
if (s->pb->eof_reached)
@@ -85,10 +84,8 @@ static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt)
c->size = avio_rl24(s->pb);
if (!c->size)
return AVERROR_INVALIDDATA;
- tmp = av_realloc(c->packet, c->size + 1);
- if (!tmp)
- return AVERROR(ENOMEM);
- c->packet = tmp;
+ if ((err = av_reallocp(&c->packet, c->size + 1)) < 0)
+ return err;
c->packet[0] = type;
if (avio_read(s->pb, c->packet + 1, c->size) != c->size)
return AVERROR(EIO);
diff --git a/ffmpeg/libavformat/cafdec.c b/ffmpeg/libavformat/cafdec.c
index 337758e..0b5d59c 100644
--- a/ffmpeg/libavformat/cafdec.c
+++ b/ffmpeg/libavformat/cafdec.c
@@ -130,8 +130,7 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
}
avio_read(pb, preamble, ALAC_PREAMBLE);
- st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, ALAC_HEADER))
return AVERROR(ENOMEM);
/* For the old style cookie, we skip 12 bytes, then read 36 bytes.
@@ -154,13 +153,9 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12);
avio_skip(pb, size - ALAC_NEW_KUKI);
}
- st->codec->extradata_size = ALAC_HEADER;
} else {
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, st->codec->extradata, size);
- st->codec->extradata_size = size;
}
return 0;
diff --git a/ffmpeg/libavformat/cafenc.c b/ffmpeg/libavformat/cafenc.c
index 11bb055..ae36b85 100644
--- a/ffmpeg/libavformat/cafenc.c
+++ b/ffmpeg/libavformat/cafenc.c
@@ -86,8 +86,9 @@ static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels) {
return 1152;
case AV_CODEC_ID_AC3:
return 1536;
- case AV_CODEC_ID_ALAC:
case AV_CODEC_ID_QDM2:
+ return 2048 * channels;
+ case AV_CODEC_ID_ALAC:
return 4096;
case AV_CODEC_ID_ADPCM_IMA_WAV:
return (1024 - 4 * channels) * 8 / (4 * channels) + 1;
@@ -107,6 +108,11 @@ 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:
diff --git a/ffmpeg/libavformat/cavsvideodec.c b/ffmpeg/libavformat/cavsvideodec.c
index c035128..5ca3c80 100644
--- a/ffmpeg/libavformat/cavsvideodec.c
+++ b/ffmpeg/libavformat/cavsvideodec.c
@@ -61,7 +61,7 @@ static int cavsvideo_probe(AVProbeData *p)
}
}
if(seq && seq*9<=pic*10)
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
return 0;
}
diff --git a/ffmpeg/libavformat/cdxl.c b/ffmpeg/libavformat/cdxl.c
index 185b745..ab8a846 100644
--- a/ffmpeg/libavformat/cdxl.c
+++ b/ffmpeg/libavformat/cdxl.c
@@ -41,7 +41,7 @@ typedef struct CDXLDemuxContext {
static int cdxl_read_probe(AVProbeData *p)
{
- int score = AVPROBE_SCORE_MAX / 2 + 10;
+ int score = AVPROBE_SCORE_EXTENSION + 10;
if (p->buf_size < CDXL_HEADER_SIZE)
return 0;
diff --git a/ffmpeg/libavformat/concat.c b/ffmpeg/libavformat/concat.c
index f97354c..3bbc83d 100644
--- a/ffmpeg/libavformat/concat.c
+++ b/ffmpeg/libavformat/concat.c
@@ -56,7 +56,7 @@ static av_cold int concat_close(URLContext *h)
static av_cold int concat_open(URLContext *h, const char *uri, int flags)
{
- char *node_uri = NULL, *tmp_uri;
+ char *node_uri = NULL;
int err = 0;
int64_t size;
size_t len, i;
@@ -74,7 +74,7 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags)
return AVERROR(ENAMETOOLONG);
}
- if (!(nodes = av_malloc(sizeof(*nodes) * len))) {
+ if (!(nodes = av_realloc(NULL, sizeof(*nodes) * len))) {
return AVERROR(ENOMEM);
} else
data->nodes = nodes;
@@ -85,11 +85,8 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags)
for (i = 0; *uri; i++) {
/* parsing uri */
len = strcspn(uri, AV_CAT_SEPARATOR);
- if (!(tmp_uri = av_realloc(node_uri, len+1))) {
- err = AVERROR(ENOMEM);
+ if ((err = av_reallocp(&node_uri, len + 1)) < 0)
break;
- } else
- node_uri = tmp_uri;
av_strlcpy(node_uri, uri, len+1);
uri += len + strspn(uri+len, AV_CAT_SEPARATOR);
diff --git a/ffmpeg/libavformat/concatdec.c b/ffmpeg/libavformat/concatdec.c
index 5359ad1..86f82e0 100644
--- a/ffmpeg/libavformat/concatdec.c
+++ b/ffmpeg/libavformat/concatdec.c
@@ -23,6 +23,7 @@
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
+#include "url.h"
typedef struct {
char *url;
@@ -216,6 +217,8 @@ static int concat_read_header(AVFormatContext *avf)
}
if (ret < 0)
FAIL(ret);
+ if (!cat->nb_files)
+ FAIL(AVERROR_INVALIDDATA);
for (i = 0; i < cat->nb_files; i++) {
if (cat->files[i].start_time == AV_NOPTS_VALUE)
@@ -276,6 +279,9 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
(ret = open_next_file(avf)) < 0)
break;
}
+ if (ret < 0)
+ 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);
@@ -341,7 +347,7 @@ static int real_seek(AVFormatContext *avf, int stream,
return ret;
ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
- if (ret < 0 && !(flags & AVSEEK_FLAG_BACKWARD) &&
+ if (ret < 0 &&
left < cat->nb_files - 1 &&
cat->files[left + 1].start_time < max_ts) {
if ((ret = open_file(avf, left + 1)) < 0)
diff --git a/ffmpeg/libavformat/crypto.c b/ffmpeg/libavformat/crypto.c
index 5d518be..a9b6e47 100644
--- a/ffmpeg/libavformat/crypto.c
+++ b/ffmpeg/libavformat/crypto.c
@@ -2,20 +2,20 @@
* Decryption protocol handler
* Copyright (c) 2011 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/daud.c b/ffmpeg/libavformat/daud.c
index fb62ab1..6983785 100644
--- a/ffmpeg/libavformat/daud.c
+++ b/ffmpeg/libavformat/daud.c
@@ -68,7 +68,6 @@ static int daud_write_packet(struct AVFormatContext *s, AVPacket *pkt)
avio_wb16(s->pb, pkt->size);
avio_wb16(s->pb, 0x8010); // unknown
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/dfa.c b/ffmpeg/libavformat/dfa.c
index 8cf2f24..9cd13e2 100644
--- a/ffmpeg/libavformat/dfa.c
+++ b/ffmpeg/libavformat/dfa.c
@@ -28,6 +28,9 @@ static int dfa_probe(AVProbeData *p)
if (p->buf_size < 4 || AV_RL32(p->buf) != MKTAG('D', 'F', 'I', 'A'))
return 0;
+ if (AV_RL32(p->buf + 16) != 0x80)
+ return AVPROBE_SCORE_MAX / 4;
+
return AVPROBE_SCORE_MAX;
}
@@ -36,13 +39,15 @@ static int dfa_read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVStream *st;
int frames;
+ int version;
uint32_t mspf;
if (avio_rl32(pb) != MKTAG('D', 'F', 'I', 'A')) {
av_log(s, AV_LOG_ERROR, "Invalid magic for DFA\n");
return AVERROR_INVALIDDATA;
}
- avio_skip(pb, 2); // unused
+
+ version = avio_rl16(pb);
frames = avio_rl16(pb);
st = avformat_new_stream(s, NULL);
@@ -62,6 +67,12 @@ static int dfa_read_header(AVFormatContext *s)
avio_skip(pb, 128 - 16); // padding
st->duration = frames;
+ if (ff_alloc_extradata(st->codec, 2))
+ return AVERROR(ENOMEM);
+ AV_WL16(st->codec->extradata, version);
+ if (version == 0x100)
+ st->sample_aspect_ratio = (AVRational){2, 1};
+
return 0;
}
diff --git a/ffmpeg/libavformat/diracdec.c b/ffmpeg/libavformat/diracdec.c
index 6636ead..e061ba5 100644
--- a/ffmpeg/libavformat/diracdec.c
+++ b/ffmpeg/libavformat/diracdec.c
@@ -25,10 +25,19 @@
static int dirac_probe(AVProbeData *p)
{
- if (AV_RL32(p->buf) == MKTAG('B', 'B', 'C', 'D'))
- return AVPROBE_SCORE_MAX;
- else
+ unsigned size;
+ if (AV_RL32(p->buf) != MKTAG('B', 'B', 'C', 'D'))
return 0;
+
+ size = AV_RB32(p->buf+5);
+ if (size < 13)
+ return 0;
+ if (size + 13LL > p->buf_size)
+ return AVPROBE_SCORE_MAX / 4;
+ if (AV_RL32(p->buf + size) != MKTAG('B', 'B', 'C', 'D'))
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
}
FF_DEF_RAWVIDEO_DEMUXER(dirac, "raw Dirac", dirac_probe, NULL, AV_CODEC_ID_DIRAC)
diff --git a/ffmpeg/libavformat/dsicin.c b/ffmpeg/libavformat/dsicin.c
index b8ca57c..4a54680 100644
--- a/ffmpeg/libavformat/dsicin.c
+++ b/ffmpeg/libavformat/dsicin.c
@@ -155,6 +155,8 @@ static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) {
if (avio_rl32(pb) != 0xAA55AA55)
return AVERROR_INVALIDDATA;
+ if (hdr->video_frame_size < 0 || hdr->audio_frame_size < 0)
+ return AVERROR_INVALIDDATA;
return 0;
}
diff --git a/ffmpeg/libavformat/dtsdec.c b/ffmpeg/libavformat/dtsdec.c
index 5c05758..23cbe93 100644
--- a/ffmpeg/libavformat/dtsdec.c
+++ b/ffmpeg/libavformat/dtsdec.c
@@ -34,6 +34,7 @@ static int dts_probe(AVProbeData *p)
uint32_t state = -1;
int markers[3] = {0};
int sum, max;
+ int64_t diff = 0;
buf = p->buf;
@@ -54,13 +55,17 @@ static int dts_probe(AVProbeData *p)
if (state == DCA_MARKER_14B_LE)
if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
markers[2]++;
+
+ if (buf - p->buf >= 4)
+ diff += FFABS(AV_RL16(buf) - AV_RL16(buf-4));
}
sum = markers[0] + markers[1] + markers[2];
max = markers[1] > markers[0];
max = markers[2] > markers[max] ? 2 : max;
if (markers[max] > 3 && p->buf_size / markers[max] < 32*1024 &&
- markers[max] * 4 > sum * 3)
- return AVPROBE_SCORE_MAX/2+1;
+ markers[max] * 4 > sum * 3 &&
+ diff / p->buf_size > 200)
+ return AVPROBE_SCORE_EXTENSION + 1;
return 0;
}
diff --git a/ffmpeg/libavformat/dv.c b/ffmpeg/libavformat/dv.c
index a04735a..f972478 100644
--- a/ffmpeg/libavformat/dv.c
+++ b/ffmpeg/libavformat/dv.c
@@ -32,7 +32,7 @@
#include "avformat.h"
#include "internal.h"
#include "libavcodec/dv_profile.h"
-#include "libavcodec/dvdata.h"
+#include "libavcodec/dv.h"
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
@@ -65,7 +65,7 @@ static inline uint16_t dv_audio_12to16(uint16_t sample)
shift--;
result = (sample - (256 * shift)) << shift;
} else {
- shift = 0xe - shift;
+ shift = 0xe - shift;
result = ((sample + ((256 * shift) + 1)) << shift) - 1;
}
@@ -77,19 +77,19 @@ static inline uint16_t dv_audio_12to16(uint16_t sample)
* a fixed offset and if pack isn't there -- fails. We might want
* to have a fallback mechanism for complete search of missing packs.
*/
-static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t)
+static const uint8_t *dv_extract_pack(uint8_t *frame, enum dv_pack_type t)
{
int offs;
switch (t) {
case dv_audio_source:
- offs = (80*6 + 80*16*3 + 3);
+ offs = (80 * 6 + 80 * 16 * 3 + 3);
break;
case dv_audio_control:
- offs = (80*6 + 80*16*4 + 3);
+ offs = (80 * 6 + 80 * 16 * 4 + 3);
break;
case dv_video_control:
- offs = (80*5 + 48 + 5);
+ offs = (80 * 5 + 48 + 5);
break;
case dv_timecode:
offs = (80*1 + 3 + 3);
@@ -113,29 +113,29 @@ static const int dv_audio_frequency[3] = {
* 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
* are converted into 16bit linear ones.
*/
-static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4],
+static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
const DVprofile *sys)
{
int size, chan, i, j, d, of, smpls, freq, quant, half_ch;
uint16_t lc, rc;
- const uint8_t* as_pack;
+ const uint8_t *as_pack;
uint8_t *pcm, ipcm;
as_pack = dv_extract_pack(frame, dv_audio_source);
if (!as_pack) /* No audio ? */
return 0;
- smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
- freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
- quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
+ smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
+ freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
+ quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
if (quant > 1)
- return -1; /* unsupported quantization */
+ return -1; /* unsupported quantization */
if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency))
return AVERROR_INVALIDDATA;
- size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
+ size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
half_ch = sys->difseg_size / 2;
/* We work with 720p frames split in half, thus even frames have
@@ -169,32 +169,41 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4],
for (j = 0; j < 9; j++) {
for (d = 8; d < 80; d += 2) {
if (quant == 0) { /* 16bit quantization */
- of = sys->audio_shuffle[i][j] + (d - 8) / 2 * sys->audio_stride;
- if (of*2 >= size)
+ of = sys->audio_shuffle[i][j] +
+ (d - 8) / 2 * sys->audio_stride;
+ if (of * 2 >= size)
continue;
- pcm[of*2] = frame[d+1]; // FIXME: maybe we have to admit
- pcm[of*2+1] = frame[d]; // that DV is a big-endian PCM
- if (pcm[of*2+1] == 0x80 && pcm[of*2] == 0x00)
- pcm[of*2+1] = 0;
+ /* FIXME: maybe we have to admit that DV is a
+ * big-endian PCM */
+ pcm[of * 2] = frame[d + 1];
+ pcm[of * 2 + 1] = frame[d];
+
+ if (pcm[of * 2 + 1] == 0x80 && pcm[of * 2] == 0x00)
+ pcm[of * 2 + 1] = 0;
} else { /* 12bit quantization */
- lc = ((uint16_t)frame[d] << 4) |
- ((uint16_t)frame[d+2] >> 4);
- rc = ((uint16_t)frame[d+1] << 4) |
- ((uint16_t)frame[d+2] & 0x0f);
+ lc = ((uint16_t)frame[d] << 4) |
+ ((uint16_t)frame[d + 2] >> 4);
+ rc = ((uint16_t)frame[d + 1] << 4) |
+ ((uint16_t)frame[d + 2] & 0x0f);
lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc));
rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc));
- of = sys->audio_shuffle[i%half_ch][j] + (d - 8) / 3 * sys->audio_stride;
- if (of*2 >= size)
+ of = sys->audio_shuffle[i % half_ch][j] +
+ (d - 8) / 3 * sys->audio_stride;
+ if (of * 2 >= size)
continue;
- pcm[of*2] = lc & 0xff; // FIXME: maybe we have to admit
- pcm[of*2+1] = lc >> 8; // that DV is a big-endian PCM
- of = sys->audio_shuffle[i%half_ch+half_ch][j] +
- (d - 8) / 3 * sys->audio_stride;
- pcm[of*2] = rc & 0xff; // FIXME: maybe we have to admit
- pcm[of*2+1] = rc >> 8; // that DV is a big-endian PCM
+ /* FIXME: maybe we have to admit that DV is a
+ * big-endian PCM */
+ pcm[of * 2] = lc & 0xff;
+ pcm[of * 2 + 1] = lc >> 8;
+ of = sys->audio_shuffle[i % half_ch + half_ch][j] +
+ (d - 8) / 3 * sys->audio_stride;
+ /* FIXME: maybe we have to admit that DV is a
+ * big-endian PCM */
+ pcm[of * 2] = rc & 0xff;
+ pcm[of * 2 + 1] = rc >> 8;
++d;
}
}
@@ -207,9 +216,9 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4],
return size;
}
-static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame)
+static int dv_extract_audio_info(DVDemuxContext *c, uint8_t *frame)
{
- const uint8_t* as_pack;
+ const uint8_t *as_pack;
int freq, stype, smpls, quant, i, ach;
as_pack = dv_extract_pack(frame, dv_audio_source);
@@ -218,10 +227,10 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame)
return 0;
}
- smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
- freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
- stype = (as_pack[3] & 0x1f); /* 0 - 2CH, 2 - 4CH, 3 - 8CH */
- quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
+ smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
+ freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
+ stype = as_pack[3] & 0x1f; /* 0 - 2CH, 2 - 4CH, 3 - 8CH */
+ quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency)) {
av_log(c->fctx, AV_LOG_ERROR,
@@ -236,7 +245,7 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame)
}
/* note: ach counts PAIRS of channels (i.e. stereo channels) */
- ach = ((int[4]){ 1, 0, 2, 4})[stype];
+ ach = ((int[4]) { 1, 0, 2, 4 })[stype];
if (ach == 1 && quant && freq == 2)
ach = 2;
@@ -256,21 +265,21 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame)
c->audio_pkt[i].stream_index = c->ast[i]->index;
c->audio_pkt[i].flags |= AV_PKT_FLAG_KEY;
}
- c->ast[i]->codec->sample_rate = dv_audio_frequency[freq];
- c->ast[i]->codec->channels = 2;
+ c->ast[i]->codec->sample_rate = dv_audio_frequency[freq];
+ c->ast[i]->codec->channels = 2;
c->ast[i]->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16;
- c->ast[i]->start_time = 0;
+ c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16;
+ c->ast[i]->start_time = 0;
}
c->ach = i;
- return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */;
+ return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
}
-static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame)
+static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
{
- const uint8_t* vsc_pack;
- AVCodecContext* avctx;
+ const uint8_t *vsc_pack;
+ AVCodecContext *avctx;
int apt, is16_9;
int size = 0;
@@ -279,7 +288,7 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame)
avpriv_set_pts_info(c->vst, 64, c->sys->time_base.num,
c->sys->time_base.den);
- avctx->time_base= c->sys->time_base;
+ avctx->time_base = c->sys->time_base;
/* finding out SAR is a little bit messy */
vsc_pack = dv_extract_pack(frame, dv_video_control);
@@ -287,7 +296,8 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame)
is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 ||
(!apt && (vsc_pack[2] & 0x07) == 0x07)));
c->vst->sample_aspect_ratio = c->sys->sar[is16_9];
- avctx->bit_rate = av_rescale_q(c->sys->frame_size, (AVRational){8,1},
+ avctx->bit_rate = av_rescale_q(c->sys->frame_size,
+ (AVRational) { 8, 1 },
c->sys->time_base);
size = c->sys->frame_size;
}
@@ -310,11 +320,9 @@ static int dv_extract_timecode(DVDemuxContext* c, uint8_t* frame, char *tc)
return 1;
}
-/*
- * The following 3 functions constitute our interface to the world
- */
+/* The following 3 functions constitute our interface to the world */
-DVDemuxContext* avpriv_dv_init_demux(AVFormatContext *s)
+DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s)
{
DVDemuxContext *c;
@@ -344,9 +352,9 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt)
for (i = 0; i < c->ach; i++) {
if (c->ast[i] && c->audio_pkt[i].size) {
- *pkt = c->audio_pkt[i];
+ *pkt = c->audio_pkt[i];
c->audio_pkt[i].size = 0;
- size = pkt->size;
+ size = pkt->size;
break;
}
}
@@ -355,10 +363,10 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt)
}
int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
- uint8_t* buf, int buf_size, int64_t pos)
+ uint8_t *buf, int buf_size, int64_t pos)
{
int size, i;
- uint8_t *ppcm[4] = {0};
+ uint8_t *ppcm[5] = { 0 };
if (buf_size < DV_PROFILE_BYTES ||
!(c->sys = avpriv_dv_frame_profile(c->sys, buf, buf_size)) ||
@@ -372,7 +380,8 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
for (i = 0; i < c->ach; i++) {
c->audio_pkt[i].pos = pos;
c->audio_pkt[i].size = size;
- c->audio_pkt[i].pts = c->abytes * 30000 * 8 / c->ast[i]->codec->bit_rate;
+ c->audio_pkt[i].pts = c->abytes * 30000 * 8 /
+ c->ast[i]->codec->bit_rate;
ppcm[i] = c->audio_buf[i];
}
if (c->ach)
@@ -385,7 +394,7 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
} else {
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
- c->abytes += size;
+ c->abytes += size;
}
} else {
c->abytes += size;
@@ -407,30 +416,32 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
}
static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c,
- int64_t timestamp, int flags)
+ int64_t timestamp, int flags)
{
// FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk)
- const DVprofile* sys = avpriv_dv_codec_profile(c->vst->codec);
+ const DVprofile *sys = avpriv_dv_codec_profile(c->vst->codec);
int64_t offset;
- int64_t size = avio_size(s->pb) - s->data_offset;
- int64_t max_offset = ((size-1) / sys->frame_size) * sys->frame_size;
+ int64_t size = avio_size(s->pb) - s->data_offset;
+ int64_t max_offset = ((size - 1) / sys->frame_size) * sys->frame_size;
offset = sys->frame_size * timestamp;
- if (size >= 0 && offset > max_offset) offset = max_offset;
- else if (offset < 0) offset = 0;
+ if (size >= 0 && offset > max_offset)
+ offset = max_offset;
+ else if (offset < 0)
+ offset = 0;
return offset + s->data_offset;
}
void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
{
- c->frames= frame_offset;
+ c->frames = frame_offset;
if (c->ach) {
if (c->sys) {
- c->abytes= av_rescale_q(c->frames, c->sys->time_base,
- (AVRational){8, c->ast[0]->codec->bit_rate});
- }else
+ c->abytes = av_rescale_q(c->frames, c->sys->time_base,
+ (AVRational) { 8, c->ast[0]->codec->bit_rate });
+ } else
av_log(c->fctx, AV_LOG_ERROR, "cannot adjust audio bytes\n");
}
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
@@ -442,7 +453,7 @@ void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
************************************************************/
typedef struct RawDVContext {
- DVDemuxContext* dv_demux;
+ DVDemuxContext *dv_demux;
uint8_t buf[DV_MAX_FRAME_SIZE];
} RawDVContext;
@@ -508,13 +519,17 @@ static int dv_read_header(AVFormatContext *s)
avio_seek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0)
return AVERROR(EIO);
- c->dv_demux->sys = avpriv_dv_frame_profile(c->dv_demux->sys, c->buf, DV_PROFILE_BYTES);
+ c->dv_demux->sys = avpriv_dv_frame_profile(c->dv_demux->sys,
+ c->buf,
+ DV_PROFILE_BYTES);
if (!c->dv_demux->sys) {
- av_log(s, AV_LOG_ERROR, "Can't determine profile of DV input stream.\n");
+ av_log(s, AV_LOG_ERROR,
+ "Can't determine profile of DV input stream.\n");
return -1;
}
- s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size, (AVRational){8,1},
+ s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size,
+ (AVRational) { 8, 1 },
c->dv_demux->sys->time_base);
if (s->pb->seekable)
@@ -523,7 +538,6 @@ static int dv_read_header(AVFormatContext *s)
return 0;
}
-
static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int size;
@@ -546,7 +560,7 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
}
static int dv_read_seek(AVFormatContext *s, int stream_index,
- int64_t timestamp, int flags)
+ int64_t timestamp, int flags)
{
RawDVContext *r = s->priv_data;
DVDemuxContext *c = r->dv_demux;
@@ -568,33 +582,42 @@ static int dv_read_close(AVFormatContext *s)
static int dv_probe(AVProbeData *p)
{
- unsigned state, marker_pos = 0;
+ unsigned marker_pos = 0;
int i;
- int matches = 0;
+ int matches = 0;
+ int firstmatch = 0;
int secondary_matches = 0;
if (p->buf_size < 5)
return 0;
- state = AV_RB32(p->buf);
- for (i = 4; i < p->buf_size; i++) {
- if ((state & 0xffffff7f) == 0x1f07003f)
- matches++;
- // any section header, also with seq/chan num != 0,
- // should appear around every 12000 bytes, at least 10 per frame
- if ((state & 0xff07ff7f) == 0x1f07003f)
- secondary_matches++;
- if (state == 0x003f0700 || state == 0xff3f0700)
- marker_pos = i;
- if (state == 0xff3f0701 && i - marker_pos == 80)
- matches++;
- state = (state << 8) | p->buf[i];
+ for (i = 0; i < p->buf_size-4; i++) {
+ unsigned state = AV_RB32(p->buf+i);
+ if ((state & 0x0007f840) == 0x00070000) {
+ // any section header, also with seq/chan num != 0,
+ // should appear around every 12000 bytes, at least 10 per frame
+ if ((state & 0xff07ff7f) == 0x1f07003f) {
+ secondary_matches++;
+ if ((state & 0xffffff7f) == 0x1f07003f) {
+ matches++;
+ if (!i)
+ firstmatch = 1;
+ }
+ }
+ if (state == 0x003f0700 || state == 0xff3f0700)
+ marker_pos = i;
+ if (state == 0xff3f0701 && i - marker_pos == 80)
+ matches++;
+ }
}
- if (matches && p->buf_size / matches < 1024*1024) {
- if (matches > 4 || (secondary_matches >= 10 && p->buf_size / secondary_matches < 24000))
- return AVPROBE_SCORE_MAX*3/4; // not max to avoid dv in mov to match
- return AVPROBE_SCORE_MAX/4;
+ if (matches && p->buf_size / matches < 1024 * 1024) {
+ if (matches > 4 || firstmatch ||
+ (secondary_matches >= 10 &&
+ p->buf_size / secondary_matches < 24000))
+ // not max to avoid dv in mov to match
+ return AVPROBE_SCORE_MAX * 3 / 4;
+ return AVPROBE_SCORE_MAX / 4;
}
return 0;
}
diff --git a/ffmpeg/libavformat/dvenc.c b/ffmpeg/libavformat/dvenc.c
index 0b3811e..43f65c3 100644
--- a/ffmpeg/libavformat/dvenc.c
+++ b/ffmpeg/libavformat/dvenc.c
@@ -33,7 +33,7 @@
#include "avformat.h"
#include "internal.h"
#include "libavcodec/dv_profile.h"
-#include "libavcodec/dvdata.h"
+#include "libavcodec/dv.h"
#include "dv.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
@@ -390,7 +390,6 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt)
pkt->data, pkt->size, &frame);
if (fsize > 0) {
avio_write(s->pb, frame, fsize);
- avio_flush(s->pb);
}
return 0;
}
diff --git a/ffmpeg/libavformat/dxa.c b/ffmpeg/libavformat/dxa.c
index 22ee2a9..5b2d7c0 100644
--- a/ffmpeg/libavformat/dxa.c
+++ b/ffmpeg/libavformat/dxa.c
@@ -169,7 +169,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,7 +190,10 @@ 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);
diff --git a/ffmpeg/libavformat/electronicarts.c b/ffmpeg/libavformat/electronicarts.c
index cf7a271..4ba0fa0 100644
--- a/ffmpeg/libavformat/electronicarts.c
+++ b/ffmpeg/libavformat/electronicarts.c
@@ -30,35 +30,35 @@
#include "internal.h"
#define SCHl_TAG MKTAG('S', 'C', 'H', 'l')
-#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */
-#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */
-#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */
-#define SHEN_TAG MKTAG('S', 'H', 'E', 'N') /* SxEN header */
-#define SDEN_TAG MKTAG('S', 'D', 'E', 'N') /* SxEN data */
-#define SEEN_TAG MKTAG('S', 'E', 'E', 'N') /* SxEN end */
-#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */
+#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */
+#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */
+#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */
+#define SHEN_TAG MKTAG('S', 'H', 'E', 'N') /* SxEN header */
+#define SDEN_TAG MKTAG('S', 'D', 'E', 'N') /* SxEN data */
+#define SEEN_TAG MKTAG('S', 'E', 'E', 'N') /* SxEN end */
+#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */
#define EACS_TAG MKTAG('E', 'A', 'C', 'S')
-#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */
-#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */
+#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */
+#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */
#define PT00_TAG MKTAG('P', 'T', 0x0, 0x0)
#define GSTR_TAG MKTAG('G', 'S', 'T', 'R')
#define SCDl_TAG MKTAG('S', 'C', 'D', 'l')
#define SCEl_TAG MKTAG('S', 'C', 'E', 'l')
-#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV i-frame */
-#define fVGT_TAG MKTAG('f', 'V', 'G', 'T') /* TGV p-frame */
-#define mTCD_TAG MKTAG('m', 'T', 'C', 'D') /* MDEC */
-#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD i-frame */
-#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD p-frame */
-#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */
-#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG2 */
-#define TGQs_TAG MKTAG('T', 'G', 'Q', 's') /* TGQ i-frame (appears in .TGQ files) */
-#define pQGT_TAG MKTAG('p', 'Q', 'G', 'T') /* TGQ i-frame (appears in .UV files) */
-#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') /* TQI/UV2 i-frame (.UV2/.WVE) */
+#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV I-frame */
+#define fVGT_TAG MKTAG('f', 'V', 'G', 'T') /* TGV P-frame */
+#define mTCD_TAG MKTAG('m', 'T', 'C', 'D') /* MDEC */
+#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD I-frame */
+#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD P-frame */
+#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */
+#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG-2 */
+#define TGQs_TAG MKTAG('T', 'G', 'Q', 's') /* TGQ I-frame (appears in .TGQ files) */
+#define pQGT_TAG MKTAG('p', 'Q', 'G', 'T') /* TGQ I-frame (appears in .UV files) */
+#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') /* TQI/UV2 I-frame (.UV2/.WVE) */
#define MVhd_TAG MKTAG('M', 'V', 'h', 'd')
#define MV0K_TAG MKTAG('M', 'V', '0', 'K')
#define MV0F_TAG MKTAG('M', 'V', '0', 'F')
-#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */
-#define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV i-frame */
+#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */
+#define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV I-frame */
typedef struct EaDemuxContext {
int big_endian;
@@ -78,7 +78,8 @@ typedef struct EaDemuxContext {
int num_samples;
} EaDemuxContext;
-static uint32_t read_arbitary(AVIOContext *pb) {
+static uint32_t read_arbitrary(AVIOContext *pb)
+{
uint8_t size, byte;
int i;
uint32_t word;
@@ -87,108 +88,135 @@ static uint32_t read_arbitary(AVIOContext *pb) {
word = 0;
for (i = 0; i < size; i++) {
- byte = avio_r8(pb);
+ byte = avio_r8(pb);
word <<= 8;
- word |= byte;
+ word |= byte;
}
return word;
}
-/*
- * Process PT/GSTR sound header
- * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx
- */
static int process_audio_header_elements(AVFormatContext *s)
{
- int inHeader = 1;
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
+ int in_header = 1;
int compression_type = -1, revision = -1, revision2 = -1;
- ea->bytes = 2;
- ea->sample_rate = -1;
+ ea->bytes = 2;
+ ea->sample_rate = -1;
ea->num_channels = 1;
- while (!url_feof(pb) && inHeader) {
- int inSubheader;
+ while (!url_feof(pb) && in_header) {
+ int in_subheader;
uint8_t byte;
byte = avio_r8(pb);
switch (byte) {
case 0xFD:
- av_log (s, AV_LOG_DEBUG, "entered audio subheader\n");
- inSubheader = 1;
- while (!url_feof(pb) && inSubheader) {
+ av_log(s, AV_LOG_DEBUG, "entered audio subheader\n");
+ in_subheader = 1;
+ while (!url_feof(pb) && in_subheader) {
uint8_t subbyte;
subbyte = avio_r8(pb);
switch (subbyte) {
case 0x80:
- revision = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "revision (element 0x80) set to 0x%08x\n", revision);
+ revision = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "revision (element 0x80) set to 0x%08x\n", revision);
break;
case 0x82:
- ea->num_channels = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "num_channels (element 0x82) set to 0x%08x\n", ea->num_channels);
+ ea->num_channels = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "num_channels (element 0x82) set to 0x%08x\n",
+ ea->num_channels);
break;
case 0x83:
- compression_type = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "compression_type (element 0x83) set to 0x%08x\n", compression_type);
+ compression_type = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "compression_type (element 0x83) set to 0x%08x\n",
+ compression_type);
break;
case 0x84:
- ea->sample_rate = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "sample_rate (element 0x84) set to %i\n", ea->sample_rate);
+ ea->sample_rate = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "sample_rate (element 0x84) set to %i\n",
+ ea->sample_rate);
break;
case 0x85:
- ea->num_samples = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "num_samples (element 0x85) set to 0x%08x\n", ea->num_samples);
+ ea->num_samples = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "num_samples (element 0x85) set to 0x%08x\n",
+ ea->num_samples);
break;
case 0x8A:
- av_log (s, AV_LOG_DEBUG, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb));
- av_log (s, AV_LOG_DEBUG, "exited audio subheader\n");
- inSubheader = 0;
+ av_log(s, AV_LOG_DEBUG,
+ "element 0x%02x set to 0x%08x\n",
+ subbyte, read_arbitrary(pb));
+ av_log(s, AV_LOG_DEBUG, "exited audio subheader\n");
+ in_subheader = 0;
break;
case 0xA0:
- revision2 = read_arbitary(pb);
- av_log (s, AV_LOG_DEBUG, "revision2 (element 0xA0) set to 0x%08x\n", revision2);
+ revision2 = read_arbitrary(pb);
+ av_log(s, AV_LOG_DEBUG,
+ "revision2 (element 0xA0) set to 0x%08x\n",
+ revision2);
break;
case 0xFF:
- av_log (s, AV_LOG_DEBUG, "end of header block reached (within audio subheader)\n");
- inSubheader = 0;
- inHeader = 0;
+ av_log(s, AV_LOG_DEBUG,
+ "end of header block reached (within audio subheader)\n");
+ in_subheader = 0;
+ in_header = 0;
break;
default:
- av_log (s, AV_LOG_DEBUG, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb));
+ av_log(s, AV_LOG_DEBUG,
+ "element 0x%02x set to 0x%08x\n",
+ subbyte, read_arbitrary(pb));
break;
}
}
break;
case 0xFF:
- av_log (s, AV_LOG_DEBUG, "end of header block reached\n");
- inHeader = 0;
+ av_log(s, AV_LOG_DEBUG, "end of header block reached\n");
+ in_header = 0;
break;
default:
- av_log (s, AV_LOG_DEBUG, "header element 0x%02x set to 0x%08x\n", byte, read_arbitary(pb));
+ av_log(s, AV_LOG_DEBUG,
+ "header element 0x%02x set to 0x%08x\n",
+ byte, read_arbitrary(pb));
break;
}
}
switch (compression_type) {
- case 0: ea->audio_codec = AV_CODEC_ID_PCM_S16LE; break;
- case 7: ea->audio_codec = AV_CODEC_ID_ADPCM_EA; break;
+ case 0:
+ ea->audio_codec = AV_CODEC_ID_PCM_S16LE;
+ break;
+ case 7:
+ ea->audio_codec = AV_CODEC_ID_ADPCM_EA;
+ break;
case -1:
switch (revision) {
- case 1: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1; break;
- case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; break;
- case 3: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3; break;
- case -1: break;
+ case 1:
+ ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1;
+ break;
+ case 2:
+ ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2;
+ break;
+ case 3:
+ ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3;
+ break;
+ case -1:
+ break;
default:
avpriv_request_sample(s, "stream type; revision=%i", revision);
return 0;
}
switch (revision2) {
- case 8: ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR; break;
+ case 8:
+ ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR;
+ break;
case 10:
switch (revision) {
case -1:
@@ -199,8 +227,11 @@ static int process_audio_header_elements(AVFormatContext *s)
return 0;
}
break;
- case 16: ea->audio_codec = AV_CODEC_ID_MP3; break;
- case -1: break;
+ case 16:
+ ea->audio_codec = AV_CODEC_ID_MP3;
+ break;
+ case -1:
+ break;
default:
ea->audio_codec = AV_CODEC_ID_NONE;
avpriv_request_sample(s, "stream type; revision2=%i", revision2);
@@ -208,24 +239,22 @@ static int process_audio_header_elements(AVFormatContext *s)
}
break;
default:
- avpriv_request_sample(s, "stream type; compression_type=%i", compression_type);
+ avpriv_request_sample(s,
+ "stream type; compression_type=%i",
+ compression_type);
return 0;
}
if (ea->sample_rate == -1)
- ea->sample_rate = revision==3 ? 48000 : 22050;
+ ea->sample_rate = revision == 3 ? 48000 : 22050;
return 1;
}
-/*
- * Process EACS sound header
- * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx
- */
-static int process_audio_header_eacs(AVFormatContext *s)
+static void process_audio_header_eacs(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
int compression_type;
ea->sample_rate = ea->big_endian ? avio_rb32(pb) : avio_rl32(pb);
@@ -237,64 +266,70 @@ static int process_audio_header_eacs(AVFormatContext *s)
switch (compression_type) {
case 0:
switch (ea->bytes) {
- case 1: ea->audio_codec = AV_CODEC_ID_PCM_S8; break;
- case 2: ea->audio_codec = AV_CODEC_ID_PCM_S16LE; break;
+ case 1:
+ ea->audio_codec = AV_CODEC_ID_PCM_S8;
+ break;
+ case 2:
+ ea->audio_codec = AV_CODEC_ID_PCM_S16LE;
+ break;
}
break;
- case 1: ea->audio_codec = AV_CODEC_ID_PCM_MULAW; ea->bytes = 1; break;
- case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS; break;
+ case 1:
+ ea->audio_codec = AV_CODEC_ID_PCM_MULAW;
+ ea->bytes = 1;
+ break;
+ case 2:
+ ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS;
+ break;
default:
- avpriv_request_sample(s, "stream type; audio compression_type=%i", compression_type);
+ avpriv_request_sample(s,
+ "stream type; audio compression_type=%i",
+ compression_type);
}
-
- return 1;
}
-/*
- * Process SEAD sound header
- * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx
- */
-static int process_audio_header_sead(AVFormatContext *s)
+static void process_audio_header_sead(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
ea->sample_rate = avio_rl32(pb);
ea->bytes = avio_rl32(pb); /* 1=8-bit, 2=16-bit */
ea->num_channels = avio_rl32(pb);
ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_SEAD;
-
- return 1;
}
-static int process_video_header_mdec(AVFormatContext *s)
+static void process_video_header_mdec(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
avio_skip(pb, 4);
- ea->width = avio_rl16(pb);
- ea->height = avio_rl16(pb);
- ea->time_base = (AVRational){1,15};
+ ea->width = avio_rl16(pb);
+ ea->height = avio_rl16(pb);
+ ea->time_base = (AVRational) { 1, 15 };
ea->video_codec = AV_CODEC_ID_MDEC;
- return 1;
}
static int process_video_header_vp6(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
avio_skip(pb, 8);
ea->nb_frames = avio_rl32(pb);
avio_skip(pb, 4);
ea->time_base.den = avio_rl32(pb);
ea->time_base.num = avio_rl32(pb);
- ea->video_codec = AV_CODEC_ID_VP6;
+ if (ea->time_base.den <= 0 || ea->time_base.num <= 0) {
+ av_log(s, AV_LOG_ERROR, "Timebase is invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+ ea->video_codec = AV_CODEC_ID_VP6;
return 1;
}
-static int process_video_header_cmv(AVFormatContext *s)
+static void process_video_header_cmv(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
int fps;
@@ -302,90 +337,92 @@ static int process_video_header_cmv(AVFormatContext *s)
avio_skip(s->pb, 10);
fps = avio_rl16(s->pb);
if (fps)
- ea->time_base = (AVRational){1, fps};
+ ea->time_base = (AVRational) { 1, fps };
ea->video_codec = AV_CODEC_ID_CMV;
-
- return 0;
}
-/*
- * Process EA file header
- * Returns 1 if the EA file is valid and successfully opened, 0 otherwise
- */
-static int process_ea_header(AVFormatContext *s) {
+/* Process EA file header.
+ * Return 1 if the EA file is valid and successfully opened, 0 otherwise. */
+static int process_ea_header(AVFormatContext *s)
+{
uint32_t blockid, size = 0;
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVIOContext *pb = s->pb;
int i;
- for (i=0; i<5 && (!ea->audio_codec || !ea->video_codec); i++) {
- unsigned int startpos = avio_tell(pb);
- int err = 0;
+ for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) {
+ uint64_t startpos = avio_tell(pb);
+ int err = 0;
blockid = avio_rl32(pb);
- size = 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);
+ if (size < 8) {
+ av_log(s, AV_LOG_ERROR, "chunk size too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
switch (blockid) {
- case ISNh_TAG:
- if (avio_rl32(pb) != EACS_TAG) {
- avpriv_request_sample(s, "unknown 1SNh headerid");
- return 0;
- }
- err = process_audio_header_eacs(s);
- break;
+ case ISNh_TAG:
+ if (avio_rl32(pb) != EACS_TAG) {
+ avpriv_request_sample(s, "unknown 1SNh headerid");
+ return 0;
+ }
+ process_audio_header_eacs(s);
+ break;
- case SCHl_TAG :
- case SHEN_TAG :
- blockid = avio_rl32(pb);
- if (blockid == GSTR_TAG) {
- avio_skip(pb, 4);
- } else if ((blockid & 0xFFFF)!=PT00_TAG) {
- avpriv_request_sample(s, "unknown SCHl headerid");
- return 0;
- }
- err = process_audio_header_elements(s);
- break;
+ case SCHl_TAG:
+ case SHEN_TAG:
+ blockid = avio_rl32(pb);
+ if (blockid == GSTR_TAG) {
+ avio_skip(pb, 4);
+ } else if ((blockid & 0xFFFF) != PT00_TAG) {
+ avpriv_request_sample(s, "unknown SCHl headerid");
+ return 0;
+ }
+ err = process_audio_header_elements(s);
+ break;
- case SEAD_TAG:
- err = process_audio_header_sead(s);
- break;
+ case SEAD_TAG:
+ process_audio_header_sead(s);
+ break;
- case MVIh_TAG :
- err = process_video_header_cmv(s);
- break;
+ case MVIh_TAG:
+ process_video_header_cmv(s);
+ break;
- case kVGT_TAG:
- ea->video_codec = AV_CODEC_ID_TGV;
- break;
+ case kVGT_TAG:
+ ea->video_codec = AV_CODEC_ID_TGV;
+ break;
- case mTCD_TAG :
- err = process_video_header_mdec(s);
- break;
+ case mTCD_TAG:
+ process_video_header_mdec(s);
+ break;
- case MPCh_TAG:
- ea->video_codec = AV_CODEC_ID_MPEG2VIDEO;
- break;
+ case MPCh_TAG:
+ ea->video_codec = AV_CODEC_ID_MPEG2VIDEO;
+ break;
- case pQGT_TAG:
- case TGQs_TAG:
- ea->video_codec = AV_CODEC_ID_TGQ;
- break;
+ case pQGT_TAG:
+ case TGQs_TAG:
+ ea->video_codec = AV_CODEC_ID_TGQ;
+ break;
- case pIQT_TAG:
- ea->video_codec = AV_CODEC_ID_TQI;
- break;
+ case pIQT_TAG:
+ ea->video_codec = AV_CODEC_ID_TQI;
+ break;
- case MADk_TAG :
- ea->video_codec = AV_CODEC_ID_MAD;
- break;
+ case MADk_TAG:
+ ea->video_codec = AV_CODEC_ID_MAD;
+ break;
- case MVhd_TAG :
- err = process_video_header_vp6(s);
- break;
+ case MVhd_TAG:
+ err = process_video_header_vp6(s);
+ break;
}
if (err < 0) {
@@ -401,9 +438,10 @@ static int process_ea_header(AVFormatContext *s) {
return 1;
}
-
static int ea_probe(AVProbeData *p)
{
+ unsigned big_endian, size;
+
switch (AV_RL32(&p->buf[0])) {
case ISNh_TAG:
case SCHl_TAG:
@@ -418,8 +456,13 @@ static int ea_probe(AVProbeData *p)
default:
return 0;
}
- if (AV_RL32(&p->buf[4]) > 0xfffff && AV_RB32(&p->buf[4]) > 0xfffff)
+ size = AV_RL32(&p->buf[4]);
+ big_endian = size > 0x000FFFFF;
+ if (big_endian)
+ size = av_bswap32(size);
+ if (size > 0xfffff || size < 8)
return 0;
+
return AVPROBE_SCORE_MAX;
}
@@ -437,34 +480,37 @@ static int ea_read_header(AVFormatContext *s)
if (!st)
return AVERROR(ENOMEM);
ea->video_stream_index = st->index;
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = ea->video_codec;
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = ea->video_codec;
// parsing is necessary to make FFmpeg generate correct timestamps
if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
- st->codec->codec_tag = 0; /* no fourcc */
- st->codec->width = ea->width;
- st->codec->height = ea->height;
- st->duration = st->nb_frames = ea->nb_frames;
+ st->codec->codec_tag = 0; /* no fourcc */
+ st->codec->width = ea->width;
+ st->codec->height = ea->height;
+ st->duration = st->nb_frames = ea->nb_frames;
if (ea->time_base.num)
avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den);
- st->r_frame_rate =
- st->avg_frame_rate = av_inv_q(ea->time_base);
+ st->r_frame_rate =
+ st->avg_frame_rate = av_inv_q(ea->time_base);
}
if (ea->audio_codec) {
- if (ea->num_channels <= 0) {
- av_log(s, AV_LOG_WARNING, "Unsupported number of channels: %d\n", ea->num_channels);
+ if (ea->num_channels <= 0 || ea->num_channels > 2) {
+ av_log(s, AV_LOG_WARNING,
+ "Unsupported number of channels: %d\n", ea->num_channels);
ea->audio_codec = 0;
return 1;
}
if (ea->sample_rate <= 0) {
- av_log(s, AV_LOG_ERROR, "Unsupported sample rate: %d\n", ea->sample_rate);
+ av_log(s, AV_LOG_ERROR,
+ "Unsupported sample rate: %d\n", ea->sample_rate);
ea->audio_codec = 0;
return 1;
}
if (ea->bytes <= 0) {
- av_log(s, AV_LOG_ERROR, "Invalid number of bytes per sample: %d\n", ea->bytes);
+ av_log(s, AV_LOG_ERROR,
+ "Invalid number of bytes per sample: %d\n", ea->bytes);
ea->audio_codec = AV_CODEC_ID_NONE;
return 1;
}
@@ -474,32 +520,31 @@ static int ea_read_header(AVFormatContext *s)
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 33, 1, ea->sample_rate);
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = ea->audio_codec;
- st->codec->codec_tag = 0; /* no tag */
- st->codec->channels = ea->num_channels;
- st->codec->sample_rate = ea->sample_rate;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = ea->audio_codec;
+ st->codec->codec_tag = 0; /* no tag */
+ st->codec->channels = ea->num_channels;
+ st->codec->sample_rate = ea->sample_rate;
st->codec->bits_per_coded_sample = ea->bytes * 8;
- st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
- st->codec->bits_per_coded_sample / 4;
- st->codec->block_align = st->codec->channels*st->codec->bits_per_coded_sample;
- ea->audio_stream_index = st->index;
- st->start_time = 0;
+ st->codec->bit_rate = st->codec->channels *
+ st->codec->sample_rate *
+ st->codec->bits_per_coded_sample / 4;
+ st->codec->block_align = st->codec->channels *
+ st->codec->bits_per_coded_sample;
+ ea->audio_stream_index = st->index;
+ st->start_time = 0;
}
return 1;
}
-static int ea_read_packet(AVFormatContext *s,
- AVPacket *pkt)
+static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
{
EaDemuxContext *ea = s->priv_data;
- AVIOContext *pb = s->pb;
- int ret = 0;
- int packet_read = 0;
+ AVIOContext *pb = s->pb;
int partial_packet = 0;
unsigned int chunk_type, chunk_size;
- int key = 0;
+ int ret = 0, packet_read = 0, key = 0;
int av_uninit(num_samples);
while (!packet_read || partial_packet) {
@@ -512,7 +557,7 @@ static int ea_read_packet(AVFormatContext *s,
switch (chunk_type) {
/* audio data */
case ISNh_TAG:
- /* header chunk also contains data; skip over the header portion*/
+ /* header chunk also contains data; skip over the header portion */
if (chunk_size < 32)
return AVERROR_INVALIDDATA;
avio_skip(pb, 32);
@@ -545,12 +590,16 @@ static int ea_read_packet(AVFormatContext *s,
case AV_CODEC_ID_ADPCM_EA_R1:
case AV_CODEC_ID_ADPCM_EA_R2:
case AV_CODEC_ID_ADPCM_IMA_EA_EACS:
- if (pkt->size >= 4)
- pkt->duration = AV_RL32(pkt->data);
- break;
case AV_CODEC_ID_ADPCM_EA_R3:
- if (pkt->size >= 4)
+ if (pkt->size < 4) {
+ av_log(s, AV_LOG_ERROR, "Packet is too short\n");
+ av_free_packet(pkt);
+ return AVERROR_INVALIDDATA;
+ }
+ if (ea->audio_codec == AV_CODEC_ID_ADPCM_EA_R3)
pkt->duration = AV_RB32(pkt->data);
+ else
+ pkt->duration = AV_RL32(pkt->data);
break;
case AV_CODEC_ID_ADPCM_IMA_EA_SEAD:
pkt->duration = ret * 2 / ea->num_channels;
@@ -572,7 +621,7 @@ static int ea_read_packet(AVFormatContext *s,
case SCEl_TAG:
case SEND_TAG:
case SEEN_TAG:
- ret = AVERROR(EIO);
+ ret = AVERROR(EIO);
packet_read = 1;
break;
@@ -586,12 +635,12 @@ static int ea_read_packet(AVFormatContext *s,
case fVGT_TAG:
case MADm_TAG:
case MADe_TAG:
- avio_seek(pb, -8, SEEK_CUR); // include chunk preamble
+ avio_seek(pb, -8, SEEK_CUR); // include chunk preamble
chunk_size += 8;
goto get_video_packet;
case mTCD_TAG:
- avio_skip(pb, 8); // skip ea dct header
+ avio_skip(pb, 8); // skip ea DCT header
chunk_size -= 8;
goto get_video_packet;
@@ -611,8 +660,8 @@ get_video_packet:
}
partial_packet = chunk_type == MVIh_TAG;
pkt->stream_index = ea->video_stream_index;
- pkt->flags |= key;
- packet_read = 1;
+ pkt->flags |= key;
+ packet_read = 1;
break;
default:
diff --git a/ffmpeg/libavformat/ffmdec.c b/ffmpeg/libavformat/ffmdec.c
index 02cf790..9d89b16 100644
--- a/ffmpeg/libavformat/ffmdec.c
+++ b/ffmpeg/libavformat/ffmdec.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "avformat.h"
@@ -278,11 +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) {
- codec->extradata_size = avio_rb32(pb);
- codec->extradata = av_malloc(codec->extradata_size);
- if (!codec->extradata)
+ 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,11 +467,8 @@ static int ffm_read_header(AVFormatContext *s)
goto fail;
}
if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
- codec->extradata_size = avio_rb32(pb);
- codec->extradata = av_malloc(codec->extradata_size);
- if (!codec->extradata)
+ if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, codec->extradata, codec->extradata_size);
}
}
diff --git a/ffmpeg/libavformat/ffmenc.c b/ffmpeg/libavformat/ffmenc.c
index 522945e..eb809eb 100644
--- a/ffmpeg/libavformat/ffmenc.c
+++ b/ffmpeg/libavformat/ffmenc.c
@@ -277,4 +277,5 @@ AVOutputFormat ff_ffm_muxer = {
.write_header = ffm_write_header,
.write_packet = ffm_write_packet,
.write_trailer = ffm_write_trailer,
+ .flags = AVFMT_TS_NEGATIVE,
};
diff --git a/ffmpeg/libavformat/ffmetadec.c b/ffmpeg/libavformat/ffmetadec.c
index 4bdc98a..19c14e4 100644
--- a/ffmpeg/libavformat/ffmetadec.c
+++ b/ffmpeg/libavformat/ffmetadec.c
@@ -135,7 +135,7 @@ static int read_header(AVFormatContext *s)
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = AV_CODEC_ID_FFMETADATA;
@@ -145,7 +145,7 @@ static int read_header(AVFormatContext *s)
AVChapter *ch = read_chapter(s);
if (!ch)
- return -1;
+ return AVERROR(ENOMEM);
m = &ch->metadata;
} else
diff --git a/ffmpeg/libavformat/file.c b/ffmpeg/libavformat/file.c
index e09a64b..2defc75 100644
--- a/ffmpeg/libavformat/file.c
+++ b/ffmpeg/libavformat/file.c
@@ -20,6 +20,7 @@
*/
#include "libavutil/avstring.h"
+#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avformat.h"
#include <fcntl.h>
@@ -49,10 +50,17 @@ typedef struct FileContext {
const AVClass *class;
int fd;
int trunc;
+ int blocksize;
} 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 },
+ { "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 }
+};
+
+static const AVOption pipe_options[] = {
+ { "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 }
};
@@ -63,17 +71,28 @@ static const AVClass file_class = {
.version = LIBAVUTIL_VERSION_INT,
};
+static const AVClass pipe_class = {
+ .class_name = "pipe",
+ .item_name = av_default_item_name,
+ .option = pipe_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static int file_read(URLContext *h, unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
- int r = read(c->fd, buf, size);
+ int r;
+ size = FFMIN(size, c->blocksize);
+ r = read(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
static int file_write(URLContext *h, const unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
- int r = write(c->fd, buf, size);
+ int r;
+ size = FFMIN(size, c->blocksize);
+ r = write(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
@@ -132,7 +151,7 @@ static int file_open(URLContext *h, const char *filename, int flags)
#ifdef O_BINARY
access |= O_BINARY;
#endif
- fd = open(filename, access, 0666);
+ fd = avpriv_open(filename, access, 0666);
if (fd == -1)
return AVERROR(errno);
c->fd = fd;
@@ -213,6 +232,7 @@ URLProtocol ff_pipe_protocol = {
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.priv_data_size = sizeof(FileContext),
+ .priv_data_class = &pipe_class,
};
#endif /* CONFIG_PIPE_PROTOCOL */
diff --git a/ffmpeg/libavformat/flacdec.c b/ffmpeg/libavformat/flacdec.c
index d5aacfd..29310b8 100644
--- a/ffmpeg/libavformat/flacdec.c
+++ b/ffmpeg/libavformat/flacdec.c
@@ -21,139 +21,13 @@
#include "libavcodec/flac.h"
#include "avformat.h"
-#include "id3v2.h"
+#include "flac_picture.h"
#include "internal.h"
#include "rawdec.h"
#include "oggdec.h"
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
-#define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0)
-
-static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
-{
- const CodecMime *mime = ff_id3v2_mime_tags;
- enum AVCodecID id = AV_CODEC_ID_NONE;
- AVBufferRef *data = NULL;
- uint8_t mimetype[64], *desc = NULL;
- AVIOContext *pb = NULL;
- AVStream *st;
- int type, width, height;
- int len, ret = 0;
-
- pb = avio_alloc_context(buf, buf_size, 0, NULL, NULL, NULL, NULL);
- if (!pb)
- return AVERROR(ENOMEM);
-
- /* read the picture type */
- type = avio_rb32(pb);
- if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) {
- av_log(s, AV_LOG_ERROR, "Invalid picture type: %d.\n", type);
- if (s->error_recognition & AV_EF_EXPLODE) {
- RETURN_ERROR(AVERROR_INVALIDDATA);
- }
- type = 0;
- }
-
- /* picture mimetype */
- len = avio_rb32(pb);
- if (len <= 0 ||
- avio_read(pb, mimetype, FFMIN(len, sizeof(mimetype) - 1)) != len) {
- av_log(s, AV_LOG_ERROR, "Could not read mimetype from an attached "
- "picture.\n");
- if (s->error_recognition & AV_EF_EXPLODE)
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- mimetype[len] = 0;
-
- while (mime->id != AV_CODEC_ID_NONE) {
- if (!strncmp(mime->str, mimetype, sizeof(mimetype))) {
- id = mime->id;
- break;
- }
- mime++;
- }
- if (id == AV_CODEC_ID_NONE) {
- av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n",
- mimetype);
- if (s->error_recognition & AV_EF_EXPLODE)
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
-
- /* picture description */
- len = avio_rb32(pb);
- if (len > 0) {
- if (!(desc = av_malloc(len + 1))) {
- RETURN_ERROR(AVERROR(ENOMEM));
- }
-
- if (avio_read(pb, desc, len) != len) {
- av_log(s, AV_LOG_ERROR, "Error reading attached picture description.\n");
- if (s->error_recognition & AV_EF_EXPLODE)
- ret = AVERROR(EIO);
- goto fail;
- }
- desc[len] = 0;
- }
-
- /* picture metadata */
- width = avio_rb32(pb);
- height = avio_rb32(pb);
- avio_skip(pb, 8);
-
- /* picture data */
- len = avio_rb32(pb);
- if (len <= 0) {
- av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len);
- if (s->error_recognition & AV_EF_EXPLODE)
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- if (!(data = av_buffer_alloc(len))) {
- RETURN_ERROR(AVERROR(ENOMEM));
- }
- 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)
- ret = AVERROR(EIO);
- goto fail;
- }
-
- st = avformat_new_stream(s, NULL);
- if (!st) {
- RETURN_ERROR(AVERROR(ENOMEM));
- }
-
- av_init_packet(&st->attached_pic);
- st->attached_pic.buf = data;
- st->attached_pic.data = data->data;
- st->attached_pic.size = len;
- st->attached_pic.stream_index = st->index;
- st->attached_pic.flags |= AV_PKT_FLAG_KEY;
-
- st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = id;
- st->codec->width = width;
- st->codec->height = height;
- av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0);
- if (desc)
- av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL);
-
- av_freep(&pb);
-
- return 0;
-
-fail:
- av_buffer_unref(&data);
- av_freep(&desc);
- av_freep(&pb);
- return ret;
-
-}
-
static int flac_read_header(AVFormatContext *s)
{
int ret, metadata_last=0, metadata_type, metadata_size, found_streaminfo=0;
@@ -248,7 +122,7 @@ static int flac_read_header(AVFormatContext *s)
}
av_freep(&buffer);
} else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) {
- ret = parse_picture(s, buffer, metadata_size);
+ ret = ff_flac_parse_picture(s, buffer, metadata_size);
av_freep(&buffer);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Error parsing attached picture.\n");
@@ -280,7 +154,7 @@ static int flac_probe(AVProbeData *p)
{
if (p->buf_size < 4 || memcmp(p->buf, "fLaC", 4))
return 0;
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
AVInputFormat ff_flac_demuxer = {
diff --git a/ffmpeg/libavformat/flacenc.c b/ffmpeg/libavformat/flacenc.c
index b625278..87e9362 100644
--- a/ffmpeg/libavformat/flacenc.c
+++ b/ffmpeg/libavformat/flacenc.c
@@ -21,6 +21,7 @@
#include "libavcodec/flac.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "flacenc.h"
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
@@ -31,10 +32,7 @@ static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_byte
{
avio_w8(pb, last_block ? 0x81 : 0x01);
avio_wb24(pb, n_padding_bytes);
- while (n_padding_bytes > 0) {
- avio_w8(pb, 0);
- n_padding_bytes--;
- }
+ ffio_fill(pb, 0, n_padding_bytes);
return 0;
}
@@ -122,7 +120,6 @@ static int flac_write_trailer(struct AVFormatContext *s)
static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/flic.c b/ffmpeg/libavformat/flic.c
index 8d49116..7235f2e 100644
--- a/ffmpeg/libavformat/flic.c
+++ b/ffmpeg/libavformat/flic.c
@@ -80,7 +80,7 @@ static int flic_probe(AVProbeData *p)
return 0;
- return AVPROBE_SCORE_MAX;
+ return AVPROBE_SCORE_MAX - 1;
}
static int flic_read_header(AVFormatContext *s)
@@ -125,8 +125,8 @@ static int flic_read_header(AVFormatContext *s)
}
/* send over the whole 128-byte FLIC header */
- st->codec->extradata_size = FLIC_HEADER_SIZE;
- st->codec->extradata = av_malloc(FLIC_HEADER_SIZE);
+ if (ff_alloc_extradata(st->codec, FLIC_HEADER_SIZE))
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE);
/* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */
@@ -176,8 +176,8 @@ static int flic_read_header(AVFormatContext *s)
/* send over abbreviated FLIC header chunk */
av_free(st->codec->extradata);
- st->codec->extradata_size = 12;
- st->codec->extradata = av_malloc(12);
+ if (ff_alloc_extradata(st->codec, 12))
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, header, 12);
} else if (magic_number == FLIC_FILE_MAGIC_1) {
diff --git a/ffmpeg/libavformat/flvdec.c b/ffmpeg/libavformat/flvdec.c
index d0511f1..5683ed5 100644
--- a/ffmpeg/libavformat/flvdec.c
+++ b/ffmpeg/libavformat/flvdec.c
@@ -41,12 +41,12 @@
typedef struct {
const AVClass *class; ///< Class for private options.
- int trust_metadata; ///< configure streams according onMetaData
- int wrong_dts; ///< wrong dts due to negative cts
+ int trust_metadata; ///< configure streams according onMetaData
+ int wrong_dts; ///< wrong dts due to negative cts
uint8_t *new_extradata[FLV_STREAM_TYPE_NB];
- int new_extradata_size[FLV_STREAM_TYPE_NB];
- int last_sample_rate;
- int last_channels;
+ int new_extradata_size[FLV_STREAM_TYPE_NB];
+ int last_sample_rate;
+ int last_channels;
struct {
int64_t dts;
int64_t pos;
@@ -61,7 +61,11 @@ static int flv_probe(AVProbeData *p)
const uint8_t *d;
d = p->buf;
- if (d[0] == 'F' && d[1] == 'L' && d[2] == 'V' && d[3] < 5 && d[5]==0 && AV_RB32(d+5)>8) {
+ if (d[0] == 'F' &&
+ d[1] == 'L' &&
+ d[2] == 'V' &&
+ d[3] < 5 && d[5] == 0 &&
+ AV_RB32(d + 5) > 8) {
return AVPROBE_SCORE_MAX;
}
return 0;
@@ -73,7 +77,7 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
if (!st)
return NULL;
st->codec->codec_type = codec_type;
- if(s->nb_streams>=3 ||( s->nb_streams==2
+ if (s->nb_streams>=3 ||( s->nb_streams==2
&& s->streams[0]->codec->codec_type != AVMEDIA_TYPE_DATA
&& s->streams[1]->codec->codec_type != AVMEDIA_TYPE_DATA))
s->ctx_flags &= ~AVFMTCTX_NOHEADER;
@@ -81,10 +85,11 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
return st;
}
+
static int flv_same_audio_codec(AVCodecContext *acodec, int flags)
{
int bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8;
- int flv_codecid = flags & FLV_AUDIO_CODECID_MASK;
+ int flv_codecid = flags & FLV_AUDIO_CODECID_MASK;
int codec_id;
if (!acodec->codec_id && !acodec->codec_tag)
@@ -93,18 +98,21 @@ static int flv_same_audio_codec(AVCodecContext *acodec, int flags)
if (acodec->bits_per_coded_sample != bits_per_coded_sample)
return 0;
- switch(flv_codecid) {
- //no distinction between S16 and S8 PCM codec flags
+ switch (flv_codecid) {
+ // no distinction between S16 and S8 PCM codec flags
case FLV_CODECID_PCM:
- codec_id = bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 :
+ codec_id = bits_per_coded_sample == 8
+ ? AV_CODEC_ID_PCM_U8
#if HAVE_BIGENDIAN
- AV_CODEC_ID_PCM_S16BE;
+ : AV_CODEC_ID_PCM_S16BE;
#else
- AV_CODEC_ID_PCM_S16LE;
+ : AV_CODEC_ID_PCM_S16LE;
#endif
return codec_id == acodec->codec_id;
case FLV_CODECID_PCM_LE:
- codec_id = bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : AV_CODEC_ID_PCM_S16LE;
+ codec_id = bits_per_coded_sample == 8
+ ? AV_CODEC_ID_PCM_U8
+ : AV_CODEC_ID_PCM_S16LE;
return codec_id == acodec->codec_id;
case FLV_CODECID_AAC:
return acodec->codec_id == AV_CODEC_ID_AAC;
@@ -120,57 +128,72 @@ static int flv_same_audio_codec(AVCodecContext *acodec, int flags)
return acodec->codec_id == AV_CODEC_ID_NELLYMOSER;
case FLV_CODECID_PCM_MULAW:
return acodec->sample_rate == 8000 &&
- acodec->codec_id == AV_CODEC_ID_PCM_MULAW;
+ acodec->codec_id == AV_CODEC_ID_PCM_MULAW;
case FLV_CODECID_PCM_ALAW:
- return acodec->sample_rate = 8000 &&
- acodec->codec_id == AV_CODEC_ID_PCM_ALAW;
+ return acodec->sample_rate == 8000 &&
+ acodec->codec_id == AV_CODEC_ID_PCM_ALAW;
default:
return acodec->codec_tag == (flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
}
}
-static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecContext *acodec, int flv_codecid) {
- switch(flv_codecid) {
- //no distinction between S16 and S8 PCM codec flags
- case FLV_CODECID_PCM:
- acodec->codec_id = acodec->bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 :
+static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream,
+ AVCodecContext *acodec, int flv_codecid)
+{
+ switch (flv_codecid) {
+ // no distinction between S16 and S8 PCM codec flags
+ case FLV_CODECID_PCM:
+ acodec->codec_id = acodec->bits_per_coded_sample == 8
+ ? AV_CODEC_ID_PCM_U8
#if HAVE_BIGENDIAN
- AV_CODEC_ID_PCM_S16BE;
+ : AV_CODEC_ID_PCM_S16BE;
#else
- AV_CODEC_ID_PCM_S16LE;
+ : AV_CODEC_ID_PCM_S16LE;
#endif
- break;
- case FLV_CODECID_PCM_LE:
- acodec->codec_id = acodec->bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : AV_CODEC_ID_PCM_S16LE; break;
- case FLV_CODECID_AAC : acodec->codec_id = AV_CODEC_ID_AAC; break;
- case FLV_CODECID_ADPCM: acodec->codec_id = AV_CODEC_ID_ADPCM_SWF; break;
- case FLV_CODECID_SPEEX:
- acodec->codec_id = AV_CODEC_ID_SPEEX;
- acodec->sample_rate = 16000;
- break;
- case FLV_CODECID_MP3 : acodec->codec_id = AV_CODEC_ID_MP3 ; astream->need_parsing = AVSTREAM_PARSE_FULL; break;
- case FLV_CODECID_NELLYMOSER_8KHZ_MONO:
- acodec->sample_rate = 8000; //in case metadata does not otherwise declare samplerate
- acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
- break;
- case FLV_CODECID_NELLYMOSER_16KHZ_MONO:
- acodec->sample_rate = 16000;
- acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
- break;
- case FLV_CODECID_NELLYMOSER:
- acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
- break;
- case FLV_CODECID_PCM_MULAW:
- acodec->sample_rate = 8000;
- acodec->codec_id = AV_CODEC_ID_PCM_MULAW;
- break;
- case FLV_CODECID_PCM_ALAW:
- acodec->sample_rate = 8000;
- acodec->codec_id = AV_CODEC_ID_PCM_ALAW;
- break;
- default:
- av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n", flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
- acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET;
+ break;
+ case FLV_CODECID_PCM_LE:
+ acodec->codec_id = acodec->bits_per_coded_sample == 8
+ ? AV_CODEC_ID_PCM_U8
+ : AV_CODEC_ID_PCM_S16LE;
+ break;
+ case FLV_CODECID_AAC:
+ acodec->codec_id = AV_CODEC_ID_AAC;
+ break;
+ case FLV_CODECID_ADPCM:
+ acodec->codec_id = AV_CODEC_ID_ADPCM_SWF;
+ break;
+ case FLV_CODECID_SPEEX:
+ acodec->codec_id = AV_CODEC_ID_SPEEX;
+ acodec->sample_rate = 16000;
+ break;
+ case FLV_CODECID_MP3:
+ acodec->codec_id = AV_CODEC_ID_MP3;
+ astream->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
+ case FLV_CODECID_NELLYMOSER_8KHZ_MONO:
+ // in case metadata does not otherwise declare samplerate
+ acodec->sample_rate = 8000;
+ acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
+ break;
+ case FLV_CODECID_NELLYMOSER_16KHZ_MONO:
+ acodec->sample_rate = 16000;
+ acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
+ break;
+ case FLV_CODECID_NELLYMOSER:
+ acodec->codec_id = AV_CODEC_ID_NELLYMOSER;
+ break;
+ case FLV_CODECID_PCM_MULAW:
+ acodec->sample_rate = 8000;
+ acodec->codec_id = AV_CODEC_ID_PCM_MULAW;
+ break;
+ case FLV_CODECID_PCM_ALAW:
+ acodec->sample_rate = 8000;
+ acodec->codec_id = AV_CODEC_ID_PCM_ALAW;
+ break;
+ default:
+ avpriv_request_sample(s, "Audio codec (%x)",
+ flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
+ acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET;
}
}
@@ -182,63 +205,74 @@ static int flv_same_video_codec(AVCodecContext *vcodec, int flags)
return 1;
switch (flv_codecid) {
- case FLV_CODECID_H263:
- return vcodec->codec_id == AV_CODEC_ID_FLV1;
- case FLV_CODECID_SCREEN:
- return vcodec->codec_id == AV_CODEC_ID_FLASHSV;
- case FLV_CODECID_SCREEN2:
- return vcodec->codec_id == AV_CODEC_ID_FLASHSV2;
- case FLV_CODECID_VP6:
- return vcodec->codec_id == AV_CODEC_ID_VP6F;
- case FLV_CODECID_VP6A:
- return vcodec->codec_id == AV_CODEC_ID_VP6A;
- case FLV_CODECID_H264:
- return vcodec->codec_id == AV_CODEC_ID_H264;
- default:
- return vcodec->codec_tag == flv_codecid;
+ case FLV_CODECID_H263:
+ return vcodec->codec_id == AV_CODEC_ID_FLV1;
+ case FLV_CODECID_SCREEN:
+ return vcodec->codec_id == AV_CODEC_ID_FLASHSV;
+ case FLV_CODECID_SCREEN2:
+ return vcodec->codec_id == AV_CODEC_ID_FLASHSV2;
+ case FLV_CODECID_VP6:
+ return vcodec->codec_id == AV_CODEC_ID_VP6F;
+ case FLV_CODECID_VP6A:
+ return vcodec->codec_id == AV_CODEC_ID_VP6A;
+ case FLV_CODECID_H264:
+ return vcodec->codec_id == AV_CODEC_ID_H264;
+ default:
+ return vcodec->codec_tag == flv_codecid;
}
}
-static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_codecid, int read) {
+static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
+ int flv_codecid, int read)
+{
AVCodecContext *vcodec = vstream->codec;
- switch(flv_codecid) {
- case FLV_CODECID_H263 : vcodec->codec_id = AV_CODEC_ID_FLV1 ; break;
- case FLV_CODECID_REALH263: vcodec->codec_id = AV_CODEC_ID_H263 ; break; // Really mean it this time
- case FLV_CODECID_SCREEN: vcodec->codec_id = AV_CODEC_ID_FLASHSV; break;
- case FLV_CODECID_SCREEN2: vcodec->codec_id = AV_CODEC_ID_FLASHSV2; break;
- case FLV_CODECID_VP6 : vcodec->codec_id = AV_CODEC_ID_VP6F ;
- case FLV_CODECID_VP6A :
- if(flv_codecid == FLV_CODECID_VP6A)
- vcodec->codec_id = AV_CODEC_ID_VP6A;
- if (read) {
- if (vcodec->extradata_size != 1) {
- vcodec->extradata = av_malloc(1 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (vcodec->extradata)
- vcodec->extradata_size = 1;
- }
- if (vcodec->extradata)
- vcodec->extradata[0] = avio_r8(s->pb);
- else
- avio_skip(s->pb, 1);
+ switch (flv_codecid) {
+ case FLV_CODECID_H263:
+ vcodec->codec_id = AV_CODEC_ID_FLV1;
+ break;
+ case FLV_CODECID_REALH263:
+ vcodec->codec_id = AV_CODEC_ID_H263;
+ break; // Really mean it this time
+ case FLV_CODECID_SCREEN:
+ vcodec->codec_id = AV_CODEC_ID_FLASHSV;
+ break;
+ case FLV_CODECID_SCREEN2:
+ vcodec->codec_id = AV_CODEC_ID_FLASHSV2;
+ break;
+ case FLV_CODECID_VP6:
+ vcodec->codec_id = AV_CODEC_ID_VP6F;
+ case FLV_CODECID_VP6A:
+ if (flv_codecid == FLV_CODECID_VP6A)
+ vcodec->codec_id = AV_CODEC_ID_VP6A;
+ if (read) {
+ if (vcodec->extradata_size != 1) {
+ ff_alloc_extradata(vcodec, 1);
}
- return 1; // 1 byte body size adjustment for flv_read_packet()
- case FLV_CODECID_H264:
- vcodec->codec_id = AV_CODEC_ID_H264;
- return 3; // not 4, reading packet type will consume one byte
- case FLV_CODECID_MPEG4:
- vcodec->codec_id = AV_CODEC_ID_MPEG4;
- return 3;
- default:
- av_log(s, AV_LOG_INFO, "Unsupported video codec (%x)\n", flv_codecid);
- vcodec->codec_tag = flv_codecid;
+ if (vcodec->extradata)
+ vcodec->extradata[0] = avio_r8(s->pb);
+ else
+ avio_skip(s->pb, 1);
+ }
+ 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;
+ return 3;
+ default:
+ avpriv_request_sample(s, "Video codec (%x)", flv_codecid);
+ vcodec->codec_tag = flv_codecid;
}
return 0;
}
-static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) {
+static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize)
+{
int length = avio_rb16(ioc);
- if(length >= buffsize) {
+ if (length >= buffsize) {
avio_skip(ioc, length);
return -1;
}
@@ -250,16 +284,18 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) {
return length;
}
-static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream *vstream, int64_t max_pos) {
- FLVContext *flv = s->priv_data;
+static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
+ AVStream *vstream, int64_t max_pos)
+{
+ FLVContext *flv = s->priv_data;
unsigned int timeslen = 0, fileposlen = 0, i;
char str_val[256];
- int64_t *times = NULL;
+ int64_t *times = NULL;
int64_t *filepositions = NULL;
- int ret = AVERROR(ENOSYS);
- int64_t initial_pos = avio_tell(ioc);
+ int ret = AVERROR(ENOSYS);
+ int64_t initial_pos = avio_tell(ioc);
- if(vstream->nb_index_entries>0){
+ if (vstream->nb_index_entries>0) {
av_log(s, AV_LOG_WARNING, "Skiping duplicate index\n");
return 0;
}
@@ -267,8 +303,9 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
if (s->flags & AVFMT_FLAG_IGNIDX)
return 0;
- while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
- int64_t** current_array;
+ while (avio_tell(ioc) < max_pos - 2 &&
+ amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
+ int64_t **current_array;
unsigned int arraylen;
// Expect array object in context
@@ -276,16 +313,19 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
break;
arraylen = avio_rb32(ioc);
- if(arraylen>>28)
+ if (arraylen>>28)
break;
- if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times){
- current_array= &times;
- timeslen= arraylen;
- }else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && !filepositions){
- current_array= &filepositions;
- fileposlen= arraylen;
- }else // unexpected metatag inside keyframes, will not use such metadata for indexing
+ if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times) {
+ current_array = &times;
+ timeslen = arraylen;
+ } else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) &&
+ !filepositions) {
+ current_array = &filepositions;
+ fileposlen = arraylen;
+ } else
+ // unexpected metatag inside keyframes, will not use such
+ // metadata for indexing
break;
if (!(*current_array = av_mallocz(sizeof(**current_array) * arraylen))) {
@@ -308,12 +348,12 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) {
for (i = 0; i < fileposlen; i++) {
- av_add_index_entry(vstream, filepositions[i], times[i]*1000,
+ av_add_index_entry(vstream, filepositions[i], times[i] * 1000,
0, 0, AVINDEX_KEYFRAME);
if (i < 2) {
flv->validate_index[i].pos = filepositions[i];
flv->validate_index[i].dts = times[i] * 1000;
- flv->validate_count = i + 1;
+ flv->validate_count = i + 1;
}
}
} else {
@@ -328,7 +368,10 @@ finish:
return ret;
}
-static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) {
+static int amf_parse_object(AVFormatContext *s, AVStream *astream,
+ AVStream *vstream, const char *key,
+ int64_t max_pos, int depth)
+{
AVCodecContext *acodec, *vcodec;
FLVContext *flv = s->priv_data;
AVIOContext *ioc;
@@ -336,74 +379,85 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
char str_val[256];
double num_val;
- num_val = 0;
- ioc = s->pb;
-
+ num_val = 0;
+ ioc = s->pb;
amf_type = avio_r8(ioc);
- switch(amf_type) {
- case AMF_DATA_TYPE_NUMBER:
- num_val = av_int2double(avio_rb64(ioc)); break;
- case AMF_DATA_TYPE_BOOL:
- num_val = avio_r8(ioc); break;
- case AMF_DATA_TYPE_STRING:
- if(amf_get_string(ioc, str_val, sizeof(str_val)) < 0)
- return -1;
- break;
- case AMF_DATA_TYPE_OBJECT:
- if ((vstream || astream) && ioc->seekable && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1)
- if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
- max_pos) < 0)
- av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
-
- while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
- if (amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0)
- return -1; //if we couldn't skip, bomb out.
- }
- if(avio_r8(ioc) != AMF_END_OF_OBJECT)
- return -1;
- break;
- case AMF_DATA_TYPE_NULL:
- case AMF_DATA_TYPE_UNDEFINED:
- case AMF_DATA_TYPE_UNSUPPORTED:
- break; //these take up no additional space
- case AMF_DATA_TYPE_MIXEDARRAY:
- avio_skip(ioc, 4); //skip 32-bit max array index
- while(avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
- //this is the only case in which we would want a nested parse to not skip over the object
- if(amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0)
- return -1;
- }
- if(avio_r8(ioc) != AMF_END_OF_OBJECT)
+ switch (amf_type) {
+ case AMF_DATA_TYPE_NUMBER:
+ num_val = av_int2double(avio_rb64(ioc));
+ break;
+ case AMF_DATA_TYPE_BOOL:
+ num_val = avio_r8(ioc);
+ break;
+ case AMF_DATA_TYPE_STRING:
+ if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0)
+ return -1;
+ break;
+ case AMF_DATA_TYPE_OBJECT:
+ if ((vstream || astream) && key &&
+ ioc->seekable &&
+ !strcmp(KEYFRAMES_TAG, key) && depth == 1)
+ if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
+ max_pos) < 0)
+ av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
+
+ while (avio_tell(ioc) < max_pos - 2 &&
+ amf_get_string(ioc, str_val, sizeof(str_val)) > 0)
+ if (amf_parse_object(s, astream, vstream, str_val, max_pos,
+ depth + 1) < 0)
+ return -1; // if we couldn't skip, bomb out.
+ if (avio_r8(ioc) != AMF_END_OF_OBJECT)
+ return -1;
+ break;
+ case AMF_DATA_TYPE_NULL:
+ case AMF_DATA_TYPE_UNDEFINED:
+ case AMF_DATA_TYPE_UNSUPPORTED:
+ break; // these take up no additional space
+ case AMF_DATA_TYPE_MIXEDARRAY:
+ avio_skip(ioc, 4); // skip 32-bit max array index
+ while (avio_tell(ioc) < max_pos - 2 &&
+ amf_get_string(ioc, str_val, sizeof(str_val)) > 0)
+ // this is the only case in which we would want a nested
+ // parse to not skip over the object
+ if (amf_parse_object(s, astream, vstream, str_val, max_pos,
+ depth + 1) < 0)
return -1;
- break;
- case AMF_DATA_TYPE_ARRAY: {
- unsigned int arraylen, i;
-
- arraylen = avio_rb32(ioc);
- for(i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) {
- if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1) < 0)
- return -1; //if we couldn't skip, bomb out.
- }
- }
- break;
- case AMF_DATA_TYPE_DATE:
- avio_skip(ioc, 8 + 2); //timestamp (double) and UTC offset (int16)
- break;
- default: //unsupported type, we couldn't skip
+ if (avio_r8(ioc) != AMF_END_OF_OBJECT)
return -1;
+ break;
+ case AMF_DATA_TYPE_ARRAY:
+ {
+ unsigned int arraylen, i;
+
+ arraylen = avio_rb32(ioc);
+ for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++)
+ if (amf_parse_object(s, NULL, NULL, NULL, max_pos,
+ depth + 1) < 0)
+ return -1; // if we couldn't skip, bomb out.
+ }
+ break;
+ case AMF_DATA_TYPE_DATE:
+ avio_skip(ioc, 8 + 2); // timestamp (double) and UTC offset (int16)
+ break;
+ default: // unsupported type, we couldn't skip
+ return -1;
}
- if(depth == 1 && key) { //only look for metadata values when we are not nested and key != NULL
+ // only look for metadata values when we are not nested and key != NULL
+ if (depth == 1 && key) {
acodec = astream ? astream->codec : NULL;
vcodec = vstream ? vstream->codec : NULL;
- if (amf_type == AMF_DATA_TYPE_NUMBER) {
+ if (amf_type == AMF_DATA_TYPE_NUMBER ||
+ amf_type == AMF_DATA_TYPE_BOOL) {
if (!strcmp(key, "duration"))
s->duration = num_val * AV_TIME_BASE;
- else if (!strcmp(key, "videodatarate") && vcodec && 0 <= (int)(num_val * 1024.0))
+ else if (!strcmp(key, "videodatarate") && vcodec &&
+ 0 <= (int)(num_val * 1024.0))
vcodec->bit_rate = num_val * 1024.0;
- else if (!strcmp(key, "audiodatarate") && acodec && 0 <= (int)(num_val * 1024.0))
+ else if (!strcmp(key, "audiodatarate") && acodec &&
+ 0 <= (int)(num_val * 1024.0))
acodec->bit_rate = num_val * 1024.0;
else if (!strcmp(key, "datastream")) {
AVStream *st = create_stream(s, AVMEDIA_TYPE_DATA);
@@ -413,17 +467,21 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
} else if (flv->trust_metadata) {
if (!strcmp(key, "videocodecid") && vcodec) {
flv_set_video_codec(s, vstream, num_val, 0);
- } else
- if (!strcmp(key, "audiocodecid") && acodec) {
- flv_set_audio_codec(s, astream, acodec, num_val);
- } else
- if (!strcmp(key, "audiosamplerate") && acodec) {
+ } else if (!strcmp(key, "audiocodecid") && acodec) {
+ int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET;
+ flv_set_audio_codec(s, astream, acodec, id);
+ } else if (!strcmp(key, "audiosamplerate") && acodec) {
acodec->sample_rate = num_val;
- } else
- if (!strcmp(key, "width") && vcodec) {
+ } else if (!strcmp(key, "audiosamplesize") && acodec) {
+ acodec->bits_per_coded_sample = num_val;
+ } else if (!strcmp(key, "stereo") && acodec) {
+ acodec->channels = num_val + 1;
+ acodec->channel_layout = acodec->channels == 2 ?
+ AV_CH_LAYOUT_STEREO :
+ AV_CH_LAYOUT_MONO;
+ } else if (!strcmp(key, "width") && vcodec) {
vcodec->width = num_val;
- } else
- if (!strcmp(key, "height") && vcodec) {
+ } else if (!strcmp(key, "height") && vcodec) {
vcodec->height = num_val;
}
}
@@ -445,13 +503,15 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
!strcmp(key, "audiosamplerate") ||
!strcmp(key, "audiosamplesize") ||
!strcmp(key, "stereo") ||
- !strcmp(key, "audiocodecid"))
+ !strcmp(key, "audiocodecid") ||
+ !strcmp(key, "datastream"))
return 0;
- if(amf_type == AMF_DATA_TYPE_BOOL) {
- av_strlcpy(str_val, num_val > 0 ? "true" : "false", sizeof(str_val));
+ if (amf_type == AMF_DATA_TYPE_BOOL) {
+ av_strlcpy(str_val, num_val > 0 ? "true" : "false",
+ sizeof(str_val));
av_dict_set(&s->metadata, key, str_val, 0);
- } else if(amf_type == AMF_DATA_TYPE_NUMBER) {
+ } else if (amf_type == AMF_DATA_TYPE_NUMBER) {
snprintf(str_val, sizeof(str_val), "%.f", num_val);
av_dict_set(&s->metadata, key, str_val, 0);
} else if (amf_type == AMF_DATA_TYPE_STRING)
@@ -461,17 +521,23 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
return 0;
}
-static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) {
+static int flv_read_metabody(AVFormatContext *s, int64_t next_pos)
+{
AMFDataType type;
- AVStream *stream, *astream, *vstream, *dstream;
+ AVStream *stream, *astream, *vstream;
+ AVStream av_unused *dstream;
AVIOContext *ioc;
int i;
- char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.
+ // only needs to hold the string "onMetaData".
+ // Anything longer is something we don't want.
+ char buffer[11];
- vstream = astream = dstream = NULL;
- ioc = s->pb;
+ astream = NULL;
+ vstream = NULL;
+ dstream = NULL;
+ ioc = s->pb;
- //first object needs to be "onMetaData" string
+ // first object needs to be "onMetaData" string
type = avio_r8(ioc);
if (type != AMF_DATA_TYPE_STRING ||
amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
@@ -483,16 +549,20 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) {
if (strcmp(buffer, "onMetaData"))
return -1;
- //find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called.
- for(i = 0; i < s->nb_streams; i++) {
+ // find the streams now so that amf_parse_object doesn't need to do
+ // the lookup every time it is called.
+ for (i = 0; i < s->nb_streams; i++) {
stream = s->streams[i];
- if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = stream;
- else if(stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) astream = stream;
- else if(stream->codec->codec_type == AVMEDIA_TYPE_DATA) dstream = stream;
+ if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ vstream = stream;
+ else if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ astream = stream;
+ else if (stream->codec->codec_type == AVMEDIA_TYPE_DATA)
+ dstream = stream;
}
- //parse the second object (we want a mixed array)
- if(amf_parse_object(s, astream, vstream, buffer, next_pos, 0) < 0)
+ // parse the second object (we want a mixed array)
+ if (amf_parse_object(s, astream, vstream, buffer, next_pos, 0) < 0)
return -1;
return 0;
@@ -508,19 +578,19 @@ static int flv_read_header(AVFormatContext *s)
/* FIXME: better fix needed */
if (!flags) {
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");
+ av_log(s, AV_LOG_WARNING,
+ "Broken FLV file, which says no streams present, "
+ "this might fail\n");
}
s->ctx_flags |= AVFMTCTX_NOHEADER;
- if(flags & FLV_HEADER_FLAG_HASVIDEO){
- if(!create_stream(s, AVMEDIA_TYPE_VIDEO))
+ if (flags & FLV_HEADER_FLAG_HASVIDEO)
+ if (!create_stream(s, AVMEDIA_TYPE_VIDEO))
return AVERROR(ENOMEM);
- }
- if(flags & FLV_HEADER_FLAG_HASAUDIO){
- if(!create_stream(s, AVMEDIA_TYPE_AUDIO))
+ if (flags & FLV_HEADER_FLAG_HASAUDIO)
+ if (!create_stream(s, AVMEDIA_TYPE_AUDIO))
return AVERROR(ENOMEM);
- }
// Flag doesn't indicate whether or not there is script-data present. Must
// create that stream if it's encountered.
@@ -537,7 +607,7 @@ static int flv_read_close(AVFormatContext *s)
{
int i;
FLVContext *flv = s->priv_data;
- for(i=0; i<FLV_STREAM_TYPE_NB; i++)
+ for (i=0; i<FLV_STREAM_TYPE_NB; i++)
av_freep(&flv->new_extradata[i]);
return 0;
}
@@ -545,11 +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);
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, s->pb, size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = size;
- avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
@@ -557,7 +624,8 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream,
int size)
{
av_free(flv->new_extradata[stream]);
- flv->new_extradata[stream] = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ flv->new_extradata[stream] = av_mallocz(size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
if (!flv->new_extradata[stream])
return AVERROR(ENOMEM);
flv->new_extradata_size[stream] = size;
@@ -568,51 +636,96 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream,
static void clear_index_entries(AVFormatContext *s, int64_t pos)
{
int i, j, out;
- av_log(s, AV_LOG_WARNING, "Found invalid index entries, clearing the index.\n");
+ av_log(s, AV_LOG_WARNING,
+ "Found invalid index entries, clearing the index.\n");
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
/* Remove all index entries that point to >= pos */
out = 0;
- for (j = 0; j < st->nb_index_entries; j++) {
+ for (j = 0; j < st->nb_index_entries; j++)
if (st->index_entries[j].pos < pos)
st->index_entries[out++] = st->index_entries[j];
- }
st->nb_index_entries = out;
}
}
+static int amf_skip_tag(AVIOContext *pb, AMFDataType type)
+{
+ int nb = -1, ret, parse_name = 1;
+
+ switch (type) {
+ case AMF_DATA_TYPE_NUMBER:
+ avio_skip(pb, 8);
+ break;
+ case AMF_DATA_TYPE_BOOL:
+ avio_skip(pb, 1);
+ break;
+ case AMF_DATA_TYPE_STRING:
+ avio_skip(pb, avio_rb16(pb));
+ break;
+ case AMF_DATA_TYPE_ARRAY:
+ parse_name = 0;
+ case AMF_DATA_TYPE_MIXEDARRAY:
+ nb = avio_rb32(pb);
+ case AMF_DATA_TYPE_OBJECT:
+ while(!pb->eof_reached && (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY)) {
+ if (parse_name) {
+ int size = avio_rb16(pb);
+ if (!size) {
+ avio_skip(pb, 1);
+ break;
+ }
+ avio_skip(pb, size);
+ }
+ if ((ret = amf_skip_tag(pb, avio_r8(pb))) < 0)
+ return ret;
+ }
+ break;
+ case AMF_DATA_TYPE_NULL:
+ case AMF_DATA_TYPE_OBJECT_END:
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+}
static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
int64_t dts, int64_t next)
{
- int ret = AVERROR_INVALIDDATA, i;
AVIOContext *pb = s->pb;
- AVStream *st = NULL;
- AMFDataType type;
+ AVStream *st = NULL;
char buf[20];
- int length;
+ int ret = AVERROR_INVALIDDATA;
+ int i, length = -1;
- type = avio_r8(pb);
- if (type == AMF_DATA_TYPE_MIXEDARRAY)
+ switch (avio_r8(pb)) {
+ case AMF_DATA_TYPE_MIXEDARRAY:
avio_seek(pb, 4, SEEK_CUR);
- else if (type != AMF_DATA_TYPE_OBJECT)
- goto out;
-
- amf_get_string(pb, buf, sizeof(buf));
- if (strcmp(buf, "type") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
- goto out;
-
- amf_get_string(pb, buf, sizeof(buf));
- //FIXME parse it as codec_id
- amf_get_string(pb, buf, sizeof(buf));
- if (strcmp(buf, "text") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
- goto out;
-
- length = avio_rb16(pb);
- ret = av_get_packet(s->pb, pkt, length);
- if (ret < 0) {
- ret = AVERROR(EIO);
- goto out;
+ case AMF_DATA_TYPE_OBJECT:
+ break;
+ default:
+ goto skip;
+ }
+
+ while ((ret = amf_get_string(pb, buf, sizeof(buf))) > 0) {
+ AMFDataType type = avio_r8(pb);
+ if (type == AMF_DATA_TYPE_STRING && !strcmp(buf, "text")) {
+ length = avio_rb16(pb);
+ ret = av_get_packet(pb, pkt, length);
+ if (ret < 0)
+ goto skip;
+ else
+ break;
+ } else {
+ if ((ret = amf_skip_tag(pb, type)) < 0)
+ goto skip;
+ }
+ }
+
+ if (length < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto skip;
}
for (i = 0; i < s->nb_streams; i++) {
@@ -624,7 +737,7 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
if (i == s->nb_streams) {
st = create_stream(s, AVMEDIA_TYPE_DATA);
if (!st)
- goto out;
+ return AVERROR_INVALIDDATA;
st->codec->codec_id = AV_CODEC_ID_TEXT;
}
@@ -633,10 +746,11 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
pkt->size = ret;
pkt->stream_index = st->index;
- pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+skip:
avio_seek(s->pb, next + 4, SEEK_SET);
-out:
+
return ret;
}
@@ -645,130 +759,131 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
FLVContext *flv = s->priv_data;
int ret, i, type, size, flags;
int stream_type=-1;
- int64_t next, pos;
+ int64_t next, pos, meta_pos;
int64_t dts, pts = AV_NOPTS_VALUE;
int av_uninit(channels);
int av_uninit(sample_rate);
- AVStream *st = NULL;
-
- for(;;avio_skip(s->pb, 4)){ /* pkt size is repeated at end. skip it */
- pos = avio_tell(s->pb);
- type = avio_r8(s->pb);
- 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);
- if (url_feof(s->pb))
- return AVERROR_EOF;
- avio_skip(s->pb, 3); /* stream id, always 0 */
- flags = 0;
-
- if (flv->validate_next < flv->validate_count) {
- int64_t validate_pos = flv->validate_index[flv->validate_next].pos;
- if (pos == validate_pos) {
- if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <=
- VALIDATE_INDEX_TS_THRESH) {
- flv->validate_next++;
- } else {
+ AVStream *st = NULL;
+
+ /* pkt size is repeated at end. skip it */
+ for (;; avio_skip(s->pb, 4)) {
+ pos = avio_tell(s->pb);
+ type = avio_r8(s->pb);
+ 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);
+ if (url_feof(s->pb))
+ return AVERROR_EOF;
+ avio_skip(s->pb, 3); /* stream id, always 0 */
+ flags = 0;
+
+ if (flv->validate_next < flv->validate_count) {
+ int64_t validate_pos = flv->validate_index[flv->validate_next].pos;
+ if (pos == validate_pos) {
+ if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <=
+ VALIDATE_INDEX_TS_THRESH) {
+ flv->validate_next++;
+ } else {
+ clear_index_entries(s, validate_pos);
+ flv->validate_count = 0;
+ }
+ } else if (pos > validate_pos) {
clear_index_entries(s, validate_pos);
flv->validate_count = 0;
}
- } else if (pos > validate_pos) {
- clear_index_entries(s, validate_pos);
- flv->validate_count = 0;
}
- }
-
- if(size == 0)
- continue;
- next= size + avio_tell(s->pb);
-
- if (type == FLV_TAG_TYPE_AUDIO) {
- stream_type=FLV_STREAM_TYPE_AUDIO;
- flags = avio_r8(s->pb);
- size--;
- } else if (type == FLV_TAG_TYPE_VIDEO) {
- stream_type=FLV_STREAM_TYPE_VIDEO;
- flags = avio_r8(s->pb);
- size--;
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
- goto skip;
- } else if (type == FLV_TAG_TYPE_META) {
- if (size > 13+1+4 && dts == 0) { // Header-type metadata stuff
- flv_read_metabody(s, next);
- goto skip;
- } else if (dts != 0) { // Script-data "special" metadata frames - don't skip
+ if (size == 0)
+ continue;
+
+ next = size + avio_tell(s->pb);
+
+ if (type == FLV_TAG_TYPE_AUDIO) {
+ stream_type = FLV_STREAM_TYPE_AUDIO;
+ flags = avio_r8(s->pb);
+ size--;
+ } else if (type == FLV_TAG_TYPE_VIDEO) {
+ stream_type = FLV_STREAM_TYPE_VIDEO;
+ flags = avio_r8(s->pb);
+ size--;
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
+ goto skip;
+ } else if (type == FLV_TAG_TYPE_META) {
stream_type=FLV_STREAM_TYPE_DATA;
+ if (size > 13 + 1 + 4 && dts == 0) { // Header-type metadata stuff
+ meta_pos = avio_tell(s->pb);
+ if (flv_read_metabody(s, next) == 0) {
+ goto skip;
+ }
+ avio_seek(s->pb, meta_pos, SEEK_SET);
+ }
} else {
- goto skip;
+ av_log(s, AV_LOG_DEBUG,
+ "skipping flv packet: type %d, size %d, flags %d\n",
+ type, size, flags);
+skip:
+ avio_seek(s->pb, next, SEEK_SET);
+ continue;
}
- } else {
- av_log(s, AV_LOG_DEBUG, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags);
- skip:
- avio_seek(s->pb, next, SEEK_SET);
- continue;
- }
-
- /* skip empty data packets */
- if (!size)
- continue;
- /* now find stream */
- for(i=0;i<s->nb_streams;i++) {
- st = s->streams[i];
- if (stream_type == FLV_STREAM_TYPE_AUDIO) {
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- (s->audio_codec_id || flv_same_audio_codec(st->codec, flags))) {
- break;
+ /* skip empty data packets */
+ if (!size)
+ continue;
+
+ /* now find stream */
+ for (i = 0; i < s->nb_streams; i++) {
+ st = s->streams[i];
+ if (stream_type == FLV_STREAM_TYPE_AUDIO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ (s->audio_codec_id || flv_same_audio_codec(st->codec, flags)))
+ break;
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ (s->video_codec_id || flv_same_video_codec(st->codec, flags)))
+ break;
+ } else if (stream_type == FLV_STREAM_TYPE_DATA) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_DATA)
+ break;
}
- } else
- if (stream_type == FLV_STREAM_TYPE_VIDEO) {
- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- (s->video_codec_id || flv_same_video_codec(st->codec, flags))) {
- break;
- }
- } else if (stream_type == FLV_STREAM_TYPE_DATA) {
- if (st->codec->codec_type == AVMEDIA_TYPE_DATA)
- break;
}
- }
- if(i == s->nb_streams){
- av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");
- st = create_stream(s,
- (int[]){AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA}[stream_type]);
- if (!st)
- return AVERROR(ENOMEM);
+ if (i == s->nb_streams) {
+ static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA};
+ av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");
+ st = create_stream(s, stream_types[stream_type]);
+ if (!st)
+ return AVERROR(ENOMEM);
+ }
+ av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard);
+ if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
+ ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO)))
+ || st->discard >= AVDISCARD_ALL
+ ) {
+ avio_seek(s->pb, next, SEEK_SET);
+ continue;
+ }
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO)
+ av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
+ break;
}
- av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard);
- if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
- ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO)))
- || st->discard >= AVDISCARD_ALL
- ){
- avio_seek(s->pb, next, SEEK_SET);
- continue;
- }
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
- av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
- break;
- }
- // if not streamed and no duration from metadata then seek to end to find the duration from the timestamps
- if(s->pb->seekable && (!s->duration || s->duration==AV_NOPTS_VALUE) && !flv->searched_for_end){
+ // if not streamed and no duration from metadata then seek to end to find
+ // the duration from the timestamps
+ if (s->pb->seekable && (!s->duration || s->duration == AV_NOPTS_VALUE) && !flv->searched_for_end) {
int size;
- const int64_t pos= avio_tell(s->pb);
- int64_t fsize= avio_size(s->pb);
+ const int64_t pos = avio_tell(s->pb);
+ int64_t fsize = avio_size(s->pb);
retry_duration:
- avio_seek(s->pb, fsize-4, SEEK_SET);
- size= avio_rb32(s->pb);
- avio_seek(s->pb, fsize-3-size, SEEK_SET);
- if(size == avio_rb24(s->pb) + 11){
+ avio_seek(s->pb, fsize - 4, SEEK_SET);
+ size = avio_rb32(s->pb);
+ avio_seek(s->pb, fsize - 3 - size, SEEK_SET);
+ if (size == avio_rb24(s->pb) + 11) {
uint32_t ts = avio_rb24(s->pb);
- ts |= avio_r8(s->pb) << 24;
- if(ts)
+ ts |= avio_r8(s->pb) << 24;
+ if (ts)
s->duration = ts * (int64_t)AV_TIME_BASE / 1000;
- else if (fsize >= 8 && fsize - 8 >= size){
+ else if (fsize >= 8 && fsize - 8 >= size) {
fsize -= size+4;
goto retry_duration;
}
@@ -778,29 +893,35 @@ retry_duration:
flv->searched_for_end = 1;
}
- if(stream_type == FLV_STREAM_TYPE_AUDIO){
+ if (stream_type == FLV_STREAM_TYPE_AUDIO) {
int bits_per_coded_sample;
- channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
- sample_rate = (44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >> FLV_AUDIO_SAMPLERATE_OFFSET) >> 3);
+ channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
+ sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >>
+ FLV_AUDIO_SAMPLERATE_OFFSET) >> 3;
bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8;
- if(!st->codec->channels || !st->codec->sample_rate || !st->codec->bits_per_coded_sample) {
+ if (!st->codec->channels || !st->codec->sample_rate ||
+ !st->codec->bits_per_coded_sample) {
st->codec->channels = channels;
- st->codec->channel_layout = channels == 1 ? AV_CH_LAYOUT_MONO :
- AV_CH_LAYOUT_STEREO;
+ st->codec->channel_layout = channels == 1
+ ? AV_CH_LAYOUT_MONO
+ : AV_CH_LAYOUT_STEREO;
st->codec->sample_rate = sample_rate;
st->codec->bits_per_coded_sample = bits_per_coded_sample;
}
- if(!st->codec->codec_id){
- flv_set_audio_codec(s, st, st->codec, flags & FLV_AUDIO_CODECID_MASK);
- flv->last_sample_rate = sample_rate = st->codec->sample_rate;
- flv->last_channels = channels = st->codec->channels;
+ if (!st->codec->codec_id) {
+ flv_set_audio_codec(s, st, st->codec,
+ flags & FLV_AUDIO_CODECID_MASK);
+ flv->last_sample_rate =
+ sample_rate = st->codec->sample_rate;
+ flv->last_channels =
+ channels = st->codec->channels;
} else {
AVCodecContext ctx;
ctx.sample_rate = sample_rate;
flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK);
sample_rate = ctx.sample_rate;
}
- } else if(stream_type == FLV_STREAM_TYPE_VIDEO) {
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK, 1);
}
@@ -810,11 +931,13 @@ retry_duration:
int type = avio_r8(s->pb);
size--;
if (st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_MPEG4) {
- int32_t cts = (avio_rb24(s->pb)+0xff800000)^0xff800000; // sign extension
+ // sign extension
+ int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
pts = dts + cts;
if (cts < 0) { // dts are wrong
flv->wrong_dts = 1;
- av_log(s, AV_LOG_WARNING, "negative cts, previous timestamps might be wrong\n");
+ av_log(s, AV_LOG_WARNING,
+ "negative cts, previous timestamps might be wrong\n");
}
if (flv->wrong_dts)
dts = AV_NOPTS_VALUE;
@@ -832,7 +955,7 @@ retry_duration:
MPEG4AudioConfig cfg;
if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
st->codec->extradata_size * 8, 1) >= 0) {
- st->codec->channels = cfg.channels;
+ st->codec->channels = cfg.channels;
st->codec->channel_layout = 0;
if (cfg.ext_sample_rate)
st->codec->sample_rate = cfg.ext_sample_rate;
@@ -854,11 +977,11 @@ retry_duration:
goto leave;
}
- ret= av_get_packet(s->pb, pkt, size);
+ ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
return ret;
- pkt->dts = dts;
- pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
+ pkt->dts = dts;
+ pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
pkt->stream_index = st->index;
if (flv->new_extradata[stream_type]) {
uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
@@ -870,8 +993,9 @@ retry_duration:
flv->new_extradata_size[stream_type] = 0;
}
}
- if (stream_type == FLV_STREAM_TYPE_AUDIO && (sample_rate != flv->last_sample_rate ||
- channels != flv->last_channels)) {
+ if (stream_type == FLV_STREAM_TYPE_AUDIO &&
+ (sample_rate != flv->last_sample_rate ||
+ channels != flv->last_channels)) {
flv->last_sample_rate = sample_rate;
flv->last_channels = channels;
ff_add_param_change(pkt, channels, 0, sample_rate, 0, 0);
@@ -888,7 +1012,7 @@ leave:
}
static int flv_read_seek(AVFormatContext *s, int stream_index,
- int64_t ts, int flags)
+ int64_t ts, int flags)
{
FLVContext *flv = s->priv_data;
flv->validate_count = 0;
@@ -898,11 +1022,11 @@ static int flv_read_seek(AVFormatContext *s, int stream_index,
#define OFFSET(x) offsetof(FLVContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
- { "flv_metadata", "Allocate streams according the onMetaData array", OFFSET(trust_metadata), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VD},
+ { "flv_metadata", "Allocate streams according to the onMetaData array", OFFSET(trust_metadata), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VD },
{ NULL }
};
-static const AVClass class = {
+static const AVClass flv_class = {
.class_name = "flvdec",
.item_name = av_default_item_name,
.option = options,
@@ -919,5 +1043,5 @@ AVInputFormat ff_flv_demuxer = {
.read_seek = flv_read_seek,
.read_close = flv_read_close,
.extensions = "flv",
- .priv_class = &class,
+ .priv_class = &flv_class,
};
diff --git a/ffmpeg/libavformat/flvenc.c b/ffmpeg/libavformat/flvenc.c
index 502da0f..fb36f66 100644
--- a/ffmpeg/libavformat/flvenc.c
+++ b/ffmpeg/libavformat/flvenc.c
@@ -212,6 +212,11 @@ static int flv_write_header(AVFormatContext *s)
} else {
framerate = 1 / av_q2d(s->streams[i]->codec->time_base);
}
+ if (video_enc) {
+ av_log(s, AV_LOG_ERROR,
+ "at most one video stream is supported in flv\n");
+ return AVERROR(EINVAL);
+ }
video_enc = enc;
if (enc->codec_tag == 0) {
av_log(s, AV_LOG_ERROR, "Video codec '%s' for stream %d is not compatible with FLV\n",
@@ -220,6 +225,11 @@ static int flv_write_header(AVFormatContext *s)
}
break;
case AVMEDIA_TYPE_AUDIO:
+ if (audio_enc) {
+ av_log(s, AV_LOG_ERROR,
+ "at most one audio stream is supported in flv\n");
+ return AVERROR(EINVAL);
+ }
audio_enc = enc;
if (get_audio_flags(s, enc) < 0)
return AVERROR_INVALIDDATA;
@@ -450,8 +460,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
uint8_t *data = NULL;
int flags = -1, flags_size, ret;
- if (enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_VP6F ||
- enc->codec_id == AV_CODEC_ID_VP6A || enc->codec_id == AV_CODEC_ID_AAC)
+ if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A ||
+ enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC)
flags_size = 2;
else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4)
flags_size = 5;
@@ -493,10 +503,13 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
return ret;
} else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
(AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
+ if (!s->streams[pkt->stream_index]->nb_frames) {
av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
"use audio bitstream filter 'aac_adtstoasc' to fix it "
"('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
return AVERROR_INVALIDDATA;
+ }
+ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
}
if (flv->delay == AV_NOPTS_VALUE)
@@ -526,7 +539,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);
@@ -550,13 +563,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_w8(pb,flags);
if (enc->codec_id == AV_CODEC_ID_VP6)
avio_w8(pb,0);
- if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A)
- avio_w8(pb, enc->extradata_size ? enc->extradata[0] : 0);
- else if (enc->codec_id == AV_CODEC_ID_AAC)
- avio_w8(pb,1); // AAC raw
+ if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) {
+ if (enc->extradata_size)
+ avio_w8(pb, enc->extradata[0]);
+ else
+ avio_w8(pb, ((FFALIGN(enc->width, 16) - enc->width) << 4) |
+ (FFALIGN(enc->height, 16) - enc->height));
+ } else if (enc->codec_id == AV_CODEC_ID_AAC)
+ avio_w8(pb, 1); // AAC raw
else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) {
- avio_w8(pb,1); // AVC NALU
- avio_wb24(pb,pkt->pts - pkt->dts);
+ avio_w8(pb, 1); // AVC NALU
+ avio_wb24(pb, pkt->pts - pkt->dts);
}
avio_write(pb, data ? data : pkt->data, size);
@@ -566,7 +583,6 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
pkt->pts + flv->delay + pkt->duration);
}
- avio_flush(pb);
av_free(data);
return pb->error;
diff --git a/ffmpeg/libavformat/framecrcenc.c b/ffmpeg/libavformat/framecrcenc.c
index 92f2e91..dbe49b5 100644
--- a/ffmpeg/libavformat/framecrcenc.c
+++ b/ffmpeg/libavformat/framecrcenc.c
@@ -34,19 +34,27 @@ static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt)
if (pkt->flags != AV_PKT_FLAG_KEY)
av_strlcatf(buf, sizeof(buf), ", F=0x%0X", pkt->flags);
if (pkt->side_data_elems) {
- int i;
+ int i, j;
av_strlcatf(buf, sizeof(buf), ", S=%d", pkt->side_data_elems);
for (i=0; i<pkt->side_data_elems; i++) {
- uint32_t side_data_crc = av_adler32_update(0,
- pkt->side_data[i].data,
- pkt->side_data[i].size);
+ uint32_t side_data_crc = 0;
+ if (HAVE_BIGENDIAN && AV_PKT_DATA_PALETTE == pkt->side_data[i].type) {
+ for (j=0; j<pkt->side_data[i].size; j++) {
+ side_data_crc = av_adler32_update(side_data_crc,
+ pkt->side_data[i].data + (j^3),
+ 1);
+ }
+ } else {
+ side_data_crc = av_adler32_update(0,
+ pkt->side_data[i].data,
+ pkt->side_data[i].size);
+ }
av_strlcatf(buf, sizeof(buf), ", %8d, 0x%08x", pkt->side_data[i].size, side_data_crc);
}
}
av_strlcatf(buf, sizeof(buf), "\n");
avio_write(s->pb, buf, strlen(buf));
- avio_flush(s->pb);
return 0;
}
@@ -57,5 +65,6 @@ AVOutputFormat ff_framecrc_muxer = {
.video_codec = AV_CODEC_ID_RAWVIDEO,
.write_header = ff_framehash_write_header,
.write_packet = framecrc_write_packet,
- .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
+ AVFMT_TS_NEGATIVE,
};
diff --git a/ffmpeg/libavformat/framehash.c b/ffmpeg/libavformat/framehash.c
index 28e9e84..f97f59b 100644
--- a/ffmpeg/libavformat/framehash.c
+++ b/ffmpeg/libavformat/framehash.c
@@ -1,20 +1,20 @@
/*
* Common functions for the frame{crc,md5} muxers
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,9 @@
int ff_framehash_write_header(AVFormatContext *s)
{
int i;
+
+ if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT))
+ avio_printf(s->pb, "#software: %s\n", LIBAVFORMAT_IDENT);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
diff --git a/ffmpeg/libavformat/g723_1.c b/ffmpeg/libavformat/g723_1.c
index 8d35f88..4f3ce8f 100644
--- a/ffmpeg/libavformat/g723_1.c
+++ b/ffmpeg/libavformat/g723_1.c
@@ -24,13 +24,14 @@
* G.723.1 demuxer
*/
+#include "libavutil/attributes.h"
#include "libavutil/channel_layout.h"
#include "avformat.h"
#include "internal.h"
static const uint8_t frame_size[4] = { 24, 20, 4, 1 };
-static int g723_1_init(AVFormatContext *s)
+static av_cold int g723_1_init(AVFormatContext *s)
{
AVStream *st;
diff --git a/ffmpeg/libavformat/gif.c b/ffmpeg/libavformat/gif.c
index 31b0101..e52498d 100644
--- a/ffmpeg/libavformat/gif.c
+++ b/ffmpeg/libavformat/gif.c
@@ -2,6 +2,8 @@
* Animated GIF muxer
* Copyright (c) 2000 Fabrice Bellard
*
+ * first version by Francois Revol <revol@free.fr>
+ *
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
@@ -19,333 +21,169 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * First version by Francois Revol revol@free.fr
- *
- * Features and limitations:
- * - currently no compression is performed,
- * in fact the size of the data is 9/8 the size of the image in 8bpp
- * - uses only a global standard palette
- * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
- *
- * Reference documents:
- * http://www.goice.co.jp/member/mo/formats/gif.html
- * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
- * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
- *
- * this url claims to have an LZW algorithm not covered by Unisys patent:
- * http://www.msg.net/utility/whirlgif/gifencod.html
- * could help reduce the size of the files _a lot_...
- * some sites mentions an RLE type compression also.
- */
-
#include "avformat.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
-/* The GIF format uses reversed order for bitstreams... */
-/* at least they don't use PDP_ENDIAN :) */
-#define BITSTREAM_WRITER_LE
-
-#include "libavcodec/put_bits.h"
-
-/* bitstream minipacket size */
-#define GIF_CHUNKS 100
-
-/* slows down the decoding (and some browsers don't like it) */
-/* update on the 'some browsers don't like it issue from above:
- * this was probably due to missing 'Data Sub-block Terminator'
- * (byte 19) in the app_header */
-#define GIF_ADD_APP_HEADER // required to enable looping of animated gif
-
-typedef struct {
- unsigned char r;
- unsigned char g;
- unsigned char b;
-} rgb_triplet;
-
-/* we use the standard 216 color palette */
-
-/* this script was used to create the palette:
- * for r in 00 33 66 99 cc ff; do
- * for g in 00 33 66 99 cc ff; do
- * echo -n " "
- * for b in 00 33 66 99 cc ff; do
- * echo -n "{ 0x$r, 0x$g, 0x$b }, "
- * done
- * echo ""
- * done
- * done
- */
-
-static const rgb_triplet gif_clut[216] = {
- { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
- { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
- { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
- { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
- { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
- { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
- { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
- { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
- { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
- { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
- { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
- { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
- { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
- { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
- { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
- { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
- { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
- { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
- { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
- { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
- { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
- { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
- { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
- { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
- { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
- { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
- { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
- { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
- { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
- { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
- { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
- { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
- { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
- { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
- { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
- { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
-};
-
-/* GIF header */
static int gif_image_write_header(AVIOContext *pb, int width, int height,
int loop_count, uint32_t *palette)
{
int i;
- unsigned int v;
avio_write(pb, "GIF", 3);
avio_write(pb, "89a", 3);
avio_wl16(pb, width);
avio_wl16(pb, height);
- avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
- avio_w8(pb, 0x1f); /* background color index */
- avio_w8(pb, 0); /* aspect ratio */
-
- /* the global palette */
- if (!palette) {
- avio_write(pb, (const unsigned char *)gif_clut, 216 * 3);
- for (i = 0; i < ((256 - 216) * 3); i++)
- avio_w8(pb, 0);
- } else {
+ if (palette) {
+ avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
+ avio_w8(pb, 0x1f); /* background color index */
+ avio_w8(pb, 0); /* aspect ratio */
for (i = 0; i < 256; i++) {
- v = palette[i];
- avio_w8(pb, (v >> 16) & 0xff);
- avio_w8(pb, (v >> 8) & 0xff);
- avio_w8(pb, (v) & 0xff);
+ const uint32_t v = palette[i] & 0xffffff;
+ avio_wb24(pb, v);
}
+ } else {
+ avio_w8(pb, 0); /* flags */
+ avio_w8(pb, 0); /* background color index */
+ avio_w8(pb, 0); /* aspect ratio */
}
- /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated
- * GIF, see http://members.aol.com/royalef/gifabout.htm#net-extension
- *
- * byte 1 : 33 (hex 0x21) GIF Extension code
- * byte 2 : 255 (hex 0xFF) Application Extension Label
- * byte 3 : 11 (hex (0x0B) Length of Application Block
- * (eleven bytes of data to follow)
- * bytes 4 to 11 : "NETSCAPE"
- * bytes 12 to 14 : "2.0"
- * byte 15 : 3 (hex 0x03) Length of Data Sub-Block
- * (three bytes of data to follow)
- * byte 16 : 1 (hex 0x01)
- * bytes 17 to 18 : 0 to 65535, an unsigned integer in
- * lo-hi byte format. This indicate the
- * number of iterations the loop should
- * be executed.
- * bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator
- */
- /* application extension header */
-#ifdef GIF_ADD_APP_HEADER
- if (loop_count >= 0 && loop_count <= 65535) {
- avio_w8(pb, 0x21);
- avio_w8(pb, 0xff);
- avio_w8(pb, 0x0b);
- // bytes 4 to 14
+ if (loop_count >= 0 ) {
+ /* "NETSCAPE EXTENSION" for looped animation GIF */
+ avio_w8(pb, 0x21); /* GIF Extension code */
+ avio_w8(pb, 0xff); /* Application Extension Label */
+ avio_w8(pb, 0x0b); /* Length of Application Block */
avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
- avio_w8(pb, 0x03); // byte 15
- avio_w8(pb, 0x01); // byte 16
+ avio_w8(pb, 0x03); /* Length of Data Sub-Block */
+ avio_w8(pb, 0x01);
avio_wl16(pb, (uint16_t)loop_count);
- avio_w8(pb, 0x00); // byte 19
- }
-#endif
- return 0;
-}
-
-/* this is maybe slow, but allows for extensions */
-static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
-{
- return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6);
-}
-
-static int gif_image_write_image(AVIOContext *pb,
- int x1, int y1, int width, int height,
- const uint8_t *buf, int linesize, int pix_fmt)
-{
- PutBitContext p;
- uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
- int i, left, w, v;
- const uint8_t *ptr;
- /* image block */
-
- avio_w8(pb, 0x2c);
- avio_wl16(pb, x1);
- avio_wl16(pb, y1);
- avio_wl16(pb, width);
- avio_wl16(pb, height);
- avio_w8(pb, 0x00); /* flags */
- /* no local clut */
-
- avio_w8(pb, 0x08);
-
- left = width * height;
-
- init_put_bits(&p, buffer, 130);
-
-/*
- * the thing here is the bitstream is written as little packets, with a size
- * byte before but it's still the same bitstream between packets (no flush !)
- */
- ptr = buf;
- w = width;
- while (left > 0) {
- put_bits(&p, 9, 0x0100); /* clear code */
-
- for (i = (left < GIF_CHUNKS) ? left : GIF_CHUNKS; i; i--) {
- if (pix_fmt == AV_PIX_FMT_RGB24) {
- v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
- ptr += 3;
- } else {
- v = *ptr++;
- }
- put_bits(&p, 9, v);
- if (--w == 0) {
- w = width;
- buf += linesize;
- ptr = buf;
- }
- }
-
- if (left <= GIF_CHUNKS) {
- put_bits(&p, 9, 0x101); /* end of stream */
- flush_put_bits(&p);
- }
- if (put_bits_ptr(&p) - p.buf > 0) {
- avio_w8(pb, put_bits_ptr(&p) - p.buf); /* byte count of the packet */
- avio_write(pb, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */
- p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
- }
- left -= GIF_CHUNKS;
+ avio_w8(pb, 0x00); /* Data Sub-block Terminator */
}
- avio_w8(pb, 0x00); /* end of image block */
return 0;
}
typedef struct {
- AVClass *class; /** Class for private options. */
- int64_t time, file_time;
- uint8_t buffer[100]; /* data chunks */
+ AVClass *class;
int loop;
+ int last_delay;
+ AVPacket *prev_pkt;
+ int duration;
} GIFContext;
static int gif_write_header(AVFormatContext *s)
{
GIFContext *gif = s->priv_data;
AVIOContext *pb = s->pb;
- AVCodecContext *enc, *video_enc;
- int i, width, height /*, rate*/;
-
-/* XXX: do we reject audio streams or just ignore them ?
- * if (s->nb_streams > 1)
- * return -1;
- */
- gif->time = 0;
- gif->file_time = 0;
+ AVCodecContext *video_enc;
+ int width, height;
+ uint32_t palette[AVPALETTE_COUNT];
- video_enc = NULL;
- for (i = 0; i < s->nb_streams; i++) {
- enc = s->streams[i]->codec;
- if (enc->codec_type != AVMEDIA_TYPE_AUDIO)
- video_enc = enc;
+ if (s->nb_streams != 1 ||
+ s->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ s->streams[0]->codec->codec_id != AV_CODEC_ID_GIF) {
+ av_log(s, AV_LOG_ERROR,
+ "GIF muxer supports only a single video GIF stream.\n");
+ return AVERROR(EINVAL);
}
- if (!video_enc) {
- av_free(gif);
- return -1;
- } else {
- width = video_enc->width;
- height = video_enc->height;
-// rate = video_enc->time_base.den;
- }
+ video_enc = s->streams[0]->codec;
+ width = video_enc->width;
+ height = video_enc->height;
- if (video_enc->pix_fmt != AV_PIX_FMT_RGB24) {
- av_log(s, AV_LOG_ERROR,
- "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
- return AVERROR(EIO);
+ 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);
+ } else {
+ gif_image_write_header(pb, width, height, gif->loop, palette);
}
- gif_image_write_header(pb, width, height, gif->loop, NULL);
-
avio_flush(s->pb);
return 0;
}
-static int gif_write_video(AVFormatContext *s, AVCodecContext *enc,
- const uint8_t *buf, int size)
+static int flush_packet(AVFormatContext *s, AVPacket *new)
{
+ GIFContext *gif = s->priv_data;
+ int size;
AVIOContext *pb = s->pb;
- int jiffies;
+ uint8_t flags = 0x4, transparent_color_index = 0x1f;
+ const uint32_t *palette;
+ AVPacket *pkt = gif->prev_pkt;
+
+ if (!pkt)
+ return 0;
+
+ /* Mark one colour as transparent if the input palette contains at least
+ * one colour that is more than 50% transparent. */
+ palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
+ if (palette && size != AVPALETTE_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (palette) {
+ unsigned i, smallest_alpha = 0xff;
+
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t v = palette[i];
+ if (v >> 24 < smallest_alpha) {
+ smallest_alpha = v >> 24;
+ transparent_color_index = i;
+ }
+ }
+ if (smallest_alpha < 128)
+ flags |= 0x1; /* Transparent Color Flag */
+ }
+
+ if (new && new->pts != AV_NOPTS_VALUE)
+ gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts);
+ else if (!new && gif->last_delay >= 0)
+ gif->duration = gif->last_delay;
/* graphic control extension block */
avio_w8(pb, 0x21);
avio_w8(pb, 0xf9);
avio_w8(pb, 0x04); /* block size */
- avio_w8(pb, 0x04); /* flags */
-
- /* 1 jiffy is 1/70 s */
- /* the delay_time field indicates the number of jiffies - 1 */
- /* XXX: should use delay, in order to be more accurate */
- /* instead of using the same rounded value each time */
- /* XXX: don't even remember if I really use it for now */
- jiffies = (70 * enc->time_base.num / enc->time_base.den) - 1;
-
- avio_wl16(pb, jiffies);
-
- avio_w8(pb, 0x1f); /* transparent color index */
+ avio_w8(pb, flags);
+ avio_wl16(pb, gif->duration);
+ avio_w8(pb, transparent_color_index);
avio_w8(pb, 0x00);
- gif_image_write_image(pb, 0, 0, enc->width, enc->height,
- buf, enc->width * 3, AV_PIX_FMT_RGB24);
+ avio_write(pb, pkt->data, pkt->size);
+
+ av_free_packet(gif->prev_pkt);
+ if (new)
+ av_copy_packet(gif->prev_pkt, new);
- avio_flush(s->pb);
return 0;
}
static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
{
- AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
- if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
- return 0; /* just ignore audio */
- else
- return gif_write_video(s, codec, pkt->data, pkt->size);
+ GIFContext *gif = s->priv_data;
+
+ if (!gif->prev_pkt) {
+ gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt));
+ if (!gif->prev_pkt)
+ return AVERROR(ENOMEM);
+ return av_copy_packet(gif->prev_pkt, pkt);
+ }
+ return flush_packet(s, pkt);
}
static int gif_write_trailer(AVFormatContext *s)
{
+ GIFContext *gif = s->priv_data;
AVIOContext *pb = s->pb;
+ flush_packet(s, NULL);
+ av_freep(&gif->prev_pkt);
avio_w8(pb, 0x3b);
return 0;
@@ -354,8 +192,10 @@ static int gif_write_trailer(AVFormatContext *s)
#define OFFSET(x) offsetof(GIFContext, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "loop", "Number of times to loop the output.", OFFSET(loop),
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC },
+ { "loop", "Number of times to loop the output: -1 - no loop, 0 - infinite loop", OFFSET(loop),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 65535, ENC },
+ { "final_delay", "Force delay (in centiseconds) after the last frame", OFFSET(last_delay),
+ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
{ NULL },
};
@@ -373,9 +213,10 @@ AVOutputFormat ff_gif_muxer = {
.extensions = "gif",
.priv_data_size = sizeof(GIFContext),
.audio_codec = AV_CODEC_ID_NONE,
- .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .video_codec = AV_CODEC_ID_GIF,
.write_header = gif_write_header,
.write_packet = gif_write_packet,
.write_trailer = gif_write_trailer,
.priv_class = &gif_muxer_class,
+ .flags = AVFMT_VARIABLE_FPS,
};
diff --git a/ffmpeg/libavformat/gifdec.c b/ffmpeg/libavformat/gifdec.c
index 1122849..2981bca 100644
--- a/ffmpeg/libavformat/gifdec.c
+++ b/ffmpeg/libavformat/gifdec.c
@@ -44,6 +44,13 @@ typedef struct GIFDemuxContext {
*/
int min_delay;
int default_delay;
+
+ /**
+ * loop options
+ */
+ int total_iter;
+ int iter_count;
+ int ignore_loop;
} GIFDemuxContext;
/**
@@ -156,6 +163,27 @@ static int gif_read_ext(AVFormatContext *s)
/* skip the rest of the Graphic Control Extension block */
if ((ret = avio_skip(pb, sb_size - 3)) < 0 )
return ret;
+ } else if (ext_label == GIF_APP_EXT_LABEL) {
+ uint8_t data[256];
+
+ sb_size = avio_r8(pb);
+ ret = avio_read(pb, data, sb_size);
+ if (ret < 0 || !sb_size)
+ return ret;
+
+ if (sb_size == strlen(NETSCAPE_EXT_STR)) {
+ sb_size = avio_r8(pb);
+ ret = avio_read(pb, data, sb_size);
+ if (ret < 0 || !sb_size)
+ return ret;
+
+ if (sb_size == 3 && data[0] == 1) {
+ gdc->total_iter = AV_RL16(data+1);
+
+ if (gdc->total_iter == 0)
+ gdc->total_iter = -1;
+ }
+ }
}
if ((ret = gif_skip_subblocks(pb)) < 0)
@@ -268,9 +296,12 @@ resync:
}
}
- if (ret >= 0 && !frame_parsed) {
+ if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) {
/* This might happen when there is no image block
* between extension blocks and GIF_TRAILER or EOF */
+ if (!gdc->ignore_loop && (block_label == GIF_TRAILER || url_feof(pb))
+ && (gdc->total_iter < 0 || ++gdc->iter_count < gdc->total_iter))
+ return avio_seek(pb, 0, SEEK_SET);
return AVERROR_EOF;
} else
return ret;
@@ -279,6 +310,7 @@ resync:
static const AVOption options[] = {
{ "min_delay" , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay) , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY} , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
{ "default_delay", "default delay between frames (in hundredths of second)" , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
+ { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_INT, {.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
diff --git a/ffmpeg/libavformat/gsmdec.c b/ffmpeg/libavformat/gsmdec.c
index 9899266..dbe557b 100644
--- a/ffmpeg/libavformat/gsmdec.c
+++ b/ffmpeg/libavformat/gsmdec.c
@@ -2,20 +2,20 @@
* RAW GSM demuxer
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,7 +80,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass gsm_class = {
.class_name = "gsm demuxer",
.item_name = av_default_item_name,
.option = options,
@@ -96,5 +96,5 @@ AVInputFormat ff_gsm_demuxer = {
.flags = AVFMT_GENERIC_INDEX,
.extensions = "gsm",
.raw_codec_id = AV_CODEC_ID_GSM,
- .priv_class = &class,
+ .priv_class = &gsm_class,
};
diff --git a/ffmpeg/libavformat/gxf.c b/ffmpeg/libavformat/gxf.c
index 86e6291..c36479a 100644
--- a/ffmpeg/libavformat/gxf.c
+++ b/ffmpeg/libavformat/gxf.c
@@ -116,12 +116,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->codec_id = AV_CODEC_ID_MJPEG;
break;
case 13:
- case 15:
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_DVVIDEO;
- break;
case 14:
+ case 15:
case 16:
+ case 25:
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DVVIDEO;
break;
@@ -165,6 +163,12 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
st->codec->sample_rate = 48000;
break;
+ case 26: /* AVCi50 / AVCi100 (AVC Intra) */
+ case 29: /* AVCHD */
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_H264;
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ break;
// timecode tracks:
case 7:
case 8:
@@ -172,6 +176,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = AV_CODEC_ID_NONE;
break;
+ case 30:
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_DNXHD;
+ break;
default:
st->codec->codec_type = AVMEDIA_TYPE_UNKNOWN;
st->codec->codec_id = AV_CODEC_ID_NONE;
diff --git a/ffmpeg/libavformat/gxfenc.c b/ffmpeg/libavformat/gxfenc.c
index 28acb74..12031f7 100644
--- a/ffmpeg/libavformat/gxfenc.c
+++ b/ffmpeg/libavformat/gxfenc.c
@@ -217,12 +217,27 @@ static int gxf_write_mpeg_auxiliary(AVIOContext *pb, AVStream *st)
return size + 3;
}
+static int gxf_write_dv_auxiliary(AVIOContext *pb, AVStream *st)
+{
+ int64_t track_aux_data = 0;
+
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
+ if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P)
+ track_aux_data |= 0x01; /* marks stream as DVCAM instead of DVPRO */
+ track_aux_data |= 0x40000000; /* aux data is valid */
+ avio_wl64(pb, track_aux_data);
+ return 8;
+}
+
static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFContext *gxf)
{
uint32_t timecode = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop,
gxf->tc.hh, gxf->tc.mm,
gxf->tc.ss, gxf->tc.ff);
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
avio_wl32(pb, timecode);
/* reserved */
avio_wl32(pb, 0);
@@ -234,7 +249,6 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
GXFContext *gxf = s->priv_data;
AVIOContext *pb = s->pb;
int64_t pos;
- int mpeg = sc->track_type == 4 || sc->track_type == 9;
/* track description section */
avio_w8(pb, sc->media_type + 0x80);
@@ -250,13 +264,21 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
avio_wb16(pb, sc->media_info);
avio_w8(pb, 0);
- if (!mpeg) {
- /* auxiliary information */
- avio_w8(pb, TRACK_AUX);
- avio_w8(pb, 8);
- if (sc->track_type == 3)
+ switch (sc->track_type) {
+ case 3: /* timecode */
gxf_write_timecode_auxiliary(pb, gxf);
- else
+ break;
+ case 4: /* MPEG2 */
+ case 9: /* MPEG1 */
+ gxf_write_mpeg_auxiliary(pb, s->streams[index]);
+ break;
+ case 5: /* DV25 */
+ case 6: /* DV50 */
+ gxf_write_dv_auxiliary(pb, s->streams[index]);
+ break;
+ default:
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
avio_wl64(pb, 0);
}
@@ -265,9 +287,6 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
avio_w8(pb, 4);
avio_wb32(pb, 0);
- if (mpeg)
- gxf_write_mpeg_auxiliary(pb, s->streams[index]);
-
/* frame rate */
avio_w8(pb, TRACK_FPS);
avio_w8(pb, 4);
@@ -362,12 +381,13 @@ static int gxf_write_map_packet(AVFormatContext *s, int rewrite)
if (!rewrite) {
if (!(gxf->map_offsets_nb % 30)) {
- gxf->map_offsets = av_realloc_f(gxf->map_offsets,
- sizeof(*gxf->map_offsets),
- gxf->map_offsets_nb+30);
- if (!gxf->map_offsets) {
+ int err;
+ if ((err = av_reallocp_array(&gxf->map_offsets,
+ gxf->map_offsets_nb + 30,
+ sizeof(*gxf->map_offsets))) < 0) {
+ gxf->map_offsets_nb = 0;
av_log(s, AV_LOG_ERROR, "could not realloc map offsets\n");
- return -1;
+ return err;
}
}
gxf->map_offsets[gxf->map_offsets_nb++] = pos; // do not increment here
@@ -534,13 +554,20 @@ static int gxf_write_umf_media_timecode(AVIOContext *pb, int drop)
return 32;
}
-static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc)
+static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc, AVStream *st)
{
- int i;
+ int dv_umf_data = 0;
- for (i = 0; i < 8; i++) {
- avio_wb32(pb, 0);
- }
+ if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P)
+ dv_umf_data |= 0x20; /* marks as DVCAM instead of DVPRO */
+ avio_wl32(pb, dv_umf_data);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
return 32;
}
@@ -604,7 +631,7 @@ static int gxf_write_umf_media_description(AVFormatContext *s)
gxf_write_umf_media_audio(pb, sc);
break;
case AV_CODEC_ID_DVVIDEO:
- gxf_write_umf_media_dv(pb, sc);
+ gxf_write_umf_media_dv(pb, sc, st);
break;
}
}
@@ -681,6 +708,7 @@ static int gxf_write_header(AVFormatContext *s)
GXFStreamContext *vsc = NULL;
uint8_t tracks[255] = {0};
int i, media_info = 0;
+ int ret;
AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
if (!pb->seekable) {
@@ -801,7 +829,8 @@ static int gxf_write_header(AVFormatContext *s)
gxf_init_timecode_track(&gxf->timecode_track, vsc);
gxf->flags |= 0x200000; // time code track is non-drop frame
- gxf_write_map_packet(s, 0);
+ if ((ret = gxf_write_map_packet(s, 0)) < 0)
+ return ret;
gxf_write_flt_packet(s);
gxf_write_umf_packet(s);
@@ -825,6 +854,7 @@ static int gxf_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t end;
int i;
+ int ret;
ff_audio_interleave_close(s);
@@ -832,14 +862,16 @@ static int gxf_write_trailer(AVFormatContext *s)
end = avio_tell(pb);
avio_seek(pb, 0, SEEK_SET);
/* overwrite map, flt and umf packets with new values */
- gxf_write_map_packet(s, 1);
+ if ((ret = gxf_write_map_packet(s, 1)) < 0)
+ return ret;
gxf_write_flt_packet(s);
gxf_write_umf_packet(s);
avio_flush(pb);
/* update duration in all map packets */
for (i = 1; i < gxf->map_offsets_nb; i++) {
avio_seek(pb, gxf->map_offsets[i], SEEK_SET);
- gxf_write_map_packet(s, 1);
+ if ((ret = gxf_write_map_packet(s, 1)) < 0)
+ return ret;
avio_flush(pb);
}
@@ -917,7 +949,8 @@ 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);
if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO && pkt->size % 4) /* MPEG-2 frames must be padded */
@@ -930,12 +963,14 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (!(gxf->flt_entries_nb % 500)) {
- gxf->flt_entries = av_realloc_f(gxf->flt_entries,
- sizeof(*gxf->flt_entries),
- gxf->flt_entries_nb+500);
- if (!gxf->flt_entries) {
+ int err;
+ if ((err = av_reallocp_array(&gxf->flt_entries,
+ gxf->flt_entries_nb + 500,
+ sizeof(*gxf->flt_entries))) < 0) {
+ gxf->flt_entries_nb = 0;
+ gxf->nb_fields = 0;
av_log(s, AV_LOG_ERROR, "could not reallocate flt entries\n");
- return -1;
+ return err;
}
}
gxf->flt_entries[gxf->flt_entries_nb++] = packet_start_offset;
@@ -946,12 +981,11 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
gxf->packet_count++;
if (gxf->packet_count == 100) {
- gxf_write_map_packet(s, 0);
+ if ((ret = gxf_write_map_packet(s, 0)) < 0)
+ return ret;
gxf->packet_count = 0;
}
- avio_flush(pb);
-
return 0;
}
diff --git a/ffmpeg/libavformat/h261dec.c b/ffmpeg/libavformat/h261dec.c
index 1b254d6..a1d6821 100644
--- a/ffmpeg/libavformat/h261dec.c
+++ b/ffmpeg/libavformat/h261dec.c
@@ -25,40 +25,37 @@
static int h261_probe(AVProbeData *p)
{
- uint32_t code= -1;
int i;
int valid_psc=0;
int invalid_psc=0;
int next_gn=0;
int src_fmt=0;
- GetBitContext gb;
- init_get_bits(&gb, p->buf, p->buf_size*8);
+ for(i=0; i<p->buf_size; i++){
+ if ((AV_RB16(&p->buf[i]) - 1) < 0xFFU) {
+ int shift = av_log2_16bit(p->buf[i+1]);
+ uint32_t code = AV_RB64(&p->buf[FFMAX(i-1, 0)]) >> (24+shift);
+ if ((code & 0xffff0000) == 0x10000) {
+ int gn= (code>>12)&0xf;
+ if(!gn)
+ src_fmt= code&8;
+ if(gn != next_gn) invalid_psc++;
+ else valid_psc++;
- for(i=0; i<p->buf_size*8; i++){
- if ((code & 0x01ff0000) || !(code & 0xff00)) {
- code = (code<<8) + get_bits(&gb, 8);
- i += 7;
- } else
- code = (code<<1) + get_bits1(&gb);
- if ((code & 0xffff0000) == 0x10000) {
- int gn= (code>>12)&0xf;
- if(!gn)
- src_fmt= code&8;
- if(gn != next_gn) invalid_psc++;
- else valid_psc++;
-
- if(src_fmt){ // CIF
- next_gn= (gn+1 )%13;
- }else{ //QCIF
- next_gn= (gn+1+!!gn)% 7;
+ if(src_fmt){ // CIF
+ static const int lut[16]={1,2,3,4,5,6,7,8,9,10,11,12,0,16,16,16};
+ next_gn = lut[gn];
+ }else{ //QCIF
+ static const int lut[16]={1,3,16,5,16,0,16,16,16,16,16,16,16,16,16,16};
+ next_gn = lut[gn];
+ }
}
}
}
if(valid_psc > 2*invalid_psc + 6){
- return 50;
+ return AVPROBE_SCORE_EXTENSION;
}else if(valid_psc > 2*invalid_psc + 2)
- return 25;
+ return AVPROBE_SCORE_EXTENSION / 2;
return 0;
}
diff --git a/ffmpeg/libavformat/h263dec.c b/ffmpeg/libavformat/h263dec.c
index 667fdbd..e6e0345 100644
--- a/ffmpeg/libavformat/h263dec.c
+++ b/ffmpeg/libavformat/h263dec.c
@@ -56,9 +56,9 @@ static int h263_probe(AVProbeData *p)
}
}
if(valid_psc > 2*invalid_psc + 2*res_change + 3){
- return 50;
+ return AVPROBE_SCORE_EXTENSION;
}else if(valid_psc > 2*invalid_psc)
- return 25;
+ return AVPROBE_SCORE_EXTENSION / 2;
return 0;
}
diff --git a/ffmpeg/libavformat/h264dec.c b/ffmpeg/libavformat/h264dec.c
index 9c67ab9..76073dd 100644
--- a/ffmpeg/libavformat/h264dec.c
+++ b/ffmpeg/libavformat/h264dec.c
@@ -24,47 +24,55 @@
static int h264_probe(AVProbeData *p)
{
- uint32_t code= -1;
- int sps=0, pps=0, idr=0, res=0, sli=0;
+ uint32_t code = -1;
+ int sps = 0, pps = 0, idr = 0, res = 0, sli = 0;
int i;
- 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 ref_idc= (code>>5)&3;
- int type = code & 0x1F;
- static const int8_t ref_zero[32]={
- 2, 0, 0, 0, 0,-1, 1,-1,
- -1, 1, 1, 1, 1,-1, 2, 2,
- 2, 2, 2, 0, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2
+ int ref_idc = (code >> 5) & 3;
+ int type = code & 0x1F;
+ static const int8_t ref_zero[] = {
+ 2, 0, 0, 0, 0, -1, 1, -1,
+ -1, 1, 1, 1, 1, -1, 2, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2
};
- if(code & 0x80) //forbidden bit
+ if (code & 0x80) // forbidden_bit
return 0;
- if(ref_zero[type] == 1 && ref_idc)
+ if (ref_zero[type] == 1 && ref_idc)
return 0;
- if(ref_zero[type] ==-1 && !ref_idc)
+ if (ref_zero[type] == -1 && !ref_idc)
return 0;
- if(ref_zero[type] == 2)
+ if (ref_zero[type] == 2)
res++;
- switch(type){
- case 1: sli++; break;
- case 5: idr++; break;
- case 7:
+ switch (type) {
+ case 1:
+ sli++;
+ break;
+ case 5:
+ idr++;
+ break;
+ case 7:
if (p->buf[i + 2] & 0x03)
return 0;
sps++;
break;
- case 8: pps++; break;
+ case 8:
+ pps++;
+ break;
}
}
}
- if(sps && pps && (idr||sli>3) && res<(sps+pps+idr))
- return AVPROBE_SCORE_MAX/2+1; // +1 for .mpg
+
+ if (sps && pps && (idr || sli > 3) && res < (sps + pps + idr))
+ return AVPROBE_SCORE_EXTENSION + 1; // 1 more than .mpg
+
return 0;
}
-FF_DEF_RAWVIDEO_DEMUXER(h264 , "raw H.264 video", h264_probe, "h26l,h264,264", AV_CODEC_ID_H264)
+FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264)
diff --git a/ffmpeg/libavformat/hls.c b/ffmpeg/libavformat/hls.c
index 7de6059..471a62d 100644
--- a/ffmpeg/libavformat/hls.c
+++ b/ffmpeg/libavformat/hls.c
@@ -56,7 +56,7 @@ enum KeyType {
};
struct segment {
- int duration;
+ int64_t duration;
char url[MAX_URL_SIZE];
char key[MAX_URL_SIZE];
enum KeyType key_type;
@@ -81,7 +81,7 @@ struct variant {
int stream_offset;
int finished;
- int target_duration;
+ int64_t target_duration;
int start_seq_no;
int n_segments;
struct segment **segments;
@@ -105,6 +105,7 @@ typedef struct HLSContext {
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
+ char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context
} HLSContext;
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
@@ -206,24 +207,27 @@ static void handle_key_args(struct key_info *info, const char *key,
static int parse_playlist(HLSContext *c, const char *url,
struct variant *var, AVIOContext *in)
{
- int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ int64_t duration = 0;
enum KeyType key_type = KEY_NONE;
uint8_t iv[16] = "";
int has_iv = 0;
char key[MAX_URL_SIZE] = "";
- char line[1024];
+ char line[MAX_URL_SIZE];
const char *ptr;
int close_in = 0;
+ uint8_t *new_url = NULL;
if (!in) {
AVDictionary *opts = NULL;
close_in = 1;
- /* Some HLS servers dont like being sent the range header */
+ /* Some HLS servers don't like being sent the range header */
av_dict_set(&opts, "seekable", "0", 0);
// broker prior HTTP options that should be consistent across requests
av_dict_set(&opts, "user-agent", c->user_agent, 0);
av_dict_set(&opts, "cookies", c->cookies, 0);
+ av_dict_set(&opts, "headers", c->headers, 0);
ret = avio_open2(&in, url, AVIO_FLAG_READ,
c->interrupt_callback, &opts);
@@ -232,6 +236,9 @@ static int parse_playlist(HLSContext *c, const char *url,
return ret;
}
+ if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0)
+ url = new_url;
+
read_chomp_line(in, line, sizeof(line));
if (strcmp(line, "#EXTM3U")) {
ret = AVERROR_INVALIDDATA;
@@ -271,7 +278,7 @@ static int parse_playlist(HLSContext *c, const char *url,
goto fail;
}
}
- var->target_duration = atoi(ptr);
+ var->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);
@@ -286,7 +293,7 @@ static int parse_playlist(HLSContext *c, const char *url,
var->finished = 1;
} else if (av_strstart(line, "#EXTINF:", &ptr)) {
is_segment = 1;
- duration = atoi(ptr);
+ duration = atof(ptr) * AV_TIME_BASE;
} else if (av_strstart(line, "#", NULL)) {
continue;
} else if (line[0]) {
@@ -332,6 +339,7 @@ static int parse_playlist(HLSContext *c, const char *url,
var->last_load_time = av_gettime();
fail:
+ av_free(new_url);
if (close_in)
avio_close(in);
return ret;
@@ -346,6 +354,7 @@ static int open_input(HLSContext *c, struct variant *var)
// broker prior HTTP options that should be consistent across requests
av_dict_set(&opts, "user-agent", c->user_agent, 0);
av_dict_set(&opts, "cookies", c->cookies, 0);
+ av_dict_set(&opts, "headers", c->headers, 0);
av_dict_set(&opts, "seekable", "0", 0);
if (seg->key_type == KEY_NONE) {
@@ -413,7 +422,6 @@ restart:
int64_t reload_interval = v->n_segments > 0 ?
v->segments[v->n_segments - 1]->duration :
v->target_duration;
- reload_interval *= 1000000;
reload:
if (!v->finished &&
@@ -423,7 +431,7 @@ reload:
/* 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. */
- reload_interval = v->target_duration * 500000LL;
+ reload_interval = v->target_duration / 2;
}
if (v->cur_seq_no < v->start_seq_no) {
av_log(NULL, AV_LOG_WARNING,
@@ -457,7 +465,8 @@ reload:
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) {
+ 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++) {
@@ -494,6 +503,12 @@ static int hls_read_header(AVFormatContext *s)
av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies));
if (c->cookies && !strlen(c->cookies))
av_freep(&c->cookies);
+
+ // get the previous headers & set back to null if string size is zero
+ av_freep(&c->headers);
+ av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers));
+ if (c->headers && !strlen(c->headers))
+ av_freep(&c->headers);
}
if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
@@ -526,7 +541,7 @@ static int hls_read_header(AVFormatContext *s)
int64_t duration = 0;
for (i = 0; i < c->variants[0]->n_segments; i++)
duration += c->variants[0]->segments[i]->duration;
- s->duration = duration * AV_TIME_BASE;
+ s->duration = duration;
}
/* Open the demuxer for each variant */
@@ -534,7 +549,8 @@ static int hls_read_header(AVFormatContext *s)
struct variant *v = c->variants[i];
AVInputFormat *in_fmt = NULL;
char bitrate_str[20];
- AVProgram *program = NULL;
+ AVProgram *program;
+
if (v->n_segments == 0)
continue;
@@ -570,18 +586,17 @@ static int hls_read_header(AVFormatContext *s)
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);
if (ret < 0)
goto fail;
- v->stream_offset = stream_offset;
v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
ret = avformat_find_stream_info(v->ctx, NULL);
if (ret < 0)
goto fail;
snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth);
- /* Create new AVprogram for variant i */
program = av_new_program(s, i);
if (!program)
goto fail;
@@ -678,8 +693,11 @@ start:
reset_packet(&var->pkt);
break;
} else {
- if (c->first_timestamp == AV_NOPTS_VALUE)
- c->first_timestamp = var->pkt.dts;
+ 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);
}
if (c->seek_timestamp == AV_NOPTS_VALUE)
@@ -699,24 +717,35 @@ start:
c->seek_timestamp = AV_NOPTS_VALUE;
break;
}
+ av_free_packet(&var->pkt);
+ reset_packet(&var->pkt);
}
}
- /* Check if this stream has the packet with the lowest dts */
+ /* Check if this stream still is on an earlier segment number, or
+ * has the packet with the lowest dts */
if (var->pkt.data) {
- if(minvariant < 0) {
+ struct variant *minvar = minvariant < 0 ?
+ NULL : c->variants[minvariant];
+ if (minvariant < 0 || var->cur_seq_no < minvar->cur_seq_no) {
minvariant = i;
- } else {
- struct variant *minvar = c->variants[minvariant];
- 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];
+ } 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( 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)
+ 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;
+ }
}
}
}
@@ -757,7 +786,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
s->streams[stream_index]->time_base.den,
flags & AVSEEK_FLAG_BACKWARD ?
AV_ROUND_DOWN : AV_ROUND_UP);
- timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ?
+ 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);
@@ -770,12 +799,9 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
for (i = 0; i < c->n_variants; i++) {
/* Reset reading */
struct variant *var = c->variants[i];
- int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
- av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
- s->streams[stream_index]->time_base.den :
- AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
- AV_ROUND_DOWN : AV_ROUND_UP);
- if (var->input) {
+ int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ?
+ 0 : c->first_timestamp;
+ if (var->input) {
ffurl_close(var->input);
var->input = NULL;
}
diff --git a/ffmpeg/libavformat/hlsenc.c b/ffmpeg/libavformat/hlsenc.c
index 18914c0..3b50397 100644
--- a/ffmpeg/libavformat/hlsenc.c
+++ b/ffmpeg/libavformat/hlsenc.c
@@ -20,6 +20,7 @@
*/
#include <float.h>
+#include <stdint.h>
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
@@ -49,7 +50,7 @@ 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
+ int64_t duration; // last segment duration computed so far, in seconds
int nb_entries;
ListEntry *list;
ListEntry *end_list;
@@ -69,6 +70,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;
@@ -164,14 +166,12 @@ static int hls_start(AVFormatContext *s)
AVFormatContext *oc = c->avf;
int err = 0;
- if (c->wrap)
- c->number %= c->wrap;
-
if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- c->basename, c->number++) < 0) {
+ c->basename, c->wrap ? c->number % c->wrap : c->number) < 0) {
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename);
return AVERROR(EINVAL);
}
+ c->number++;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
@@ -253,25 +253,28 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
AVFormatContext *oc = hls->avf;
AVStream *st = s->streams[pkt->stream_index];
int64_t end_pts = hls->recording_time * hls->number;
- int ret, is_ref_pkt = 0;
+ int is_ref_pkt = 1;
+ int ret, can_split = 1;
if (hls->start_pts == AV_NOPTS_VALUE) {
hls->start_pts = pkt->pts;
hls->end_pts = pkt->pts;
}
- if ((hls->has_video && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
- pkt->pts != AV_NOPTS_VALUE) {
- is_ref_pkt = 1;
- hls->duration = av_rescale(pkt->pts - hls->end_pts,
- st->time_base.num, st->time_base.den);
+ if (hls->has_video) {
+ can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ pkt->flags & AV_PKT_FLAG_KEY;
+ is_ref_pkt = st->codec->codec_type == AVMEDIA_TYPE_VIDEO;
}
+ if (pkt->pts == AV_NOPTS_VALUE)
+ is_ref_pkt = can_split = 0;
- if (is_ref_pkt &&
- av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
- end_pts, AV_TIME_BASE_Q) >= 0 &&
- pkt->flags & AV_PKT_FLAG_KEY) {
+ if (is_ref_pkt)
+ hls->duration = av_rescale(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) {
ret = append_entry(hls, hls->duration);
if (ret)
return ret;
diff --git a/ffmpeg/libavformat/hlsproto.c b/ffmpeg/libavformat/hlsproto.c
index 4e35043..f6fcbe5 100644
--- a/ffmpeg/libavformat/hlsproto.c
+++ b/ffmpeg/libavformat/hlsproto.c
@@ -45,7 +45,7 @@
*/
struct segment {
- int duration;
+ int64_t duration;
char url[MAX_URL_SIZE];
};
@@ -56,7 +56,7 @@ struct variant {
typedef struct HLSContext {
char playlisturl[MAX_URL_SIZE];
- int target_duration;
+ int64_t target_duration;
int start_seq_no;
int finished;
int n_segments;
@@ -111,7 +111,8 @@ static int parse_playlist(URLContext *h, const char *url)
{
HLSContext *s = h->priv_data;
AVIOContext *in;
- int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ int64_t duration = 0;
char line[1024];
const char *ptr;
@@ -134,14 +135,14 @@ static int parse_playlist(URLContext *h, const char *url)
&info);
bandwidth = atoi(info.bandwidth);
} else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
- s->target_duration = atoi(ptr);
+ s->target_duration = atoi(ptr) * AV_TIME_BASE;
} else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
s->start_seq_no = atoi(ptr);
} else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
s->finished = 1;
} else if (av_strstart(line, "#EXTINF:", &ptr)) {
is_segment = 1;
- duration = atoi(ptr);
+ duration = atof(ptr) * AV_TIME_BASE;
} else if (av_strstart(line, "#", NULL)) {
continue;
} else if (line[0]) {
@@ -270,7 +271,6 @@ start:
reload_interval = s->n_segments > 0 ?
s->segments[s->n_segments - 1]->duration :
s->target_duration;
- reload_interval *= 1000000;
retry:
if (!s->finished) {
int64_t now = av_gettime();
@@ -280,7 +280,7 @@ retry:
/* 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. */
- reload_interval = s->target_duration * 500000LL;
+ reload_interval = s->target_duration / 2;
}
}
if (s->cur_seq_no < s->start_seq_no) {
diff --git a/ffmpeg/libavformat/http.c b/ffmpeg/libavformat/http.c
index 1e3cff7..0619e2a 100644
--- a/ffmpeg/libavformat/http.c
+++ b/ffmpeg/libavformat/http.c
@@ -29,6 +29,10 @@
#include "url.h"
#include "libavutil/opt.h"
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
/* XXX: POST protocol is not completely implemented because ffmpeg uses
only a subset of it. */
@@ -49,7 +53,9 @@ typedef struct {
char *content_type;
char *user_agent;
int64_t off, filesize;
- char location[MAX_URL_SIZE];
+ 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
+ char *location;
HTTPAuthState auth_state;
HTTPAuthState proxy_auth_state;
char *headers;
@@ -62,26 +68,43 @@ typedef struct {
uint8_t *post_data;
int post_datalen;
int is_akamai;
- int rw_timeout;
+ 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;
+ char *icy_metadata_headers;
+ char *icy_metadata_packet;
+#if CONFIG_ZLIB
+ int compressed;
+ z_stream inflate_stream;
+ uint8_t *inflate_buffer;
+#endif
+ AVDictionary *chained_options;
+ int send_expect_100;
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
-#define DEC AV_OPT_FLAG_DECODING_PARAM
+#define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
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 },
-{"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC},
+{"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 },
-{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
{"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
-{"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, 0 },
+{"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 },
+{"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 },
{NULL}
};
#define HTTP_CLASS(flavor)\
@@ -109,7 +132,7 @@ void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
}
/* return non zero if error */
-static int http_open_cnx(URLContext *h)
+static int http_open_cnx(URLContext *h, AVDictionary **options)
{
const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
char hostname[1024], hoststr[1024], proto[10];
@@ -159,15 +182,8 @@ static int http_open_cnx(URLContext *h)
ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
if (!s->hd) {
- AVDictionary *opts = NULL;
- char opts_format[20];
- if (s->rw_timeout != -1) {
- snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
- av_dict_set(&opts, "timeout", opts_format, 0);
- } /* if option is not given, don't pass it and let tcp use its own default */
err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
- &h->interrupt_callback, &opts);
- av_dict_free(&opts);
+ &h->interrupt_callback, options);
if (err < 0)
goto fail;
}
@@ -216,16 +232,27 @@ static int http_open_cnx(URLContext *h)
int ff_http_do_new_request(URLContext *h, const char *uri)
{
HTTPContext *s = h->priv_data;
+ AVDictionary *options = NULL;
+ int ret;
s->off = 0;
- av_strlcpy(s->location, uri, sizeof(s->location));
-
- return http_open_cnx(h);
+ s->icy_data_read = 0;
+ av_free(s->location);
+ s->location = av_strdup(uri);
+ if (!s->location)
+ return AVERROR(ENOMEM);
+
+ av_dict_copy(&options, s->chained_options, 0);
+ ret = http_open_cnx(h, &options);
+ av_dict_free(&options);
+ return ret;
}
-static int http_open(URLContext *h, const char *uri, int flags)
+static int http_open(URLContext *h, const char *uri, int flags,
+ AVDictionary **options)
{
HTTPContext *s = h->priv_data;
+ int ret;
if( s->seekable == 1 )
h->is_streamed = 0;
@@ -233,7 +260,11 @@ static int http_open(URLContext *h, const char *uri, int flags)
h->is_streamed = 1;
s->filesize = -1;
- av_strlcpy(s->location, uri, sizeof(s->location));
+ s->location = av_strdup(uri);
+ if (!s->location)
+ return AVERROR(ENOMEM);
+ if (options)
+ av_dict_copy(&s->chained_options, *options, 0);
if (s->headers) {
int len = strlen(s->headers);
@@ -241,7 +272,10 @@ static int http_open(URLContext *h, const char *uri, int flags)
av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n");
}
- return http_open_cnx(h);
+ ret = http_open_cnx(h, options);
+ if (ret < 0)
+ av_dict_free(&s->chained_options);
+ return ret;
}
static int http_getc(HTTPContext *s)
{
@@ -304,7 +338,7 @@ static int process_line(URLContext *h, char *line, int line_count,
p++;
s->http_code = strtol(p, &end, 10);
- av_dlog(NULL, "http_code=%d\n", s->http_code);
+ 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. */
@@ -328,7 +362,14 @@ static int process_line(URLContext *h, char *line, int line_count,
while (av_isspace(*p))
p++;
if (!av_strcasecmp(tag, "Location")) {
- av_strlcpy(s->location, p, sizeof(s->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;
*new_location = 1;
} else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) {
s->filesize = strtoll(p, NULL, 10);
@@ -357,8 +398,12 @@ static int process_line(URLContext *h, char *line, int line_count,
} else if (!av_strcasecmp (tag, "Connection")) {
if (!strcmp(p, "close"))
s->willclose = 1;
- } else if (!av_strcasecmp (tag, "Server") && !av_strcasecmp (p, "AkamaiGHost")) {
- s->is_akamai = 1;
+ } else if (!av_strcasecmp (tag, "Server")) {
+ if (!av_strcasecmp (p, "AkamaiGHost")) {
+ s->is_akamai = 1;
+ } else if (!av_strncasecmp (p, "MediaGateway", 12)) {
+ s->is_mediagateway = 1;
+ }
} else if (!av_strcasecmp (tag, "Content-Type")) {
av_free(s->mime_type); s->mime_type = av_strdup(p);
} else if (!av_strcasecmp (tag, "Set-Cookie")) {
@@ -375,6 +420,40 @@ static int process_line(URLContext *h, char *line, int line_count,
snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
av_free(tmp);
}
+ } 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);
+ }
}
}
return 1;
@@ -421,6 +500,8 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
cvalue = av_strdup(param);
}
}
+ if (!cdomain)
+ cdomain = av_strdup(domain);
// ensure all of the necessary values are valid
if (!cdomain || !cpath || !cvalue) {
@@ -495,7 +576,7 @@ static int http_read_header(URLContext *h, int *new_location)
if ((err = http_get_line(s, line, sizeof(line))) < 0)
return err;
- av_dlog(NULL, "header='%s'\n", line);
+ av_log(h, AV_LOG_DEBUG, "header='%s'\n", line);
err = process_line(h, line, s->line_count, new_location);
if (err < 0)
@@ -505,6 +586,9 @@ static int http_read_header(URLContext *h, int *new_location)
s->line_count++;
}
+ if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
+ h->is_streamed = 1; /* we can in fact _not_ seek */
+
return err;
}
@@ -519,6 +603,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
int64_t off = s->off;
int len = 0;
const char *method;
+ int send_expect_100 = 0;
/* send http header */
@@ -536,12 +621,22 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
method);
proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
local_path, method);
+ if (post && !s->post_data) {
+ send_expect_100 = s->send_expect_100;
+ /* The user has supplied authentication but we don't know the auth type,
+ * send Expect: 100-continue to get the 401 response including the
+ * WWW-Authenticate header, or an 100 continue if no auth actually
+ * is needed. */
+ if (auth && *auth &&
+ s->auth_state.auth_type == HTTP_AUTH_NONE &&
+ s->http_code != 401)
+ send_expect_100 = 1;
+ }
/* set default headers if needed */
if (!has_header(s->headers, "\r\nUser-Agent: "))
len += av_strlcatf(headers + len, sizeof(headers) - len,
- "User-Agent: %s\r\n",
- s->user_agent ? s->user_agent : LIBAVFORMAT_IDENT);
+ "User-Agent: %s\r\n", s->user_agent);
if (!has_header(s->headers, "\r\nAccept: "))
len += av_strlcpy(headers + len, "Accept: */*\r\n",
sizeof(headers) - len);
@@ -551,6 +646,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1))
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-\r\n", s->off);
+ if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "Expect: 100-continue\r\n");
if (!has_header(s->headers, "\r\nConnection: ")) {
if (s->multiple_requests) {
@@ -579,6 +677,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
av_free(cookies);
}
}
+ if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy) {
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "Icy-MetaData: %d\r\n", 1);
+ }
/* now add in custom headers */
if (s->headers)
@@ -600,6 +702,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
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;
@@ -612,11 +717,12 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
s->buf_end = s->buffer;
s->line_count = 0;
s->off = 0;
+ s->icy_data_read = 0;
s->filesize = -1;
s->willclose = 0;
s->end_chunked_post = 0;
s->end_header = 0;
- if (post && !s->post_data) {
+ if (post && !s->post_data && !send_expect_100) {
/* Pretend that it did work. We didn't read any header yet, since
* we've still to send the POST data, but the code calling this
* function will check http_code after we return. */
@@ -651,12 +757,45 @@ 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;
}
return len;
}
+#if CONFIG_ZLIB
+#define DECOMPRESS_BUF_SIZE (256 * 1024)
+static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
+{
+ HTTPContext *s = h->priv_data;
+ int ret;
+
+ if (!s->inflate_buffer) {
+ s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
+ if (!s->inflate_buffer)
+ return AVERROR(ENOMEM);
+ }
+
+ if (s->inflate_stream.avail_in == 0) {
+ int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
+ if (read <= 0)
+ return read;
+ s->inflate_stream.next_in = s->inflate_buffer;
+ s->inflate_stream.avail_in = read;
+ }
+
+ s->inflate_stream.avail_out = size;
+ s->inflate_stream.next_out = buf;
+
+ ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n", ret, s->inflate_stream.msg);
+
+ return size - s->inflate_stream.avail_out;
+}
+#endif
+
static int http_read(URLContext *h, uint8_t *buf, int size)
{
HTTPContext *s = h->priv_data;
@@ -692,6 +831,36 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
}
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);
+#endif
return http_buf_read(h, buf, size);
}
@@ -743,6 +912,11 @@ static int http_close(URLContext *h)
int ret = 0;
HTTPContext *s = h->priv_data;
+#if CONFIG_ZLIB
+ inflateEnd(&s->inflate_stream);
+ av_freep(&s->inflate_buffer);
+#endif
+
if (!s->end_chunked_post) {
/* Close the write direction by sending the end of chunked encoding. */
ret = http_shutdown(h, h->flags);
@@ -750,6 +924,7 @@ static int http_close(URLContext *h)
if (s->hd)
ffurl_closep(&s->hd);
+ av_dict_free(&s->chained_options);
return ret;
}
@@ -760,6 +935,7 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
int64_t old_off = s->off;
uint8_t old_buf[BUFFER_SIZE];
int old_buf_size;
+ AVDictionary *options = NULL;
if (whence == AVSEEK_SIZE)
return s->filesize;
@@ -777,7 +953,9 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
s->off = off;
/* if it fails, continue on old connection */
- if (http_open_cnx(h) < 0) {
+ av_dict_copy(&options, s->chained_options, 0);
+ if (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;
@@ -785,6 +963,7 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
s->off = old_off;
return -1;
}
+ av_dict_free(&options);
ffurl_close(old_hd);
return off;
}
@@ -799,7 +978,7 @@ http_get_file_handle(URLContext *h)
#if CONFIG_HTTP_PROTOCOL
URLProtocol ff_http_protocol = {
.name = "http",
- .url_open = http_open,
+ .url_open2 = http_open,
.url_read = http_read,
.url_write = http_write,
.url_seek = http_seek,
@@ -814,7 +993,7 @@ URLProtocol ff_http_protocol = {
#if CONFIG_HTTPS_PROTOCOL
URLProtocol ff_https_protocol = {
.name = "https",
- .url_open = http_open,
+ .url_open2 = http_open,
.url_read = http_read,
.url_write = http_write,
.url_seek = http_seek,
@@ -846,8 +1025,6 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
HTTPAuthType cur_auth_type;
char *authstr;
int new_loc;
- AVDictionary *opts = NULL;
- char opts_format[20];
if( s->seekable == 1 )
h->is_streamed = 0;
@@ -864,13 +1041,8 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
NULL);
redo:
- if (s->rw_timeout != -1) {
- snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
- av_dict_set(&opts, "timeout", opts_format, 0);
- } /* if option is not given, don't pass it and let tcp use its own default */
ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
- &h->interrupt_callback, &opts);
- av_dict_free(&opts);
+ &h->interrupt_callback, NULL);
if (ret < 0)
return ret;
diff --git a/ffmpeg/libavformat/icodec.c b/ffmpeg/libavformat/icodec.c
index fa308da..4c038e9 100644
--- a/ffmpeg/libavformat/icodec.c
+++ b/ffmpeg/libavformat/icodec.c
@@ -45,7 +45,7 @@ typedef struct {
static int probe(AVProbeData *p)
{
if (AV_RL16(p->buf) == 0 && AV_RL16(p->buf + 2) == 1 && AV_RL16(p->buf + 4))
- return AVPROBE_SCORE_MAX / 3;
+ return AVPROBE_SCORE_MAX / 4;
return 0;
}
diff --git a/ffmpeg/libavformat/icoenc.c b/ffmpeg/libavformat/icoenc.c
index 3e6a1ea..561c6ca 100644
--- a/ffmpeg/libavformat/icoenc.c
+++ b/ffmpeg/libavformat/icoenc.c
@@ -151,8 +151,6 @@ static int ico_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_w8(pb, 0x00); // Write bitmask (opaque)
}
- avio_flush(pb);
-
return 0;
}
diff --git a/ffmpeg/libavformat/id3v2.c b/ffmpeg/libavformat/id3v2.c
index 3e347d1..3eb368e 100644
--- a/ffmpeg/libavformat/id3v2.c
+++ b/ffmpeg/libavformat/id3v2.c
@@ -32,72 +32,71 @@
#include <zlib.h>
#endif
-#include "id3v2.h"
-#include "id3v1.h"
#include "libavutil/avstring.h"
-#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "avio_internal.h"
#include "internal.h"
+#include "id3v1.h"
+#include "id3v2.h"
const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
- { "TALB", "album"},
- { "TCOM", "composer"},
- { "TCON", "genre"},
- { "TCOP", "copyright"},
- { "TENC", "encoded_by"},
- { "TIT2", "title"},
- { "TLAN", "language"},
- { "TPE1", "artist"},
- { "TPE2", "album_artist"},
- { "TPE3", "performer"},
- { "TPOS", "disc"},
- { "TPUB", "publisher"},
- { "TRCK", "track"},
- { "TSSE", "encoder"},
+ { "TALB", "album" },
+ { "TCOM", "composer" },
+ { "TCON", "genre" },
+ { "TCOP", "copyright" },
+ { "TENC", "encoded_by" },
+ { "TIT2", "title" },
+ { "TLAN", "language" },
+ { "TPE1", "artist" },
+ { "TPE2", "album_artist" },
+ { "TPE3", "performer" },
+ { "TPOS", "disc" },
+ { "TPUB", "publisher" },
+ { "TRCK", "track" },
+ { "TSSE", "encoder" },
{ 0 }
};
const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
- { "TDRL", "date"},
- { "TDRC", "date"},
- { "TDEN", "creation_time"},
- { "TSOA", "album-sort"},
- { "TSOP", "artist-sort"},
- { "TSOT", "title-sort"},
+ { "TDRL", "date" },
+ { "TDRC", "date" },
+ { "TDEN", "creation_time" },
+ { "TSOA", "album-sort" },
+ { "TSOP", "artist-sort" },
+ { "TSOT", "title-sort" },
{ 0 }
};
static const AVMetadataConv id3v2_2_metadata_conv[] = {
- { "TAL", "album"},
- { "TCO", "genre"},
- { "TT2", "title"},
- { "TEN", "encoded_by"},
- { "TP1", "artist"},
- { "TP2", "album_artist"},
- { "TP3", "performer"},
- { "TRK", "track"},
+ { "TAL", "album" },
+ { "TCO", "genre" },
+ { "TT2", "title" },
+ { "TEN", "encoded_by" },
+ { "TP1", "artist" },
+ { "TP2", "album_artist" },
+ { "TP3", "performer" },
+ { "TRK", "track" },
{ 0 }
};
-
const char ff_id3v2_tags[][4] = {
- "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
- "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
- "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
- "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
- { 0 },
+ "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
+ "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
+ "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
+ "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
+ { 0 },
};
const char ff_id3v2_4_tags[][4] = {
- "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
- "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
- { 0 },
+ "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
+ "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
+ { 0 },
};
const char ff_id3v2_3_tags[][4] = {
- "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
- { 0 },
+ "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
+ { 0 },
};
const char *ff_id3v2_picture_types[21] = {
@@ -125,36 +124,36 @@ const char *ff_id3v2_picture_types[21] = {
};
const CodecMime ff_id3v2_mime_tags[] = {
- {"image/gif" , AV_CODEC_ID_GIF},
- {"image/jpeg", AV_CODEC_ID_MJPEG},
- {"image/jpg", AV_CODEC_ID_MJPEG},
- {"image/png" , AV_CODEC_ID_PNG},
- {"image/tiff", AV_CODEC_ID_TIFF},
- {"image/bmp", AV_CODEC_ID_BMP},
- {"JPG", AV_CODEC_ID_MJPEG}, /* ID3v2.2 */
- {"PNG" , AV_CODEC_ID_PNG}, /* ID3v2.2 */
- {"", AV_CODEC_ID_NONE},
+ { "image/gif", AV_CODEC_ID_GIF },
+ { "image/jpeg", AV_CODEC_ID_MJPEG },
+ { "image/jpg", AV_CODEC_ID_MJPEG },
+ { "image/png", AV_CODEC_ID_PNG },
+ { "image/tiff", AV_CODEC_ID_TIFF },
+ { "image/bmp", AV_CODEC_ID_BMP },
+ { "JPG", AV_CODEC_ID_MJPEG }, /* ID3v2.2 */
+ { "PNG", AV_CODEC_ID_PNG }, /* ID3v2.2 */
+ { "", AV_CODEC_ID_NONE },
};
-int ff_id3v2_match(const uint8_t *buf, const char * magic)
+int ff_id3v2_match(const uint8_t *buf, const char *magic)
{
return buf[0] == magic[0] &&
buf[1] == magic[1] &&
buf[2] == magic[2] &&
- buf[3] != 0xff &&
- buf[4] != 0xff &&
- (buf[6] & 0x80) == 0 &&
- (buf[7] & 0x80) == 0 &&
- (buf[8] & 0x80) == 0 &&
- (buf[9] & 0x80) == 0;
+ buf[3] != 0xff &&
+ buf[4] != 0xff &&
+ (buf[6] & 0x80) == 0 &&
+ (buf[7] & 0x80) == 0 &&
+ (buf[8] & 0x80) == 0 &&
+ (buf[9] & 0x80) == 0;
}
-int ff_id3v2_tag_len(const uint8_t * buf)
+int ff_id3v2_tag_len(const uint8_t *buf)
{
int len = ((buf[6] & 0x7f) << 21) +
((buf[7] & 0x7f) << 14) +
((buf[8] & 0x7f) << 7) +
- (buf[9] & 0x7f) +
+ (buf[9] & 0x7f) +
ID3v2_HEADER_SIZE;
if (buf[5] & 0x10)
len += ID3v2_HEADER_SIZE;
@@ -210,7 +209,6 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
}
switch (encoding) {
-
case ID3v2_ENCODING_ISO8859:
while (left && ch) {
ch = avio_r8(pb);
@@ -246,7 +244,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
}
if (left < 0)
- left += 2; /* did not read last char from pb */
+ left += 2; /* did not read last char from pb */
break;
case ID3v2_ENCODING_UTF8:
@@ -272,7 +270,8 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
/**
* Parse a text tag.
*/
-static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
+static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
+ AVDictionary **metadata, const char *key)
{
uint8_t *dst;
int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
@@ -289,9 +288,9 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha
return;
}
- if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
- && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
- && genre <= ID3v1_GENRE_MAX) {
+ if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
+ (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) &&
+ genre <= ID3v1_GENRE_MAX) {
av_freep(&dst);
dst = av_strdup(ff_id3v1_genre_str[genre]);
} else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
@@ -307,16 +306,17 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha
av_freep(&dst);
if (dst)
- av_dict_set(&s->metadata, key, dst, dict_flags);
+ av_dict_set(metadata, key, dst, dict_flags);
}
/**
* Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
*/
-static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
+ char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
{
ID3v2ExtraMetaGEOB *geob_data = NULL;
- ID3v2ExtraMeta *new_extra = NULL;
+ ID3v2ExtraMeta *new_extra = NULL;
char encoding;
unsigned int len;
@@ -325,13 +325,15 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *
geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
if (!geob_data) {
- av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB));
+ av_log(s, AV_LOG_ERROR, "Failed to alloc %zu 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", sizeof(ID3v2ExtraMeta));
+ av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
+ sizeof(ID3v2ExtraMeta));
goto fail;
}
@@ -340,18 +342,19 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *
taglen--;
/* read MIME type (always ISO-8859) */
- if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, &taglen) < 0
- || taglen <= 0)
+ if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type,
+ &taglen) < 0 ||
+ taglen <= 0)
goto fail;
/* read file name */
- if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0
- || taglen <= 0)
+ if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 ||
+ taglen <= 0)
goto fail;
/* read content description */
- if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0
- || taglen < 0)
+ if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 ||
+ taglen < 0)
goto fail;
if (taglen) {
@@ -362,18 +365,19 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *
goto fail;
}
if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
- av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n");
+ av_log(s, AV_LOG_WARNING,
+ "Error reading GEOB frame, data truncated.\n");
geob_data->datasize = len;
} else {
- geob_data->data = NULL;
+ geob_data->data = NULL;
geob_data->datasize = 0;
}
/* add data to the list */
- new_extra->tag = "GEOB";
+ new_extra->tag = "GEOB";
new_extra->data = geob_data;
new_extra->next = *extra_meta;
- *extra_meta = new_extra;
+ *extra_meta = new_extra;
return;
@@ -386,11 +390,12 @@ fail:
static int is_number(const char *str)
{
- while (*str >= '0' && *str <= '9') str++;
+ while (*str >= '0' && *str <= '9')
+ str++;
return !*str;
}
-static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
+static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
{
AVDictionaryEntry *t;
if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
@@ -402,28 +407,29 @@ static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
static void merge_date(AVDictionary **m)
{
AVDictionaryEntry *t;
- char date[17] = {0}; // YYYY-MM-DD hh:mm
+ char date[17] = { 0 }; // YYYY-MM-DD hh:mm
if (!(t = get_date_tag(*m, "TYER")) &&
!(t = get_date_tag(*m, "TYE")))
return;
av_strlcpy(date, t->value, 5);
av_dict_set(m, "TYER", NULL, 0);
- av_dict_set(m, "TYE", NULL, 0);
+ av_dict_set(m, "TYE", NULL, 0);
if (!(t = get_date_tag(*m, "TDAT")) &&
!(t = get_date_tag(*m, "TDA")))
goto finish;
snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
av_dict_set(m, "TDAT", NULL, 0);
- av_dict_set(m, "TDA", NULL, 0);
+ av_dict_set(m, "TDA", NULL, 0);
if (!(t = get_date_tag(*m, "TIME")) &&
!(t = get_date_tag(*m, "TIM")))
goto finish;
- snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
+ snprintf(date + 10, sizeof(date) - 10,
+ " %.2s:%.2s", t->value, t->value + 2);
av_dict_set(m, "TIME", NULL, 0);
- av_dict_set(m, "TIM", NULL, 0);
+ av_dict_set(m, "TIM", NULL, 0);
finish:
if (date[0])
@@ -438,15 +444,16 @@ static void free_apic(void *obj)
av_freep(&apic);
}
-static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
+ char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
{
int enc, pic_type;
- char mimetype[64];
- const CodecMime *mime = ff_id3v2_mime_tags;
- enum AVCodecID id = AV_CODEC_ID_NONE;
- ID3v2ExtraMetaAPIC *apic = NULL;
+ char mimetype[64];
+ const CodecMime *mime = ff_id3v2_mime_tags;
+ enum AVCodecID id = AV_CODEC_ID_NONE;
+ ID3v2ExtraMetaAPIC *apic = NULL;
ID3v2ExtraMeta *new_extra = NULL;
- int64_t end = avio_tell(pb) + taglen;
+ int64_t end = avio_tell(pb) + taglen;
if (taglen <= 4)
goto fail;
@@ -460,7 +467,12 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag
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;
@@ -469,7 +481,8 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag
mime++;
}
if (id == AV_CODEC_ID_NONE) {
- av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
+ av_log(s, AV_LOG_WARNING,
+ "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
goto fail;
}
apic->id = id;
@@ -478,25 +491,28 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag
pic_type = avio_r8(pb);
taglen--;
if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
- av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type);
+ av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n",
+ pic_type);
pic_type = 0;
}
apic->type = ff_id3v2_picture_types[pic_type];
/* description and picture data */
if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
- av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n");
+ av_log(s, AV_LOG_ERROR,
+ "Error decoding attached picture description.\n");
goto fail;
}
- apic->buf = av_buffer_alloc(taglen);
+ apic->buf = av_buffer_alloc(taglen + FF_INPUT_BUFFER_PADDING_SIZE);
if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen)
goto fail;
+ memset(apic->buf->data + taglen, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- new_extra->tag = "APIC";
- new_extra->data = apic;
- new_extra->next = *extra_meta;
- *extra_meta = new_extra;
+ new_extra->tag = "APIC";
+ new_extra->data = apic;
+ new_extra->next = *extra_meta;
+ *extra_meta = new_extra;
return;
@@ -507,47 +523,65 @@ fail:
avio_seek(pb, end, SEEK_SET);
}
-static void read_chapter(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, 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};
- char title[1024];
uint32_t start, end;
+ AVChapter *chapter;
+ uint8_t *dst = NULL;
+ int taglen;
+ char tag[5];
- taglen -= avio_get_str(pb, taglen, title, sizeof(title));
- if (taglen < 16)
+ if (decode_str(s, pb, 0, &dst, &len) < 0)
+ return;
+ if (len < 16)
return;
start = avio_rb32(pb);
end = avio_rb32(pb);
- taglen -= 27;
- if (taglen > 0) {
- char tag[4];
-
- avio_skip(pb, 8);
- avio_read(pb, tag, 4);
- if (!memcmp(tag, "TIT2", 4)) {
- taglen = FFMIN(taglen, avio_rb32(pb));
- if (taglen < 0)
- return;
- avio_skip(pb, 3);
- avio_get_str(pb, taglen, title, sizeof(title));
- }
+ avio_skip(pb, 8);
+
+ chapter = avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst);
+ if (!chapter) {
+ av_free(dst);
+ return;
}
- avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, title);
+ len -= 16;
+ while (len > 10) {
+ 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)
+ goto end;
+ if (tag[0] == 'T')
+ read_ttag(s, pb, taglen, &chapter->metadata, tag);
+ else
+ avio_skip(pb, taglen);
+ len -= taglen;
+ }
+
+ 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);
}
typedef struct ID3v2EMFunc {
const char *tag3;
const char *tag4;
- void (*read)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta **);
+ void (*read)(AVFormatContext *, AVIOContext *, int, char *,
+ ID3v2ExtraMeta **, int isv34);
void (*free)(void *obj);
} ID3v2EMFunc;
static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
{ "GEO", "GEOB", read_geobtag, free_geobtag },
- { "PIC", "APIC", read_apic, free_apic },
- { "CHAP","CHAP", read_chapter, NULL },
+ { "PIC", "APIC", read_apic, free_apic },
+ { "CHAP","CHAP", read_chapter, NULL },
{ NULL }
};
@@ -570,7 +604,8 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
return NULL;
}
-static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
+static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
+ uint8_t flags, ID3v2ExtraMeta **extra_meta)
{
int isv34, unsync;
unsigned tlen;
@@ -581,7 +616,7 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
AVIOContext pb;
AVIOContext *pbx;
unsigned char *buffer = NULL;
- int buffer_size = 0;
+ int buffer_size = 0;
const ID3v2EMFunc *extra_func = NULL;
unsigned char *uncompressed_buffer = NULL;
int uncompressed_buffer_size = 0;
@@ -594,13 +629,13 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
reason = "compression";
goto error;
}
- isv34 = 0;
+ isv34 = 0;
taghdrlen = 6;
break;
case 3:
case 4:
- isv34 = 1;
+ isv34 = 1;
taghdrlen = 10;
break;
@@ -614,7 +649,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
int extlen = get_size(s->pb, 4);
if (version == 4)
- extlen -= 4; // in v2.4 the length includes the length field we just read
+ /* In v2.4 the length includes the length field we just read. */
+ extlen -= 4;
if (extlen < 0) {
reason = "invalid extended header length";
@@ -630,24 +666,26 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
while (len >= taghdrlen) {
unsigned int tflags = 0;
- int tunsync = 0;
- int tcomp = 0;
- int tencr = 0;
+ int tunsync = 0;
+ int tcomp = 0;
+ int tencr = 0;
unsigned long dlen;
if (isv34) {
- avio_read(s->pb, tag, 4);
+ if (avio_read(s->pb, tag, 4) < 4)
+ break;
tag[4] = 0;
- if(version==3){
+ if (version == 3) {
tlen = avio_rb32(s->pb);
- }else
+ } else
tlen = get_size(s->pb, 4);
- tflags = avio_rb16(s->pb);
+ tflags = avio_rb16(s->pb);
tunsync = tflags & ID3v2_FLAG_UNSYNCH;
} else {
- avio_read(s->pb, tag, 3);
+ if (avio_read(s->pb, tag, 3) < 3)
+ break;
tag[3] = 0;
- tlen = avio_rb24(s->pb);
+ tlen = avio_rb24(s->pb);
}
if (tlen > (1<<28))
break;
@@ -660,7 +698,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
if (!tlen) {
if (tag[0])
- av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", tag);
+ av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n",
+ tag);
continue;
}
@@ -688,7 +727,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
avio_skip(s->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)))) {
+ } else if (tag[0] == 'T' ||
+ (extra_meta &&
+ (extra_func = get_extra_meta_func(tag, isv34)))) {
pbx = s->pb;
if (unsync || tunsync || tcomp) {
@@ -703,16 +744,19 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
uint8_t *b;
b = buffer;
- while (avio_tell(s->pb) < end && b - buffer < tlen) {
+ 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 && b - buffer < tlen) {
+ if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 &&
+ b - buffer < tlen &&
+ !s->pb->eof_reached ) {
uint8_t val = avio_r8(s->pb);
*b++ = val ? val : avio_r8(s->pb);
}
}
- ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL,
+ NULL);
tlen = b - buffer;
- pbx = &pb; // read from sync buffer
+ pbx = &pb; // read from sync buffer
}
#if CONFIG_ZLIB
@@ -748,12 +792,11 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
#endif
if (tag[0] == 'T')
/* parse text tag */
- read_ttag(s, pbx, tlen, tag);
+ read_ttag(s, pbx, tlen, &s->metadata, tag);
else
/* parse special meta tag */
- extra_func->read(s, pbx, tlen, tag, extra_meta);
- }
- else if (!tag[0]) {
+ 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);
@@ -764,23 +807,26 @@ seek:
avio_seek(s->pb, next, SEEK_SET);
}
- if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
+ /* Footer preset, always 10 bytes, skip over it */
+ if (version == 4 && flags & 0x10)
end += 10;
- error:
+error:
if (reason)
- av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
+ av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n",
+ version, reason);
avio_seek(s->pb, end, SEEK_SET);
av_free(buffer);
av_free(uncompressed_buffer);
return;
}
-void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
+void ff_id3v2_read(AVFormatContext *s, const char *magic,
+ ID3v2ExtraMeta **extra_meta)
{
int len, ret;
uint8_t buf[ID3v2_HEADER_SIZE];
- int found_header;
+ int found_header;
int64_t off;
do {
@@ -798,7 +844,7 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra
((buf[7] & 0x7f) << 14) |
((buf[8] & 0x7f) << 7) |
(buf[9] & 0x7f);
- ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
+ id3v2_parse(s, len, buf[3], buf[5], extra_meta);
} else {
avio_seek(s->pb, off, SEEK_SET);
}
@@ -847,7 +893,7 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
av_init_packet(&st->attached_pic);
st->attached_pic.buf = apic->buf;
st->attached_pic.data = apic->buf->data;
- st->attached_pic.size = apic->buf->size;
+ st->attached_pic.size = apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE;
st->attached_pic.stream_index = st->index;
st->attached_pic.flags |= AV_PKT_FLAG_KEY;
diff --git a/ffmpeg/libavformat/id3v2enc.c b/ffmpeg/libavformat/id3v2enc.c
index a10d679..6052244 100644
--- a/ffmpeg/libavformat/id3v2enc.c
+++ b/ffmpeg/libavformat/id3v2enc.c
@@ -26,8 +26,11 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
+#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);
@@ -162,33 +165,31 @@ void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
avio_wb32(pb, 0);
}
-int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
+static int write_metadata(AVIOContext *pb, AVDictionary **metadata,
+ ID3v2EncContext *id3, int enc)
{
AVDictionaryEntry *t = NULL;
- int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
- ID3v2_ENCODING_UTF8;
+ int ret;
- ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
+ ff_metadata_conv(metadata, ff_id3v2_34_metadata_conv, NULL);
if (id3->version == 3)
- id3v2_3_metadata_split_date(&s->metadata);
+ id3v2_3_metadata_split_date(metadata);
else if (id3->version == 4)
- ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
-
- while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
- int ret;
+ ff_metadata_conv(metadata, ff_id3v2_4_metadata_conv, NULL);
- if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) {
+ while ((t = av_dict_get(*metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = id3v2_check_write_tag(id3, pb, t, ff_id3v2_tags, enc)) > 0) {
id3->len += ret;
continue;
}
- if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ?
- ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
+ if ((ret = id3v2_check_write_tag(id3, pb, t, id3->version == 3 ?
+ ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
id3->len += ret;
continue;
}
/* unknown tag, write as TXXX frame */
- if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
+ if ((ret = id3v2_put_ttag(id3, pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
return ret;
id3->len += ret;
}
@@ -196,6 +197,64 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
return 0;
}
+static int write_chapter(AVFormatContext *s, ID3v2EncContext *id3, int id, int enc)
+{
+ const AVRational time_base = {1, 1000};
+ AVChapter *ch = s->chapters[id];
+ uint8_t *dyn_buf = NULL;
+ AVIOContext *dyn_bc = NULL;
+ char name[123];
+ int len, start, end, ret;
+
+ if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
+ goto fail;
+
+ start = av_rescale_q(ch->start, ch->time_base, time_base);
+ end = av_rescale_q(ch->end, ch->time_base, time_base);
+
+ snprintf(name, 122, "ch%d", id);
+ id3->len += avio_put_str(dyn_bc, name);
+ avio_wb32(dyn_bc, start);
+ avio_wb32(dyn_bc, end);
+ avio_wb32(dyn_bc, 0xFFFFFFFFu);
+ avio_wb32(dyn_bc, 0xFFFFFFFFu);
+
+ if ((ret = write_metadata(dyn_bc, &ch->metadata, id3, enc)) < 0)
+ goto fail;
+
+ len = avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ id3->len += 16 + ID3v2_HEADER_SIZE;
+
+ avio_wb32(s->pb, MKBETAG('C', 'H', 'A', 'P'));
+ avio_wb32(s->pb, len);
+ avio_wb16(s->pb, 0);
+ avio_write(s->pb, dyn_buf, len);
+
+fail:
+ if (dyn_bc && !dyn_buf)
+ avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ av_freep(&dyn_buf);
+
+ return ret;
+}
+
+int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
+{
+ int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
+ ID3v2_ENCODING_UTF8;
+ int i, ret;
+
+ if ((ret = write_metadata(s->pb, &s->metadata, id3, enc)) < 0)
+ return ret;
+
+ for (i = 0; i < s->nb_chapters; i++) {
+ if ((ret = write_chapter(s, id3, i, enc)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
@@ -236,6 +295,10 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
desc = e->value;
+ /* use UTF16 only for non-ASCII strings */
+ if (enc == ID3v2_ENCODING_UTF16BOM && string_is_ascii(desc))
+ enc = ID3v2_ENCODING_ISO8859;
+
/* start writing */
if (avio_open_dyn_buf(&dyn_buf) < 0)
return AVERROR(ENOMEM);
@@ -263,7 +326,15 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
{
- int64_t cur_pos = avio_tell(pb);
+ 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;
+
+ cur_pos = avio_tell(pb);
avio_seek(pb, id3->size_pos, SEEK_SET);
id3v2_put_size(pb, id3->len);
avio_seek(pb, cur_pos, SEEK_SET);
diff --git a/ffmpeg/libavformat/idcin.c b/ffmpeg/libavformat/idcin.c
index 2a8af40..cc25fb0 100644
--- a/ffmpeg/libavformat/idcin.c
+++ b/ffmpeg/libavformat/idcin.c
@@ -93,7 +93,9 @@ typedef struct IdcinDemuxContext {
static int idcin_probe(AVProbeData *p)
{
- unsigned int number;
+ unsigned int number, sample_rate;
+ unsigned int w, h;
+ int i;
/*
* This is what you could call a "probabilistic" file check: id CIN
@@ -108,36 +110,43 @@ static int idcin_probe(AVProbeData *p)
/* check we have enough data to do all checks, otherwise the
0-padding may cause a wrong recognition */
- if (p->buf_size < 20)
+ if (p->buf_size < 20 + HUFFMAN_TABLE_SIZE + 12)
return 0;
/* check the video width */
- number = AV_RL32(&p->buf[0]);
- if ((number == 0) || (number > 1024))
+ w = AV_RL32(&p->buf[0]);
+ if ((w == 0) || (w > 1024))
return 0;
/* check the video height */
- number = AV_RL32(&p->buf[4]);
- if ((number == 0) || (number > 1024))
+ h = AV_RL32(&p->buf[4]);
+ if ((h == 0) || (h > 1024))
return 0;
/* check the audio sample rate */
- number = AV_RL32(&p->buf[8]);
- if ((number != 0) && ((number < 8000) | (number > 48000)))
+ sample_rate = AV_RL32(&p->buf[8]);
+ if (sample_rate && (sample_rate < 8000 || sample_rate > 48000))
return 0;
/* check the audio bytes/sample */
number = AV_RL32(&p->buf[12]);
- if (number > 2)
+ if (number > 2 || sample_rate && !number)
return 0;
/* check the audio channels */
number = AV_RL32(&p->buf[16]);
- if (number > 2)
+ if (number > 2 || sample_rate && !number)
return 0;
- /* return half certainly since this check is a bit sketchy */
- return AVPROBE_SCORE_MAX / 2;
+ i = 20 + HUFFMAN_TABLE_SIZE;
+ if (AV_RL32(&p->buf[i]) == 1)
+ i += 768;
+
+ if (i+12 > p->buf_size || AV_RL32(&p->buf[i+8]) != w*h)
+ return 1;
+
+ /* return half certainty since this check is a bit sketchy */
+ return AVPROBE_SCORE_EXTENSION;
}
static int idcin_read_header(AVFormatContext *s)
@@ -196,15 +205,8 @@ static int idcin_read_header(AVFormatContext *s)
st->codec->height = height;
/* load up the Huffman tables into extradata */
- st->codec->extradata_size = HUFFMAN_TABLE_SIZE;
- st->codec->extradata = av_malloc(HUFFMAN_TABLE_SIZE);
- 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/ffmpeg/libavformat/idroqdec.c b/ffmpeg/libavformat/idroqdec.c
index 6f843d7..8cdd72e 100644
--- a/ffmpeg/libavformat/idroqdec.c
+++ b/ffmpeg/libavformat/idroqdec.c
@@ -145,6 +145,8 @@ static int roq_read_packet(AVFormatContext *s,
break;
case RoQ_QUAD_CODEBOOK:
+ if (roq->video_stream_index < 0)
+ return AVERROR_INVALIDDATA;
/* packet needs to contain both this codebook and next VQ chunk */
codebook_offset = avio_tell(pb) - RoQ_CHUNK_PREAMBLE_SIZE;
codebook_size = chunk_size;
@@ -194,6 +196,11 @@ static int roq_read_packet(AVFormatContext *s,
st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
}
case RoQ_QUAD_VQ:
+ if (chunk_type == RoQ_QUAD_VQ) {
+ if (roq->video_stream_index < 0)
+ return AVERROR_INVALIDDATA;
+ }
+
/* load up the packet */
if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE))
return AVERROR(EIO);
diff --git a/ffmpeg/libavformat/iff.c b/ffmpeg/libavformat/iff.c
index 1efc147..b5751c5 100644
--- a/ffmpeg/libavformat/iff.c
+++ b/ffmpeg/libavformat/iff.c
@@ -462,6 +462,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);
}
@@ -481,5 +485,5 @@ AVInputFormat ff_iff_demuxer = {
.read_probe = iff_probe,
.read_header = iff_read_header,
.read_packet = iff_read_packet,
- .flags = AVFMT_GENERIC_INDEX,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK,
};
diff --git a/ffmpeg/libavformat/ilbc.c b/ffmpeg/libavformat/ilbc.c
index 7a23b2f..3f154ce 100644
--- a/ffmpeg/libavformat/ilbc.c
+++ b/ffmpeg/libavformat/ilbc.c
@@ -56,7 +56,6 @@ static int ilbc_write_header(AVFormatContext *s)
static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/img2.c b/ffmpeg/libavformat/img2.c
index eee100a..4fd4fd2 100644
--- a/ffmpeg/libavformat/img2.c
+++ b/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" },
@@ -50,7 +51,6 @@ static const IdStrMap img_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, "y" },
{ AV_CODEC_ID_RAWVIDEO, "raw" },
{ AV_CODEC_ID_BMP, "bmp" },
- { AV_CODEC_ID_GIF, "gif" },
{ AV_CODEC_ID_TARGA, "tga" },
{ AV_CODEC_ID_TIFF, "tiff" },
{ AV_CODEC_ID_TIFF, "tif" },
@@ -67,13 +67,14 @@ static const IdStrMap img_tags[] = {
{ AV_CODEC_ID_SUNRAST, "im32" },
{ AV_CODEC_ID_SUNRAST, "sunras" },
{ AV_CODEC_ID_JPEG2000, "j2c" },
- { AV_CODEC_ID_JPEG2000, "j2k" },
{ AV_CODEC_ID_JPEG2000, "jp2" },
{ AV_CODEC_ID_JPEG2000, "jpc" },
+ { AV_CODEC_ID_JPEG2000, "j2k" },
{ AV_CODEC_ID_DPX, "dpx" },
{ AV_CODEC_ID_EXR, "exr" },
{ AV_CODEC_ID_PICTOR, "pic" },
{ AV_CODEC_ID_V210X, "yuv10" },
+ { AV_CODEC_ID_WEBP, "webp" },
{ AV_CODEC_ID_XBM, "xbm" },
{ AV_CODEC_ID_XFACE, "xface" },
{ AV_CODEC_ID_XWD, "xwd" },
diff --git a/ffmpeg/libavformat/img2dec.c b/ffmpeg/libavformat/img2dec.c
index 882abb9..5163e69 100644
--- a/ffmpeg/libavformat/img2dec.c
+++ b/ffmpeg/libavformat/img2dec.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <sys/stat.h>
#include "libavutil/avstring.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
@@ -52,8 +53,8 @@ typedef struct {
int split_planes; /**< use independent file for each Y, U, V plane */
char path[1024];
char *pixel_format; /**< Set by a private option. */
- char *video_size; /**< Set by a private option. */
- char *framerate; /**< 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;
@@ -63,6 +64,7 @@ typedef struct {
int start_number;
int start_number_range;
int frame_size;
+ int ts_from_file;
} VideoDemuxData;
static const int sizes[][2] = {
@@ -185,7 +187,7 @@ static int img_read_probe(AVProbeData *p)
else if (av_match_ext(p->filename, "raw") || av_match_ext(p->filename, "gif"))
return 5;
else
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
}
return 0;
}
@@ -193,11 +195,9 @@ static int img_read_probe(AVProbeData *p)
static int img_read_header(AVFormatContext *s1)
{
VideoDemuxData *s = s1->priv_data;
- int first_index, last_index, ret = 0;
- int width = 0, height = 0;
+ int first_index, last_index;
AVStream *st;
enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
- AVRational framerate;
s1->ctx_flags |= AVFMTCTX_NOHEADER;
@@ -212,17 +212,6 @@ static int img_read_header(AVFormatContext *s1)
s->pixel_format);
return AVERROR(EINVAL);
}
- if (s->video_size &&
- (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log(s, AV_LOG_ERROR,
- "Could not parse video size: %s.\n", s->video_size);
- return ret;
- }
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(s, AV_LOG_ERROR,
- "Could not parse framerate: %s.\n", s->framerate);
- return ret;
- }
av_strlcpy(s->path, s1->filename, sizeof(s->path));
s->img_number = 0;
@@ -236,11 +225,14 @@ static int img_read_header(AVFormatContext *s1)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
+ 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);
- if (width && height) {
- st->codec->width = width;
- st->codec->height = height;
+ if (s->width && s->height) {
+ st->codec->width = s->width;
+ st->codec->height = s->height;
}
if (!s->is_pipe) {
@@ -280,7 +272,7 @@ static int img_read_header(AVFormatContext *s1)
if (find_image_range(&first_index, &last_index, s->path,
s->start_number, s->start_number_range) < 0) {
av_log(s1, AV_LOG_ERROR,
- "Could find no file with with path '%s' and index in the range %d-%d\n",
+ "Could find no file with path '%s' and index in the range %d-%d\n",
s->path, s->start_number, s->start_number + s->start_number_range - 1);
return AVERROR(ENOENT);
}
@@ -309,8 +301,10 @@ static int img_read_header(AVFormatContext *s1)
s->img_last = last_index;
s->img_number = first_index;
/* compute duration */
- st->start_time = 0;
- st->duration = last_index - first_index + 1;
+ if (!s->ts_from_file) {
+ st->start_time = 0;
+ st->duration = last_index - first_index + 1;
+ }
}
if (s1->video_codec_id) {
@@ -394,8 +388,15 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
return AVERROR(ENOMEM);
pkt->stream_index = 0;
pkt->flags |= AV_PKT_FLAG_KEY;
- if (!s->is_pipe)
+ if (s->ts_from_file) {
+ struct stat img_stat;
+ if (stat(filename, &img_stat))
+ return AVERROR(EIO);
+ pkt->pts = (int64_t)img_stat.st_mtime;
+ 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;
+ }
pkt->size = 0;
for (i = 0; i < 3; i++) {
@@ -433,6 +434,15 @@ static int img_read_close(struct AVFormatContext* s1)
static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
VideoDemuxData *s1 = s->priv_data;
+ AVStream *st = s->streams[0];
+
+ if (s1->ts_from_file) {
+ int index = av_index_search_timestamp(st, timestamp, flags);
+ if(index < 0)
+ return -1;
+ s1->img_number = st->index_entries[index].pos;
+ return 0;
+ }
if (timestamp < 0 || !s1->loop && timestamp > s1->img_last - s1->img_first)
return -1;
@@ -444,7 +454,7 @@ static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
#define OFFSET(x) offsetof(VideoDemuxData, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
- { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC },
{ "pattern_type", "set pattern type", OFFSET(pattern_type), AV_OPT_TYPE_INT, {.i64=PT_GLOB_SEQUENCE}, 0, INT_MAX, DEC, "pattern_type"},
@@ -455,8 +465,9 @@ static const AVOption options[] = {
{ "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
{ "start_number", "set first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC },
{ "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(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, 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 },
{ NULL },
};
diff --git a/ffmpeg/libavformat/img2enc.c b/ffmpeg/libavformat/img2enc.c
index 67b5819..f61b0ca 100644
--- a/ffmpeg/libavformat/img2enc.c
+++ b/ffmpeg/libavformat/img2enc.c
@@ -21,6 +21,7 @@
*/
#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
@@ -28,7 +29,6 @@
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
-#include "libavutil/opt.h"
typedef struct {
const AVClass *class; /**< Class for private options. */
@@ -36,7 +36,9 @@ typedef struct {
int is_pipe;
int split_planes; /**< use independent file for each Y, U, V plane */
char path[1024];
- int updatefirst;
+ int update;
+ int use_strftime;
+ const char *muxer;
} VideoMuxData;
static int write_header(AVFormatContext *s)
@@ -44,7 +46,6 @@ static int write_header(AVFormatContext *s)
VideoMuxData *img = s->priv_data;
AVStream *st = s->streams[0];
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codec->pix_fmt);
- const char *str;
av_strlcpy(img->path, s->filename, sizeof(img->path));
@@ -54,14 +55,17 @@ static int write_header(AVFormatContext *s)
else
img->is_pipe = 1;
- str = strrchr(img->path, '.');
- img->split_planes = str
- && !av_strcasecmp(str + 1, "y")
- && s->nb_streams == 1
- && st->codec->codec_id == AV_CODEC_ID_RAWVIDEO
- && desc
- &&(desc->flags & PIX_FMT_PLANAR)
- && desc->nb_components >= 3;
+ if (st->codec->codec_id == AV_CODEC_ID_GIF) {
+ img->muxer = "gif";
+ } else if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ const char *str = strrchr(img->path, '.');
+ img->split_planes = str
+ && !av_strcasecmp(str + 1, "y")
+ && s->nb_streams == 1
+ && desc
+ &&(desc->flags & AV_PIX_FMT_FLAG_PLANAR)
+ && desc->nb_components >= 3;
+ }
return 0;
}
@@ -75,8 +79,19 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
int i;
if (!img->is_pipe) {
- if (av_get_frame_filename(filename, sizeof(filename),
- img->path, img->img_number) < 0 && img->img_number > 1 && !img->updatefirst) {
+ if (img->update) {
+ av_strlcpy(filename, img->path, sizeof(filename));
+ } else if (img->use_strftime) {
+ time_t now0;
+ struct tm *tm;
+ time(&now0);
+ tm = localtime(&now0);
+ if (!strftime(filename, sizeof(filename), img->path, tm)) {
+ av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n");
+ return AVERROR(EINVAL);
+ }
+ } else if (av_get_frame_filename(filename, sizeof(filename), img->path, img->img_number) < 0 &&
+ img->img_number > 1) {
av_log(s, AV_LOG_ERROR,
"Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n",
img->img_number, img->path);
@@ -91,7 +106,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
if (!img->split_planes || i+1 >= desc->nb_components)
break;
- filename[strlen(filename) - 1] = ((int[]){'U','V','A','x'})[i];
+ filename[strlen(filename) - 1] = "UVAx"[i];
}
} else {
pb[0] = s->pb;
@@ -99,7 +114,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
if (img->split_planes) {
int ysize = codec->width * codec->height;
- int usize = ((-codec->width)>>desc->log2_chroma_w) * ((-codec->height)>>desc->log2_chroma_h);
+ int usize = FF_CEIL_RSHIFT(codec->width, desc->log2_chroma_w) * FF_CEIL_RSHIFT(codec->height, desc->log2_chroma_h);
if (desc->comp[0].depth_minus1 >= 8) {
ysize *= 2;
usize *= 2;
@@ -113,6 +128,37 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
avio_write(pb[3], pkt->data + ysize + 2*usize, ysize);
avio_close(pb[3]);
}
+ } else if (img->muxer) {
+ int ret;
+ AVStream *st;
+ AVPacket pkt2 = {0};
+ AVFormatContext *fmt = NULL;
+
+ av_assert0(!img->split_planes);
+
+ ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->filename);
+ if (ret < 0)
+ return ret;
+ st = avformat_new_stream(fmt, NULL);
+ if (!st) {
+ avformat_free_context(fmt);
+ return AVERROR(ENOMEM);
+ }
+ st->id = pkt->stream_index;
+
+ fmt->pb = pb[0];
+ if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
+ (ret = av_dup_packet(&pkt2)) < 0 ||
+ (ret = avcodec_copy_context(st->codec, s->streams[0]->codec)) < 0 ||
+ (ret = avformat_write_header(fmt, NULL)) < 0 ||
+ (ret = av_interleaved_write_frame(fmt, &pkt2)) < 0 ||
+ (ret = av_write_trailer(fmt)) < 0) {
+ av_free_packet(&pkt2);
+ avformat_free_context(fmt);
+ return ret;
+ }
+ av_free_packet(&pkt2);
+ avformat_free_context(fmt);
} else {
avio_write(pb[0], pkt->data, pkt->size);
}
@@ -128,8 +174,10 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
#define OFFSET(x) offsetof(VideoMuxData, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption muxoptions[] = {
- { "updatefirst", "update the first image file", OFFSET(updatefirst), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
- { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, ENC },
+ { "updatefirst", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+ { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+ { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC },
+ { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
{ NULL },
};
@@ -145,8 +193,8 @@ AVOutputFormat ff_image2_muxer = {
.name = "image2",
.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,xwd,sun,ras,rs,im1,im8,im24,"
- "sunras,xbm,xface",
+ "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24,"
+ "sunras,webp,xbm,xface",
.priv_data_size = sizeof(VideoMuxData),
.video_codec = AV_CODEC_ID_MJPEG,
.write_header = write_header,
diff --git a/ffmpeg/libavformat/internal.h b/ffmpeg/libavformat/internal.h
index 4d56388..1560e9f 100644
--- a/ffmpeg/libavformat/internal.h
+++ b/ffmpeg/libavformat/internal.h
@@ -26,6 +26,10 @@
#define MAX_URL_SIZE 4096
+/** size of probe buffer, for guessing file type from file contents */
+#define PROBE_BUF_MIN 2048
+#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)
#else
@@ -90,31 +94,6 @@ void ff_read_frame_flush(AVFormatContext *s);
uint64_t ff_ntp_time(void);
/**
- * Assemble a URL string from components. This is the reverse operation
- * of av_url_split.
- *
- * Note, this requires networking to be initialized, so the caller must
- * ensure ff_network_init has been called.
- *
- * @see av_url_split
- *
- * @param str the buffer to fill with the url
- * @param size the size of the str buffer
- * @param proto the protocol identifier, if null, the separator
- * after the identifier is left out, too
- * @param authorization an optional authorization string, may be null.
- * An empty string is treated the same as a null string.
- * @param hostname the host name string
- * @param port the port number, left out from the string if negative
- * @param fmt a generic format string for everything to add after the
- * host/port, may be null
- * @return the number of characters written to the destination buffer
- */
-int ff_url_join(char *str, int size, const char *proto,
- const char *authorization, const char *hostname,
- int port, const char *fmt, ...) av_printf_format(7, 8);
-
-/**
* Append the media-specific SDP fragment for the media stream c
* to the buffer buff.
*
@@ -240,17 +219,6 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base,
*/
void ff_reduce_index(AVFormatContext *s, int stream_index);
-/**
- * Convert a relative url into an absolute url, given a base url.
- *
- * @param buf the buffer where output absolute url is written
- * @param size the size of buf
- * @param base the base url, may be equal to buf.
- * @param rel the new url, which is interpreted relative to base
- */
-void ff_make_absolute_url(char *buf, int size, const char *base,
- const char *rel);
-
enum AVCodecID ff_guess_image2_codec(const char *filename);
/**
@@ -278,6 +246,9 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
*/
void ff_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp);
+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 ));
+
/**
* Perform a binary search using read_timestamp().
*
@@ -386,10 +357,37 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags);
AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission);
/**
- * Generate standard extradata for AVC-Intra based on width/height and field order.
+ * Generate standard extradata for AVC-Intra based on width/height and field
+ * order.
+ */
+int ff_generate_avci_extradata(AVStream *st);
+
+/**
+ * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end
+ * which is always set to 0.
+ *
+ * @param size size of extradata
+ * @return 0 if OK, AVERROR_xxx on error
+ */
+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
+ * @return 0 if OK, AVERROR_xxx on error
*/
-void ff_generate_avci_extradata(AVStream *st);
+int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts);
-int ff_http_match_no_proxy(const char *no_proxy, const char *hostname);
+void ff_rfps_calculate(AVFormatContext *ic);
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/ffmpeg/libavformat/ipmovie.c b/ffmpeg/libavformat/ipmovie.c
index 676363b..4a766ef 100644
--- a/ffmpeg/libavformat/ipmovie.c
+++ b/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)) {
+ 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/ffmpeg/libavformat/isom.c b/ffmpeg/libavformat/isom.c
index 3f419a8..f6a4646 100644
--- a/ffmpeg/libavformat/isom.c
+++ b/ffmpeg/libavformat/isom.c
@@ -21,8 +21,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-//#define DEBUG
-
#include "avformat.h"
#include "internal.h"
#include "isom.h"
@@ -153,6 +151,9 @@ 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_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 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'q') }, /* AVC-Intra 50M 720p25/50 */
@@ -166,6 +167,7 @@ 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_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */
@@ -188,6 +190,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '4', 'p') }, /* MPEG2 IMX PAL 625/50 40mb/s produced by FCP */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'n') }, /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'p') }, /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
+ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '1') }, /* XDCAM HD422 720p30 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '4') }, /* XDCAM HD422 720p24 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '5') }, /* XDCAM HD422 720p25 CBR */
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '9') }, /* XDCAM HD422 720p60 CBR */
@@ -244,6 +247,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_PRORES, MKTAG('a', 'p', '4', 'h') }, /* Apple ProRes 4444 */
{ AV_CODEC_ID_FLIC, MKTAG('f', 'l', 'i', 'c') },
+ { AV_CODEC_ID_AIC, MKTAG('i', 'c', 'o', 'd') },
+
{ AV_CODEC_ID_NONE, 0 },
};
@@ -279,6 +284,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = {
{ AV_CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') },
{ AV_CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') },
+ { AV_CODEC_ID_PCM_S16BE, MKTAG('l', 'p', 'c', 'm') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('l', 'p', 'c', 'm') },
{ AV_CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') },
{ AV_CODEC_ID_PCM_S24LE, MKTAG('i', 'n', '2', '4') },
@@ -293,6 +299,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_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 */
@@ -431,6 +438,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 */
@@ -450,13 +458,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);
- st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- avio_read(pb, st->codec->extradata, len);
- st->codec->extradata_size = 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;
diff --git a/ffmpeg/libavformat/isom.h b/ffmpeg/libavformat/isom.h
index 4154baf..2834b11 100644
--- a/ffmpeg/libavformat/isom.h
+++ b/ffmpeg/libavformat/isom.h
@@ -110,7 +110,7 @@ typedef struct MOVStreamContext {
int ctts_index;
int ctts_sample;
unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
- unsigned int alt_sample_size; ///< always contains sample size from stsz atom
+ unsigned int stsz_sample_size; ///< always contains sample size from stsz atom
unsigned int sample_count;
int *sample_sizes;
int keyframe_absent;
@@ -162,6 +162,8 @@ typedef struct MOVContext {
int use_absolute_path;
int ignore_editlist;
int64_t next_root_atom; ///< offset of the next root atom
+ int *bitrates; ///< bitrates read before streams creation
+ int bitrates_count;
} MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb);
@@ -200,6 +202,27 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id);
#define MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO 0x02000000
#define MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES 0x01000000
+#define MOV_TKHD_FLAG_ENABLED 0x0001
+#define MOV_TKHD_FLAG_IN_MOVIE 0x0002
+#define MOV_TKHD_FLAG_IN_PREVIEW 0x0004
+#define MOV_TKHD_FLAG_IN_POSTER 0x0008
+
+#define TAG_IS_AVCI(tag) \
+ ((tag) == MKTAG('a', 'i', '5', 'p') || \
+ (tag) == MKTAG('a', 'i', '5', 'q') || \
+ (tag) == MKTAG('a', 'i', '5', '2') || \
+ (tag) == MKTAG('a', 'i', '5', '3') || \
+ (tag) == MKTAG('a', 'i', '5', '5') || \
+ (tag) == MKTAG('a', 'i', '5', '6') || \
+ (tag) == MKTAG('a', 'i', '1', 'p') || \
+ (tag) == MKTAG('a', 'i', '1', 'q') || \
+ (tag) == MKTAG('a', 'i', '1', '2') || \
+ (tag) == MKTAG('a', 'i', '1', '3') || \
+ (tag) == MKTAG('a', 'i', '1', '5') || \
+ (tag) == MKTAG('a', 'i', '1', '6') || \
+ (tag) == MKTAG('A', 'V', 'i', 'n'))
+
+
int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom);
enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags);
diff --git a/ffmpeg/libavformat/iss.c b/ffmpeg/libavformat/iss.c
index e4335b4..e994531 100644
--- a/ffmpeg/libavformat/iss.c
+++ b/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/ffmpeg/libavformat/ivfenc.c b/ffmpeg/libavformat/ivfenc.c
index ddb205b..45bae22 100644
--- a/ffmpeg/libavformat/ivfenc.c
+++ b/ffmpeg/libavformat/ivfenc.c
@@ -53,7 +53,6 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wl32(pb, pkt->size);
avio_wl64(pb, pkt->pts);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
return 0;
}
diff --git a/ffmpeg/libavformat/jacosubdec.c b/ffmpeg/libavformat/jacosubdec.c
index 89e7e1b..e77ab40 100644
--- a/ffmpeg/libavformat/jacosubdec.c
+++ b/ffmpeg/libavformat/jacosubdec.c
@@ -43,8 +43,9 @@ typedef struct {
static int timed_line(const char *ptr)
{
char c;
+ int fs, fe;
return (sscanf(ptr, "%*u:%*u:%*u.%*u %*u:%*u:%*u.%*u %c", &c) == 1 ||
- sscanf(ptr, "@%*u @%*u %c", &c) == 1);
+ (sscanf(ptr, "@%u @%u %c", &fs, &fe, &c) == 3 && fs < fe));
}
static int jacosub_probe(AVProbeData *p)
@@ -60,10 +61,10 @@ static int jacosub_probe(AVProbeData *p)
ptr++;
if (*ptr != '#' && *ptr != '\n') {
if (timed_line(ptr))
- return AVPROBE_SCORE_MAX/2 + 1;
+ return AVPROBE_SCORE_EXTENSION + 1;
return 0;
}
- ptr += strcspn(ptr, "\n") + 1;
+ ptr += ff_subtitles_next_line(ptr);
}
return 0;
}
diff --git a/ffmpeg/libavformat/jvdec.c b/ffmpeg/libavformat/jvdec.c
index e941492..03ac43d 100644
--- a/ffmpeg/libavformat/jvdec.c
+++ b/ffmpeg/libavformat/jvdec.c
@@ -33,10 +33,10 @@
#define JV_PREAMBLE_SIZE 5
typedef struct {
- int audio_size; /** audio packet size (bytes) */
- int video_size; /** video packet size (bytes) */
- int palette_size; /** palette size (bytes) */
- int video_type; /** per-frame video compression type */
+ int audio_size; /**< audio packet size (bytes) */
+ int video_size; /**< video packet size (bytes) */
+ int palette_size; /**< palette size (bytes) */
+ int video_type; /**< per-frame video compression type */
} JVFrame;
typedef struct {
@@ -59,6 +59,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;
@@ -119,10 +128,23 @@ static int read_header(AVFormatContext *s)
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");
+
jvf->video_type = avio_r8(pb);
avio_skip(pb, 1);
@@ -184,6 +206,9 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
}
}
+ if (s->pb->eof_reached)
+ return AVERROR_EOF;
+
return AVERROR(EIO);
}
@@ -218,15 +243,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/ffmpeg/libavformat/latmenc.c b/ffmpeg/libavformat/latmenc.c
index 9dfb4e4..e69de2b 100644
--- a/ffmpeg/libavformat/latmenc.c
+++ b/ffmpeg/libavformat/latmenc.c
@@ -2,20 +2,20 @@
* LATM/LOAS muxer
* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -124,7 +124,7 @@ static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
if (!ctx->channel_conf) {
GetBitContext gb;
- init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
+ init_get_bits8(&gb, avctx->extradata, avctx->extradata_size);
skip_bits_long(&gb, ctx->off + 3);
avpriv_copy_pce_data(bs, &gb);
}
diff --git a/ffmpeg/libavformat/libavformat.pc b/ffmpeg/libavformat/libavformat.pc
index ef9016f..460614c 100644
--- a/ffmpeg/libavformat/libavformat.pc
+++ b/ffmpeg/libavformat/libavformat.pc
@@ -5,10 +5,10 @@ includedir=${prefix}/include
Name: libavformat
Description: FFmpeg container format library
-Version: 55.0.100
+Version: 55.22.100
Requires:
-Requires.private: libavcodec = 55.1.100
+Requires.private: libavcodec = 55.46.100
Conflicts:
-Libs: -L${libdir} -lavformat
-Libs.private: -ldl -lXfixes -lXext -lX11 -ljack -lasound -lxvidcore -lx264 -lvorbisenc -lvorbis -logg -ltheoraenc -ltheoradec -logg -lschroedinger-1.0 -lmp3lame -lfaac -lm -pthread -lz -lrt
+Libs: -L${libdir} -lavformat
+Libs.private: -lXfixes -lXext -lX11 -lx264 -lmp3lame -lm -lz -pthread
Cflags: -I${includedir}
diff --git a/ffmpeg/libavformat/libmodplug.c b/ffmpeg/libavformat/libmodplug.c
index aa8edcc..836b7c2 100644
--- a/ffmpeg/libavformat/libmodplug.c
+++ b/ffmpeg/libavformat/libmodplug.c
@@ -166,14 +166,14 @@ static int modplug_read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
ModPlug_Settings settings;
ModPlugContext *modplug = s->priv_data;
- int sz = avio_size(pb);
+ int64_t sz = avio_size(pb);
if (sz < 0) {
av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
sz = modplug->max_size;
} else if (modplug->max_size && sz > modplug->max_size) {
sz = modplug->max_size;
- av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %dB "
+ av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %"PRIi64"B "
"but demuxing is likely to fail due to incomplete buffer\n",
sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz);
}
@@ -347,6 +347,19 @@ static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int
return 0;
}
+static const char modplug_extensions[] = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm,itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz";
+
+static int modplug_probe(AVProbeData *p)
+{
+ if (av_match_ext(p->filename, modplug_extensions)) {
+ if (p->buf_size < 16384)
+ return AVPROBE_SCORE_EXTENSION/2-1;
+ else
+ return AVPROBE_SCORE_EXTENSION;
+ }
+ return 0;
+}
+
static const AVClass modplug_class = {
.class_name = "ModPlug demuxer",
.item_name = av_default_item_name,
@@ -358,11 +371,11 @@ AVInputFormat ff_libmodplug_demuxer = {
.name = "libmodplug",
.long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"),
.priv_data_size = sizeof(ModPlugContext),
+ .read_probe = modplug_probe,
.read_header = modplug_read_header,
.read_packet = modplug_read_packet,
.read_close = modplug_read_close,
.read_seek = modplug_read_seek,
- .extensions = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm"
- ",itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz", // compressed mods
+ .extensions = modplug_extensions,
.priv_class = &modplug_class,
};
diff --git a/ffmpeg/libavformat/libnut.c b/ffmpeg/libavformat/libnut.c
index 838c55a..be8f3cb 100644
--- a/ffmpeg/libavformat/libnut.c
+++ b/ffmpeg/libavformat/libnut.c
@@ -223,14 +223,16 @@ static int nut_read_header(AVFormatContext * avf) {
AVStream * st = avformat_new_stream(avf, NULL);
int j;
+ if (!st)
+ return AVERROR(ENOMEM);
+
for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8);
st->codec->has_b_frames = s[i].decode_delay;
st->codec->extradata_size = s[i].codec_specific_len;
if (st->codec->extradata_size) {
- st->codec->extradata = av_mallocz(st->codec->extradata_size);
- if(!st->codec->extradata){
+ if(ff_alloc_extradata(st->codec, st->codec->extradata_size)){
nut_demuxer_uninit(nut);
priv->nut = NULL;
return AVERROR(ENOMEM);
diff --git a/ffmpeg/libavformat/loasdec.c b/ffmpeg/libavformat/loasdec.c
index d3a8dbd..05ef0fe 100644
--- a/ffmpeg/libavformat/loasdec.c
+++ b/ffmpeg/libavformat/loasdec.c
@@ -52,9 +52,9 @@ static int loas_probe(AVProbeData *p)
if(buf == buf0)
first_frames= frames;
}
- if (first_frames>=3) return AVPROBE_SCORE_MAX/2+1;
- else if(max_frames>100)return AVPROBE_SCORE_MAX/2;
- else if(max_frames>=3) return AVPROBE_SCORE_MAX/4;
+ 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;
}
diff --git a/ffmpeg/libavformat/lvfdec.c b/ffmpeg/libavformat/lvfdec.c
index f8dda58..1ff67c8 100644
--- a/ffmpeg/libavformat/lvfdec.c
+++ b/ffmpeg/libavformat/lvfdec.c
@@ -25,9 +25,13 @@
static int lvf_probe(AVProbeData *p)
{
- if (AV_RL32(p->buf) == MKTAG('L', 'V', 'F', 'F'))
- return AVPROBE_SCORE_MAX / 2;
- return 0;
+ if (AV_RL32(p->buf) != MKTAG('L', 'V', 'F', 'F'))
+ return 0;
+
+ if (!AV_RL32(p->buf + 16) || AV_RL32(p->buf + 16) > 256)
+ return AVPROBE_SCORE_MAX / 8;
+
+ return AVPROBE_SCORE_EXTENSION;
}
static int lvf_read_header(AVFormatContext *s)
diff --git a/ffmpeg/libavformat/lxfdec.c b/ffmpeg/libavformat/lxfdec.c
index 876f988..f0a9639 100644
--- a/ffmpeg/libavformat/lxfdec.c
+++ b/ffmpeg/libavformat/lxfdec.c
@@ -29,7 +29,6 @@
#define LXF_IDENT "LEITCH\0"
#define LXF_IDENT_LENGTH 8
#define LXF_SAMPLERATE 48000
-#define LXF_MAX_AUDIO_PACKET (8008*15*4) ///< 15-channel 32-bit NTSC audio frame
static const AVCodecTag lxf_tags[] = {
{ AV_CODEC_ID_MJPEG, 0 },
@@ -116,7 +115,7 @@ static int get_packet_header(AVFormatContext *s)
uint32_t version, audio_format, header_size, channels, tmp;
AVStream *st;
uint8_t header[LXF_MAX_PACKET_HEADER_SIZE];
- const uint8_t *p;
+ const uint8_t *p = header + LXF_IDENT_LENGTH;
//find and read the ident
if ((ret = sync(s, header)) < 0)
@@ -126,11 +125,11 @@ static int get_packet_header(AVFormatContext *s)
if (ret != 8)
return ret < 0 ? ret : AVERROR_EOF;
- p = header + LXF_IDENT_LENGTH;
version = bytestream_get_le32(&p);
header_size = bytestream_get_le32(&p);
if (version > 1)
- avpriv_request_sample(s, "format version %i", version);
+ avpriv_request_sample(s, "Unknown format version %i\n", version);
+
if (header_size < (version ? 72 : 60) ||
header_size > LXF_MAX_PACKET_HEADER_SIZE ||
(header_size & 3)) {
@@ -141,9 +140,8 @@ static int get_packet_header(AVFormatContext *s)
//read the rest of the packet header
if ((ret = avio_read(pb, header + (p - header),
header_size - (p - header))) !=
- header_size - (p - header)) {
+ header_size - (p - header))
return ret < 0 ? ret : AVERROR_EOF;
- }
if (check_checksum(header, header_size))
av_log(s, AV_LOG_ERROR, "checksum error\n");
@@ -163,16 +161,19 @@ static int get_packet_header(AVFormatContext *s)
break;
case 1:
//audio
- if (!s->streams || !(st = s->streams[1])) {
+ if (s->nb_streams < 2) {
av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n");
break;
}
- if (version == 0) p += 8;
+ if (version == 0)
+ p += 8;
audio_format = bytestream_get_le32(&p);
channels = bytestream_get_le32(&p);
track_size = bytestream_get_le32(&p);
+ st = s->streams[1];
+
//set codec based on specified audio bitdepth
//we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment
st->codec->bits_per_coded_sample = (audio_format >> 6) & 0x3F;
@@ -258,6 +259,7 @@ static int lxf_read_header(AVFormatContext *s)
st->codec->bit_rate = 1000000 * ((video_params >> 14) & 0xFF);
st->codec->codec_tag = video_params & 0xF;
st->codec->codec_id = ff_codec_get_id(lxf_tags, st->codec->codec_tag);
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
av_log(s, AV_LOG_DEBUG, "record: %x = %i-%02i-%02i\n",
record_date, 1900 + (record_date & 0x7F), (record_date >> 7) & 0xF,
@@ -290,7 +292,6 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
LXFDemuxContext *lxf = s->priv_data;
AVIOContext *pb = s->pb;
- AVStream *ast = NULL;
uint32_t stream;
int ret, ret2;
@@ -304,18 +305,11 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(EAGAIN);
}
- if (stream == 1 && !(ast = s->streams[1])) {
+ if (stream == 1 && s->nb_streams < 2) {
av_log(s, AV_LOG_ERROR, "got audio packet without having an audio stream\n");
return AVERROR_INVALIDDATA;
}
- //make sure the data fits in the de-planerization buffer
- if (ast && ret > LXF_MAX_AUDIO_PACKET) {
- av_log(s, AV_LOG_ERROR, "audio packet too large (%i > %i)\n",
- ret, LXF_MAX_AUDIO_PACKET);
- return AVERROR_INVALIDDATA;
- }
-
if ((ret2 = av_new_packet(pkt, ret)) < 0)
return ret2;
@@ -326,7 +320,7 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->stream_index = stream;
- if (!ast) {
+ if (!stream) {
//picture type (0 = closed I, 1 = open I, 2 = P, 3 = B)
if (((lxf->video_format >> 22) & 0x3) < 2)
pkt->flags |= AV_PKT_FLAG_KEY;
diff --git a/ffmpeg/libavformat/m4vdec.c b/ffmpeg/libavformat/m4vdec.c
index e72fb42..c2fd4d7 100644
--- a/ffmpeg/libavformat/m4vdec.c
+++ b/ffmpeg/libavformat/m4vdec.c
@@ -45,7 +45,7 @@ static int mpeg4video_probe(AVProbeData *probe_packet)
}
if (VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0 && res==0)
- return VOP+VO > 3 ? AVPROBE_SCORE_MAX/2 : AVPROBE_SCORE_MAX/4;
+ return VOP+VO > 3 ? AVPROBE_SCORE_EXTENSION : AVPROBE_SCORE_EXTENSION/2;
return 0;
}
diff --git a/ffmpeg/libavformat/matroska.c b/ffmpeg/libavformat/matroska.c
index 09eecf2..77a88a8 100644
--- a/ffmpeg/libavformat/matroska.c
+++ b/ffmpeg/libavformat/matroska.c
@@ -35,8 +35,8 @@ 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/EXPERIMENTAL",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},
{"A_PCM/INT/BIG" , AV_CODEC_ID_PCM_S16BE},
@@ -57,14 +57,25 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_VORBIS" , AV_CODEC_ID_VORBIS},
{"A_WAVPACK4" , AV_CODEC_ID_WAVPACK},
+ {"D_WEBVTT/SUBTITLES" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/CAPTIONS" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/DESCRIPTIONS", AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/METADATA" , AV_CODEC_ID_WEBVTT},
+
{"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP},
{"S_TEXT/UTF8" , AV_CODEC_ID_TEXT},
{"S_TEXT/UTF8" , AV_CODEC_ID_SRT},
{"S_TEXT/ASCII" , AV_CODEC_ID_TEXT},
+#if FF_API_ASS_SSA
{"S_TEXT/ASS" , AV_CODEC_ID_SSA},
{"S_TEXT/SSA" , AV_CODEC_ID_SSA},
{"S_ASS" , AV_CODEC_ID_SSA},
{"S_SSA" , AV_CODEC_ID_SSA},
+#endif
+ {"S_TEXT/ASS" , AV_CODEC_ID_ASS},
+ {"S_TEXT/SSA" , AV_CODEC_ID_ASS},
+ {"S_ASS" , AV_CODEC_ID_ASS},
+ {"S_SSA" , AV_CODEC_ID_ASS},
{"S_VOBSUB" , AV_CODEC_ID_DVD_SUBTITLE},
{"S_DVBSUB" , AV_CODEC_ID_DVB_SUBTITLE},
{"S_HDMV/PGS" , AV_CODEC_ID_HDMV_PGS_SUBTITLE},
@@ -77,6 +88,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_MPEG4/ISO/AP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/SP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/AVC" , AV_CODEC_ID_H264},
+ {"V_MPEGH/ISO/HEVC" , AV_CODEC_ID_HEVC},
{"V_MPEG4/MS/V3" , AV_CODEC_ID_MSMPEG4V3},
{"V_PRORES" , AV_CODEC_ID_PRORES},
{"V_REAL/RV10" , AV_CODEC_ID_RV10},
diff --git a/ffmpeg/libavformat/matroska.h b/ffmpeg/libavformat/matroska.h
index 8a7e10b..3bb5aee 100644
--- a/ffmpeg/libavformat/matroska.h
+++ b/ffmpeg/libavformat/matroska.h
@@ -91,6 +91,8 @@
#define MATROSKA_ID_CODECINFOURL 0x3B4040
#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240
#define MATROSKA_ID_CODECDECODEALL 0xAA
+#define MATROSKA_ID_CODECDELAY 0x56AA
+#define MATROSKA_ID_SEEKPREROLL 0x56BB
#define MATROSKA_ID_TRACKNAME 0x536E
#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C
#define MATROSKA_ID_TRACKFLAGENABLED 0xB9
@@ -156,6 +158,8 @@
/* IDs in the cuetrackposition master */
#define MATROSKA_ID_CUETRACK 0xF7
#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
+#define MATROSKA_ID_CUERELATIVEPOSITION 0xF0
+#define MATROSKA_ID_CUEDURATION 0xB2
#define MATROSKA_ID_CUEBLOCKNUMBER 0x5378
/* IDs in the tags master */
@@ -195,6 +199,8 @@
#define MATROSKA_ID_BLOCK 0xA1
#define MATROSKA_ID_BLOCKDURATION 0x9B
#define MATROSKA_ID_BLOCKREFERENCE 0xFB
+#define MATROSKA_ID_CODECSTATE 0xA4
+#define MATROSKA_ID_DISCARDPADDING 0x75A2
/* IDs in the attachments master */
#define MATROSKA_ID_ATTACHEDFILE 0x61A7
@@ -229,6 +235,7 @@ typedef enum {
MATROSKA_TRACK_TYPE_LOGO = 0x10,
MATROSKA_TRACK_TYPE_SUBTITLE = 0x11,
MATROSKA_TRACK_TYPE_CONTROL = 0x20,
+ MATROSKA_TRACK_TYPE_METADATA = 0x21,
} MatroskaTrackType;
typedef enum {
@@ -261,7 +268,7 @@ typedef enum {
*/
typedef struct CodecTags{
- char str[20];
+ char str[22];
enum AVCodecID id;
}CodecTags;
diff --git a/ffmpeg/libavformat/matroskadec.c b/ffmpeg/libavformat/matroskadec.c
index eea29da..e994786 100644
--- a/ffmpeg/libavformat/matroskadec.c
+++ b/ffmpeg/libavformat/matroskadec.c
@@ -62,6 +62,7 @@ typedef enum {
EBML_NEST,
EBML_PASS,
EBML_STOP,
+ EBML_SINT,
EBML_TYPE_COUNT
} EbmlType;
@@ -163,6 +164,8 @@ 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;
@@ -290,6 +293,7 @@ typedef struct {
EbmlBin bin;
uint64_t additional_id;
EbmlBin additional;
+ int64_t discard_padding;
} MatroskaBlock;
static EbmlSyntax ebml_header[] = {
@@ -321,8 +325,8 @@ static EbmlSyntax matroska_info[] = {
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) },
- { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height) },
+ { 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) },
@@ -409,6 +413,8 @@ static EbmlSyntax matroska_track[] = {
{ 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 },
@@ -474,6 +480,8 @@ static EbmlSyntax matroska_chapters[] = {
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_CUERELATIVEPOSITION,EBML_NONE },
+ { MATROSKA_ID_CUEDURATION, EBML_NONE },
{ MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE },
{ 0 }
};
@@ -563,7 +571,9 @@ static EbmlSyntax matroska_blockgroup[] = {
{ 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_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
+ { 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} },
{ 0 }
};
@@ -627,21 +637,20 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
matroska->current_id = 0;
matroska->num_levels = 0;
- // seek to next position to resync from
- if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0 || avio_tell(pb) <= last_pos)
+ /* seek to next position to resync from */
+ if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0)
goto eof;
id = avio_rb32(pb);
// try to find a toplevel element
while (!url_feof(pb)) {
- if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
- id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS ||
+ if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
+ 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;
+ id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) {
+ matroska->current_id = id;
+ return 0;
}
id = (id << 8) | avio_r8(pb);
}
@@ -751,6 +760,30 @@ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
}
/*
+ * Read the next element as a signed int.
+ * 0 is success, < 0 is failure.
+ */
+static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
+{
+ int n = 1;
+
+ if (size > 8)
+ return AVERROR_INVALIDDATA;
+
+ if (size == 0) {
+ *num = 0;
+ } else {
+ *num = sign_extend(avio_r8(pb), 8);
+
+ /* big-endian ordering; build up number */
+ while (n++ < size)
+ *num = (*num << 8) | avio_r8(pb);
+ }
+
+ return 0;
+}
+
+/*
* Read the next element as a float.
* 0 is success, < 0 is failure.
*/
@@ -916,7 +949,13 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
break;
case EBML_STR:
case EBML_UTF8:
- *(char **)((char *)data+syntax[i].data_offset) = av_strdup(syntax[i].def.s);
+ // the default may be NULL
+ if (syntax[i].def.s) {
+ uint8_t **dst = (uint8_t**)((uint8_t*)data + syntax[i].data_offset);
+ *dst = av_strdup(syntax[i].def.s);
+ if (!*dst)
+ return AVERROR(ENOMEM);
+ }
break;
}
@@ -948,7 +987,7 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
data = (char *)data + syntax->data_offset;
if (syntax->list_elem_size) {
EbmlList *list = data;
- newelem = av_realloc(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;
@@ -971,6 +1010,7 @@ 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_STR:
case EBML_UTF8: res = ebml_read_ascii (pb, length, data); break;
@@ -1060,7 +1100,7 @@ static int matroska_probe(AVProbeData *p)
}
// probably valid EBML header but no recognized doctype
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska,
@@ -1213,6 +1253,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size,
return result;
}
+#if FF_API_ASS_SSA
static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
AVPacket *pkt, uint64_t display_duration)
{
@@ -1259,6 +1300,7 @@ static int matroska_merge_packets(AVPacket *out, AVPacket *in)
av_free(in);
return 0;
}
+#endif
static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
AVDictionary **metadata, char *prefix)
@@ -1268,7 +1310,8 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
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;
+ 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");
@@ -1442,7 +1485,7 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
for (i = 0; i < seekhead_list->nb_elem; i++)
if (seekhead[i].id == MATROSKA_ID_CUES)
break;
- assert(i <= seekhead_list->nb_elem);
+ av_assert1(i <= seekhead_list->nb_elem);
if (matroska_parse_seekhead_entry(matroska, i) < 0)
matroska->cues_parsing_deferred = -1;
@@ -1564,7 +1607,8 @@ static int matroska_read_header(AVFormatContext *s)
/* Apply some sanity checks. */
if (track->type != MATROSKA_TRACK_TYPE_VIDEO &&
track->type != MATROSKA_TRACK_TYPE_AUDIO &&
- track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
+ track->type != MATROSKA_TRACK_TYPE_SUBTITLE &&
+ track->type != MATROSKA_TRACK_TYPE_METADATA) {
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown or unsupported track type %"PRIu64"\n",
track->type);
@@ -1576,9 +1620,9 @@ 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;
- if (!track->video.display_width)
+ if (track->video.display_width == -1)
track->video.display_width = track->video.pixel_width;
- if (!track->video.display_height)
+ if (track->video.display_height == -1)
track->video.display_height = track->video.pixel_height;
if (track->video.color_space.size == 4)
fourcc = AV_RL32(track->video.color_space.data);
@@ -1681,18 +1725,6 @@ static int matroska_read_header(AVFormatContext *s)
&& (track->codec_priv.data != NULL)) {
fourcc = AV_RL32(track->codec_priv.data);
codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
- } 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. */
- extradata_size = 12 + track->codec_priv.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);
} else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8: codec_id = AV_CODEC_ID_PCM_U8; break;
@@ -1723,6 +1755,19 @@ static int matroska_read_header(AVFormatContext *s)
extradata_size = 5;
} else
extradata_size = 2;
+ } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) {
+ /* Only ALAC's magic cookie is stored in Matroska's track headers.
+ Create the "atom size", "tag", and "tag version" fields the
+ decoder expects manually. */
+ extradata_size = 12 + track->codec_priv.size;
+ extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ 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);
} else if (codec_id == AV_CODEC_ID_TTA) {
extradata_size = 30;
extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
@@ -1734,8 +1779,10 @@ static int matroska_read_header(AVFormatContext *s)
avio_wl16(&b, 1);
avio_wl16(&b, track->audio.channels);
avio_wl16(&b, track->audio.bitdepth);
+ 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, matroska->ctx->duration * 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) {
extradata_offset = 26;
@@ -1756,13 +1803,19 @@ 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);
- track->audio.buf = av_malloc(track->audio.frame_size * track->audio.sub_packet_h);
+ 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);
+ if (!track->audio.buf)
+ return AVERROR(ENOMEM);
if (codec_id == AV_CODEC_ID_RA_288) {
st->codec->block_align = track->audio.coded_framesize;
track->codec_priv.size = 0;
} else {
if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) {
- const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
+ 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];
}
@@ -1781,7 +1834,7 @@ static int matroska_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, matroska->time_scale*track->time_scale, 1000*1000*1000); /* 64 bit pts in ns */
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);
@@ -1796,11 +1849,8 @@ static int matroska_read_header(AVFormatContext *s)
st->codec->extradata = extradata;
st->codec->extradata_size = extradata_size;
} else if(track->codec_priv.data && track->codec_priv.size > 0){
- st->codec->extradata = av_mallocz(track->codec_priv.size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if(st->codec->extradata == NULL)
+ if (ff_alloc_extradata(st->codec, track->codec_priv.size))
return AVERROR(ENOMEM);
- st->codec->extradata_size = track->codec_priv.size;
memcpy(st->codec->extradata,
track->codec_priv.data + extradata_offset,
track->codec_priv.size);
@@ -1819,12 +1869,15 @@ static int matroska_read_header(AVFormatContext *s)
st->codec->height * track->video.display_width,
st->codec-> width * track->video.display_height,
255);
- st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (st->codec->codec_id != AV_CODEC_ID_HEVC)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+
if (track->default_duration) {
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
1000000000, track->default_duration, 30000);
#if FF_API_R_FRAME_RATE
- st->r_frame_rate = st->avg_frame_rate;
+ if (st->avg_frame_rate.num < st->avg_frame_rate.den * 1000L)
+ st->r_frame_rate = st->avg_frame_rate;
#endif
}
@@ -1857,9 +1910,35 @@ static int matroska_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample = track->audio.bitdepth;
if (st->codec->codec_id != AV_CODEC_ID_AAC)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (track->codec_delay > 0) {
+ st->codec->delay = av_rescale_q(track->codec_delay,
+ (AVRational){1, 1000000000},
+ (AVRational){1, st->codec->sample_rate});
+ }
+ if (track->seek_preroll > 0) {
+ av_codec_set_seek_preroll(st->codec,
+ av_rescale_q(track->seek_preroll,
+ (AVRational){1, 1000000000},
+ (AVRational){1, st->codec->sample_rate}));
+ }
+ } else if (codec_id == AV_CODEC_ID_WEBVTT) {
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+
+ if (!strcmp(track->codec_id, "D_WEBVTT/CAPTIONS")) {
+ st->disposition |= AV_DISPOSITION_CAPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/DESCRIPTIONS")) {
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/METADATA")) {
+ st->disposition |= AV_DISPOSITION_METADATA;
+ }
} else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
+#if FF_API_ASS_SSA
+ if (st->codec->codec_id == AV_CODEC_ID_SSA ||
+ st->codec->codec_id == AV_CODEC_ID_ASS)
+#else
+ if (st->codec->codec_id == AV_CODEC_ID_ASS)
+#endif
matroska->contains_ssa = 1;
}
}
@@ -1877,10 +1956,8 @@ static int matroska_read_header(AVFormatContext *s)
av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0);
st->codec->codec_id = AV_CODEC_ID_NONE;
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if(st->codec->extradata == NULL)
+ if (ff_alloc_extradata(st->codec, attachements[j].bin.size))
break;
- st->codec->extradata_size = attachements[j].bin.size;
memcpy(st->codec->extradata, attachements[j].bin.data, attachements[j].bin.size);
for (i=0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) {
@@ -1961,10 +2038,10 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska)
}
static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
- int size, int type,
+ int* buf_size, int type,
uint32_t **lace_buf, int *laces)
{
- int res = 0, n;
+ int res = 0, n, size = *buf_size;
uint8_t *data = *buf;
uint32_t *lace_size;
@@ -1992,18 +2069,18 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
uint32_t total = 0;
for (n = 0; res == 0 && n < *laces - 1; n++) {
while (1) {
- if (size == 0) {
- res = AVERROR_EOF;
+ if (size <= total) {
+ res = AVERROR_INVALIDDATA;
break;
}
temp = *data;
+ total += temp;
lace_size[n] += temp;
data += 1;
size -= 1;
if (temp != 0xff)
break;
}
- total += lace_size[n];
}
if (size <= total) {
res = AVERROR_INVALIDDATA;
@@ -2025,12 +2102,12 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
case 0x3: /* EBML lacing */ {
uint64_t num;
- uint32_t total;
+ uint64_t total;
n = matroska_ebmlnum_uint(matroska, data, size, &num);
- if (n < 0) {
+ if (n < 0 || num > INT_MAX) {
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
- res = n;
+ res = n<0 ? n : AVERROR_INVALIDDATA;
break;
}
data += n;
@@ -2040,10 +2117,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
int64_t snum;
int r;
r = matroska_ebmlnum_sint(matroska, data, size, &snum);
- if (r < 0) {
+ if (r < 0 || lace_size[n - 1] + snum > (uint64_t)INT_MAX) {
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
- res = r;
+ res = r<0 ? r : AVERROR_INVALIDDATA;
break;
}
data += r;
@@ -2062,6 +2139,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
*buf = data;
*lace_buf = lace_size;
+ *buf_size = size;
return res;
}
@@ -2135,13 +2213,210 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
return 0;
}
+
+/* reconstruct full wavpack blocks from mangled matroska ones */
+static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
+ uint8_t **pdst, int *size)
+{
+ uint8_t *dst = NULL;
+ int dstlen = 0;
+ int srclen = *size;
+ uint32_t samples;
+ uint16_t ver;
+ int ret, offset = 0;
+
+ if (srclen < 12 || track->stream->codec->extradata_size < 2)
+ return AVERROR_INVALIDDATA;
+
+ ver = AV_RL16(track->stream->codec->extradata);
+
+ samples = AV_RL32(src);
+ src += 4;
+ srclen -= 4;
+
+ while (srclen >= 8) {
+ int multiblock;
+ uint32_t blocksize;
+ uint8_t *tmp;
+
+ uint32_t flags = AV_RL32(src);
+ uint32_t crc = AV_RL32(src + 4);
+ src += 8;
+ srclen -= 8;
+
+ multiblock = (flags & 0x1800) != 0x1800;
+ if (multiblock) {
+ if (srclen < 4) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ blocksize = AV_RL32(src);
+ src += 4;
+ srclen -= 4;
+ } else
+ blocksize = srclen;
+
+ if (blocksize > srclen) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ tmp = av_realloc(dst, dstlen + blocksize + 32);
+ if (!tmp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ 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
+
+ src += blocksize;
+ srclen -= blocksize;
+ offset += blocksize + 32;
+ }
+
+ *pdst = dst;
+ *size = dstlen;
+
+ return 0;
+
+fail:
+ av_freep(&dst);
+ return ret;
+}
+
+static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
+ MatroskaTrack *track,
+ AVStream *st,
+ uint8_t *data, int data_len,
+ uint64_t timecode,
+ uint64_t duration,
+ int64_t pos)
+{
+ AVPacket *pkt;
+ uint8_t *id, *settings, *text, *buf;
+ int id_len, settings_len, text_len;
+ uint8_t *p, *q;
+ int err;
+
+ if (data_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ p = data;
+ q = data + data_len;
+
+ id = p;
+ id_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ id_len = p - id;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ settings = p;
+ settings_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ settings_len = p - settings;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ text = p;
+ text_len = q - p;
+ while (text_len > 0) {
+ const int len = text_len - 1;
+ const uint8_t c = p[len];
+ if (c != '\r' && c != '\n')
+ break;
+ text_len = len;
+ }
+
+ if (text_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ pkt = av_mallocz(sizeof(*pkt));
+ err = av_new_packet(pkt, text_len);
+ if (err < 0) {
+ av_free(pkt);
+ return AVERROR(err);
+ }
+
+ memcpy(pkt->data, text, text_len);
+
+ if (id_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ id_len);
+ if (buf == NULL) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, id, id_len);
+ }
+
+ if (settings_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+ settings_len);
+ if (buf == NULL) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, settings, settings_len);
+ }
+
+ // Do we need this for subtitles?
+ // pkt->flags = AV_PKT_FLAG_KEY;
+
+ pkt->stream_index = st->index;
+ pkt->pts = timecode;
+
+ // Do we need this for subtitles?
+ // pkt->dts = timecode;
+
+ pkt->duration = duration;
+ pkt->pos = pos;
+
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+
+ return 0;
+}
+
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track,
AVStream *st,
uint8_t *data, int pkt_size,
uint64_t timecode, uint64_t lace_duration,
int64_t pos, int is_keyframe,
- uint8_t *additional, uint64_t additional_id, int additional_size)
+ uint8_t *additional, uint64_t additional_id, int additional_size,
+ int64_t discard_padding)
{
MatroskaTrackEncoding *encodings = track->encodings.elem;
uint8_t *pkt_data = data;
@@ -2154,6 +2429,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
return res;
}
+ if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) {
+ 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");
+ goto fail;
+ }
+ if (pkt_data != data)
+ av_freep(&pkt_data);
+ pkt_data = wv_data;
+ }
+
if (st->codec->codec_id == AV_CODEC_ID_PRORES)
offset = 8;
@@ -2161,7 +2448,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
/* XXX: prevent data copy... */
if (av_new_packet(pkt, pkt_size + offset) < 0) {
av_free(pkt);
- return AVERROR(ENOMEM);
+ res = AVERROR(ENOMEM);
+ goto fail;
}
if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
@@ -2173,7 +2461,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
memcpy(pkt->data + offset, pkt_data, pkt_size);
if (pkt_data != data)
- av_free(pkt_data);
+ av_freep(&pkt_data);
pkt->flags = is_keyframe;
pkt->stream_index = st->index;
@@ -2191,6 +2479,21 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
memcpy(side_data + 8, additional, additional_size);
}
+ if (discard_padding) {
+ 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);
+ }
+ AV_WL32(side_data, 0);
+ AV_WL32(side_data + 4, av_rescale_q(discard_padding,
+ (AVRational){1, 1000000000},
+ (AVRational){1, st->codec->sample_rate}));
+ }
+
if (track->ms_compat)
pkt->dts = timecode;
else
@@ -2220,6 +2523,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
pkt->duration = lace_duration;
}
+#if FF_API_ASS_SSA
if (st->codec->codec_id == AV_CODEC_ID_SSA)
matroska_fix_ass_packet(matroska, pkt, lace_duration);
@@ -2233,15 +2537,23 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
matroska->prev_pkt = pkt;
}
+#else
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+#endif
return 0;
+fail:
+ if (pkt_data != data)
+ av_freep(&pkt_data);
+ return res;
}
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t block_duration, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
- int64_t cluster_pos)
+ int64_t cluster_pos, int64_t discard_padding)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
@@ -2251,6 +2563,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
uint64_t num;
+ int trust_default_duration = 1;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
@@ -2271,7 +2584,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
return res;
av_assert1(block_duration != AV_NOPTS_VALUE);
- block_time = AV_RB16(data);
+ block_time = sign_extend(AV_RB16(data), 16);
data += 2;
flags = *data++;
size -= 3;
@@ -2291,21 +2604,29 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
if (timecode < matroska->skip_to_timecode)
return res;
- if (!st->skip_to_keyframe) {
+ if (is_keyframe)
+ matroska->skip_to_keyframe = 0;
+ else if (!st->skip_to_keyframe) {
av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n");
matroska->skip_to_keyframe = 0;
}
- if (is_keyframe)
- matroska->skip_to_keyframe = 0;
}
- res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1,
+ res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
&lace_size, &laces);
if (res)
goto end;
- if (!block_duration)
+ 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)
+ trust_default_duration = 0;
+ }
+ }
+
+ if (!block_duration && trust_default_duration)
block_duration = track->default_duration * laces / matroska->time_scale;
if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time))
@@ -2326,16 +2647,26 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
st->codec->block_align && track->audio.sub_packet_size) {
- res = matroska_parse_rm_audio(matroska, track, st, data, size,
+ res = matroska_parse_rm_audio(matroska, track, st, data,
+ lace_size[n],
timecode, pos);
if (res)
goto end;
+ } else if (st->codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ res = matroska_parse_webvtt(matroska, track, st,
+ data, lace_size[n],
+ timecode, lace_duration,
+ 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);
+ additional, additional_id, additional_size,
+ discard_padding);
if (res)
goto end;
}
@@ -2402,11 +2733,11 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
blocks[i].duration, is_keyframe,
additional, blocks[i].additional_id,
blocks[i].additional.size,
- matroska->current_cluster_pos);
+ matroska->current_cluster_pos,
+ blocks[i].discard_padding);
}
}
- if (res < 0) matroska->done = 1;
return res;
}
@@ -2433,7 +2764,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
blocks[i].bin.data, blocks[i].bin.size,
blocks[i].bin.pos, cluster.timecode,
blocks[i].duration, is_keyframe, NULL, 0, 0,
- pos);
+ pos, blocks[i].discard_padding);
}
ebml_free(matroska_cluster, &cluster);
return res;
@@ -2495,10 +2826,11 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
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);
- if (index_sub >= 0
- && st->index_entries[index_sub].pos < st->index_entries[index_min].pos
- && st->index_entries[index].timestamp - st->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale)
- index_min = index_sub;
+ 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--;
}
}
diff --git a/ffmpeg/libavformat/matroskaenc.c b/ffmpeg/libavformat/matroskaenc.c
index a151eef..98804d1 100644
--- a/ffmpeg/libavformat/matroskaenc.c
+++ b/ffmpeg/libavformat/matroskaenc.c
@@ -19,25 +19,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
+#include "avc.h"
#include "avformat.h"
+#include "avio_internal.h"
+#include "avlanguage.h"
+#include "flacenc.h"
#include "internal.h"
-#include "riff.h"
#include "isom.h"
#include "matroska.h"
-#include "avc.h"
-#include "flacenc.h"
-#include "avlanguage.h"
-#include "libavutil/samplefmt.h"
-#include "libavutil/sha.h"
-#include "libavutil/intreadwrite.h"
+#include "riff.h"
+#include "subtitles.h"
+#include "wv.h"
+
+#include "libavutil/avstring.h"
+#include "libavutil/dict.h"
#include "libavutil/intfloat.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/lfg.h"
#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
-#include "libavutil/lfg.h"
-#include "libavutil/dict.h"
-#include "libavutil/avstring.h"
+#include "libavutil/samplefmt.h"
+#include "libavutil/sha.h"
+
#include "libavcodec/xiph.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavcodec/internal.h"
typedef struct ebml_master {
int64_t pos; ///< absolute offset in the file where the master's elements start
@@ -62,6 +71,8 @@ typedef struct {
uint64_t pts;
int tracknum;
int64_t cluster_pos; ///< file offset of the cluster containing the block
+ int64_t relative_pos; ///< relative offset from the position of the cluster containing the block
+ int64_t duration; ///< duration of the block according to time base
} mkv_cuepoint;
typedef struct {
@@ -79,6 +90,7 @@ typedef struct {
#define MODE_WEBM 0x02
typedef struct MatroskaMuxContext {
+ const AVClass *class;
int mode;
AVIOContext *dyn_bc;
ebml_master segment;
@@ -95,6 +107,14 @@ typedef struct MatroskaMuxContext {
AVPacket cur_audio_pkt;
int have_attachments;
+
+ int reserve_cues_space;
+ int cluster_size_limit;
+ int64_t cues_pos;
+ int64_t cluster_time_limit;
+
+ uint32_t chapter_id_offset;
+ int wrote_chapters;
} MatroskaMuxContext;
@@ -102,13 +122,16 @@ typedef struct MatroskaMuxContext {
* offset, 4 bytes for target EBML ID */
#define MAX_SEEKENTRY_SIZE 21
-/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2
+/** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 4
* 8-byte uint max */
-#define MAX_CUETRACKPOS_SIZE 22
+#define MAX_CUETRACKPOS_SIZE 42
/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */
#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks
+/** Seek preroll value for opus */
+#define OPUS_SEEK_PREROLL 80000000
+
static int ebml_id_size(unsigned int id)
{
@@ -131,8 +154,7 @@ static void put_ebml_size_unknown(AVIOContext *pb, int bytes)
{
av_assert0(bytes <= 8);
avio_w8(pb, 0x1ff >> bytes);
- while (--bytes)
- avio_w8(pb, 0xff);
+ ffio_fill(pb, 0xff, bytes - 1);
}
/**
@@ -182,6 +204,19 @@ static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val)
avio_w8(pb, (uint8_t)(val >> i*8));
}
+static void put_ebml_sint(AVIOContext *pb, unsigned int elementid, int64_t val)
+{
+ int i, bytes = 1;
+ uint64_t tmp = 2*(val < 0 ? val^-1 : val);
+
+ while (tmp>>=8) bytes++;
+
+ put_ebml_id(pb, elementid);
+ put_ebml_num(pb, bytes, 0);
+ for (i = bytes - 1; i >= 0; i--)
+ avio_w8(pb, (uint8_t)(val >> i*8));
+}
+
static void put_ebml_float(AVIOContext *pb, unsigned int elementid, double val)
{
put_ebml_id(pb, elementid);
@@ -222,8 +257,7 @@ static void put_ebml_void(AVIOContext *pb, uint64_t size)
put_ebml_num(pb, size-1, 0);
else
put_ebml_num(pb, size-9, 8);
- while(avio_tell(pb) < currentpos + size)
- avio_w8(pb, 0);
+ ffio_fill(pb, 0, currentpos + size - avio_tell(pb));
}
static ebml_master start_ebml_master(AVIOContext *pb, unsigned int elementid, uint64_t expectedsize)
@@ -246,9 +280,7 @@ static void end_ebml_master(AVIOContext *pb, ebml_master master)
static void put_xiph_size(AVIOContext *pb, int size)
{
- int i;
- for (i = 0; i < size / 255; i++)
- avio_w8(pb, 255);
+ ffio_fill(pb, 255, size / 255);
avio_w8(pb, size % 255);
}
@@ -291,14 +323,14 @@ static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid
if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
return -1;
- entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry));
+ entries = av_realloc_array(entries, seekhead->num_entries + 1, sizeof(mkv_seekhead_entry));
if (entries == NULL)
return AVERROR(ENOMEM);
+ seekhead->entries = entries;
- entries[seekhead->num_entries ].elementid = elementid;
- entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
+ seekhead->entries[seekhead->num_entries].elementid = elementid;
+ seekhead->entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
- seekhead->entries = entries;
return 0;
}
@@ -349,7 +381,7 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, mkv_seekhead *seekhead)
currentpos = seekhead->filepos;
}
fail:
- av_free(seekhead->entries);
+ av_freep(&seekhead->entries);
av_free(seekhead);
return currentpos;
@@ -365,22 +397,25 @@ static mkv_cues * mkv_start_cues(int64_t segment_offset)
return cues;
}
-static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos)
+static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos, int64_t relative_pos,
+ int64_t duration)
{
mkv_cuepoint *entries = cues->entries;
if (ts < 0)
return 0;
- entries = av_realloc(entries, (cues->num_entries + 1) * sizeof(mkv_cuepoint));
+ entries = av_realloc_array(entries, cues->num_entries + 1, sizeof(mkv_cuepoint));
if (entries == NULL)
return AVERROR(ENOMEM);
+ cues->entries = entries;
- entries[cues->num_entries ].pts = ts;
- entries[cues->num_entries ].tracknum = stream + 1;
- entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset;
+ cues->entries[cues->num_entries].pts = ts;
+ cues->entries[cues->num_entries].tracknum = stream + 1;
+ cues->entries[cues->num_entries].cluster_pos = cluster_pos - cues->segment_offset;
+ cues->entries[cues->num_entries].relative_pos = relative_pos;
+ cues->entries[cues->num_entries++].duration = duration;
- cues->entries = entries;
return 0;
}
@@ -412,8 +447,11 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, mkv_track *tracks
continue;
tracks[tracknum].has_cue = 1;
track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);
- put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
- put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos);
+ put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
+ put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION , entry[j].cluster_pos);
+ put_ebml_uint(pb, MATROSKA_ID_CUERELATIVEPOSITION, entry[j].relative_pos);
+ if (entry[j].duration != -1)
+ put_ebml_uint(pb, MATROSKA_ID_CUEDURATION , entry[j].duration);
end_ebml_master(pb, track_positions);
}
i += j - 1;
@@ -452,6 +490,15 @@ static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, AVCodecContex
return 0;
}
+static int put_wv_codecpriv(AVIOContext *pb, AVCodecContext *codec)
+{
+ if (codec->extradata && codec->extradata_size == 2)
+ avio_write(pb, codec->extradata, 2);
+ else
+ avio_wl16(pb, 0x403); // fallback to the version mentioned in matroska specs
+ return 0;
+}
+
static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec, int *sample_rate, int *output_sample_rate)
{
MPEG4AudioConfig mp4ac;
@@ -481,6 +528,8 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo
ret = put_xiph_codecpriv(s, dyn_cp, codec);
else if (codec->codec_id == AV_CODEC_ID_FLAC)
ret = ff_flac_write_header(dyn_cp, codec, 1);
+ else if (codec->codec_id == AV_CODEC_ID_WAVPACK)
+ 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_ALAC) {
@@ -510,7 +559,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) {
@@ -558,6 +607,8 @@ static int mkv_write_tracks(AVFormatContext *s)
int bit_depth = av_get_bits_per_sample(codec->codec_id);
int sample_rate = codec->sample_rate;
int output_sample_rate = 0;
+ int display_width_div = 1;
+ int display_height_div = 1;
AVDictionaryEntry *tag;
if (codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) {
@@ -581,28 +632,64 @@ static int mkv_write_tracks(AVFormatContext *s)
if ((tag = av_dict_get(st->metadata, "title", NULL, 0)))
put_ebml_string(pb, MATROSKA_ID_TRACKNAME, tag->value);
tag = av_dict_get(st->metadata, "language", NULL, 0);
- put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und");
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) {
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und");
+ } else if (tag && tag->value) {
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag->value);
+ }
- if (default_stream_exists) {
+ // The default value for TRACKFLAGDEFAULT is 1, so add element
+ // if we need to clear it.
+ if (default_stream_exists && !(st->disposition & AV_DISPOSITION_DEFAULT))
put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT));
- }
+
if (st->disposition & AV_DISPOSITION_FORCED)
put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1);
- // look for a codec ID string specific to mkv to use,
- // if none are found, use AVI codes
- for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
- if (ff_mkv_codec_tags[j].id == codec->codec_id) {
- put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
- native_id = 1;
- break;
+ if (mkv->mode == MODE_WEBM && codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ const char *codec_id;
+ if (st->disposition & AV_DISPOSITION_CAPTIONS) {
+ codec_id = "D_WEBVTT/CAPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) {
+ codec_id = "D_WEBVTT/DESCRIPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else if (st->disposition & AV_DISPOSITION_METADATA) {
+ codec_id = "D_WEBVTT/METADATA";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else {
+ codec_id = "D_WEBVTT/SUBTITLES";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ }
+ put_ebml_string(pb, MATROSKA_ID_CODECID, codec_id);
+ } else {
+ // look for a codec ID string specific to mkv to use,
+ // if none are found, use AVI codes
+ for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
+ if (ff_mkv_codec_tags[j].id == codec->codec_id) {
+ put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
+ native_id = 1;
+ break;
+ }
}
}
+ 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 ||
- codec->codec_id == AV_CODEC_ID_VORBIS)) {
+ codec->codec_id == AV_CODEC_ID_VP9 ||
+ ((codec->codec_id == AV_CODEC_ID_OPUS)&&(codec->strict_std_compliance <= FF_COMPLIANCE_EXPERIMENTAL)) ||
+ codec->codec_id == AV_CODEC_ID_VORBIS ||
+ codec->codec_id == AV_CODEC_ID_WEBVTT)) {
av_log(s, AV_LOG_ERROR,
- "Only VP8 video and Vorbis audio are supported for WebM.\n");
+ "Only VP8,VP9 video and Vorbis,Opus(experimental, use -strict -2) audio and WebVTT subtitles are supported for WebM.\n");
return AVERROR(EINVAL);
}
@@ -653,6 +740,27 @@ static int mkv_write_tracks(AVFormatContext *s)
return AVERROR(EINVAL);
} else
put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, st_mode);
+
+ switch (st_mode) {
+ case 1:
+ case 8:
+ case 9:
+ case 11:
+ display_width_div = 2;
+ break;
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ display_height_div = 2;
+ break;
+ }
+ }
+
+ if ((tag = av_dict_get(st->metadata, "alpha_mode", NULL, 0)) ||
+ (tag = av_dict_get( s->metadata, "alpha_mode", NULL, 0)) ||
+ (codec->pix_fmt == AV_PIX_FMT_YUVA420P)) {
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOALPHAMODE, 1);
}
if (st->sample_aspect_ratio.num) {
@@ -661,8 +769,11 @@ static int mkv_write_tracks(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Overflow in display width\n");
return AVERROR(EINVAL);
}
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width / display_width_div);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div);
+ } else if (display_width_div != 1 || display_height_div != 1) {
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , codec->width / display_width_div);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div);
}
if (codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
@@ -690,18 +801,25 @@ static int mkv_write_tracks(AVFormatContext *s)
break;
case AVMEDIA_TYPE_SUBTITLE:
- put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE);
if (!native_id) {
av_log(s, AV_LOG_ERROR, "Subtitle codec %d is not supported.\n", codec->codec_id);
return AVERROR(ENOSYS);
}
+
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT)
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+
+ put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, native_id);
break;
default:
av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.\n");
- break;
+ return AVERROR(EINVAL);
+ }
+
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) {
+ ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id);
+ if (ret < 0) return ret;
}
- ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id);
- if (ret < 0) return ret;
end_ebml_master(pb, track);
@@ -720,7 +838,7 @@ static int mkv_write_chapters(AVFormatContext *s)
AVRational scale = {1, 1E9};
int i, ret;
- if (!s->nb_chapters)
+ if (!s->nb_chapters || mkv->wrote_chapters)
return 0;
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb));
@@ -736,7 +854,7 @@ static int mkv_write_chapters(AVFormatContext *s)
AVDictionaryEntry *t = NULL;
chapteratom = start_ebml_master(pb, MATROSKA_ID_CHAPTERATOM, 0);
- put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id);
+ put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id + mkv->chapter_id_offset);
put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMESTART,
av_rescale_q(c->start, c->time_base, scale));
put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMEEND,
@@ -753,6 +871,8 @@ static int mkv_write_chapters(AVFormatContext *s)
}
end_ebml_master(pb, editionentry);
end_ebml_master(pb, chapters);
+
+ mkv->wrote_chapters = 1;
return 0;
}
@@ -815,14 +935,26 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme
return 0;
}
+static int mkv_check_tag(AVDictionary *m)
+{
+ AVDictionaryEntry *t = NULL;
+
+ while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
+ if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode"))
+ return 1;
+
+ return 0;
+}
+
static int mkv_write_tags(AVFormatContext *s)
{
+ MatroskaMuxContext *mkv = s->priv_data;
ebml_master tags = {0};
int i, ret;
ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL);
- if (av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ if (mkv_check_tag(s->metadata)) {
ret = mkv_write_tag(s, s->metadata, 0, 0, &tags);
if (ret < 0) return ret;
}
@@ -830,7 +962,7 @@ static int mkv_write_tags(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
- if (!av_dict_get(st->metadata, "", 0, AV_DICT_IGNORE_SUFFIX))
+ if (!mkv_check_tag(st->metadata))
continue;
ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags);
@@ -840,10 +972,10 @@ static int mkv_write_tags(AVFormatContext *s)
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *ch = s->chapters[i];
- if (!av_dict_get(ch->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
+ if (!mkv_check_tag(ch->metadata))
continue;
- ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id, &tags);
+ ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &tags);
if (ret < 0) return ret;
}
@@ -968,7 +1100,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 , 2);
+ put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 4);
put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2);
end_ebml_master(pb, ebml_header);
@@ -1003,6 +1135,10 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT);
put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT);
put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16);
+ } else {
+ const char *ident = "Lavf";
+ put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , ident);
+ put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, ident);
}
if (tag = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
@@ -1022,6 +1158,9 @@ static int mkv_write_header(AVFormatContext *s)
ret = mkv_write_tracks(s);
if (ret < 0) return ret;
+ for (i = 0; i < s->nb_chapters; i++)
+ mkv->chapter_id_offset = FFMAX(mkv->chapter_id_offset, 1LL - s->chapters[i]->id);
+
if (mkv->mode != MODE_WEBM) {
ret = mkv_write_chapters(s);
if (ret < 0) return ret;
@@ -1040,11 +1179,31 @@ static int mkv_write_header(AVFormatContext *s)
if (mkv->cues == NULL)
return AVERROR(ENOMEM);
+ if (pb->seekable && mkv->reserve_cues_space) {
+ mkv->cues_pos = avio_tell(pb);
+ put_ebml_void(pb, mkv->reserve_cues_space);
+ }
+
av_init_packet(&mkv->cur_audio_pkt);
mkv->cur_audio_pkt.size = 0;
mkv->cluster_pos = -1;
avio_flush(pb);
+
+ // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
+ // after 4k and on a keyframe
+ if (pb->seekable) {
+ if (mkv->cluster_time_limit < 0)
+ mkv->cluster_time_limit = 5000;
+ if (mkv->cluster_size_limit < 0)
+ mkv->cluster_size_limit = 5 * 1024 * 1024;
+ } else {
+ if (mkv->cluster_time_limit < 0)
+ mkv->cluster_time_limit = 1000;
+ if (mkv->cluster_size_limit < 0)
+ mkv->cluster_size_limit = 32 * 1024;
+ }
+
return 0;
}
@@ -1072,6 +1231,7 @@ static int ass_get_duration(const uint8_t *p)
return end - start;
}
+#if FF_API_ASS_SSA
static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1116,15 +1276,72 @@ static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
return max_duration;
}
+#endif
+
+static int mkv_strip_wavpack(const uint8_t *src, uint8_t **pdst, int *size)
+{
+ uint8_t *dst;
+ int srclen = *size;
+ int offset = 0;
+ int ret;
+
+ dst = av_malloc(srclen);
+ if (!dst)
+ return AVERROR(ENOMEM);
+
+ while (srclen >= WV_HEADER_SIZE) {
+ WvHeader header;
+
+ ret = ff_wv_parse_header(&header, src);
+ if (ret < 0)
+ goto fail;
+ src += WV_HEADER_SIZE;
+ srclen -= WV_HEADER_SIZE;
+
+ if (srclen < header.blocksize) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ if (header.initial) {
+ AV_WL32(dst + offset, header.samples);
+ offset += 4;
+ }
+ AV_WL32(dst + offset, header.flags);
+ AV_WL32(dst + offset + 4, header.crc);
+ offset += 8;
+
+ if (!(header.initial && header.final)) {
+ AV_WL32(dst + offset, header.blocksize);
+ offset += 4;
+ }
+
+ memcpy(dst + offset, src, header.blocksize);
+ src += header.blocksize;
+ srclen -= header.blocksize;
+ offset += header.blocksize;
+ }
+
+ *pdst = dst;
+ *size = offset;
+
+ return 0;
+fail:
+ av_freep(&dst);
+ return ret;
+}
static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
unsigned int blockid, AVPacket *pkt, int flags)
{
MatroskaMuxContext *mkv = s->priv_data;
AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
- uint8_t *data = NULL;
- int offset = 0, size = pkt->size;
+ uint8_t *data = NULL, *side_data = NULL;
+ int offset = 0, size = pkt->size, side_data_size = 0;
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ uint64_t additional_id = 0;
+ int64_t discard_padding = 0;
+ ebml_master block_group, block_additions, block_more;
av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, "
"pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n",
@@ -1132,7 +1349,13 @@ 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
+ else if (codec->codec_id == AV_CODEC_ID_WAVPACK) {
+ int ret = mkv_strip_wavpack(pkt->data, &data, &size);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Error stripping a WavPack packet.\n");
+ return;
+ }
+ } else
data = pkt->data;
if (codec->codec_id == AV_CODEC_ID_PRORES) {
@@ -1142,6 +1365,30 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
offset = 8;
}
+ side_data = av_packet_get_side_data(pkt,
+ AV_PKT_DATA_SKIP_SAMPLES,
+ &side_data_size);
+
+ if (side_data && side_data_size >= 10) {
+ discard_padding = av_rescale_q(AV_RL32(side_data + 4),
+ (AVRational){1, codec->sample_rate},
+ (AVRational){1, 1000000000});
+ }
+
+ side_data = av_packet_get_side_data(pkt,
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+ &side_data_size);
+ if (side_data) {
+ additional_id = AV_RB64(side_data);
+ side_data += 8;
+ side_data_size -= 8;
+ }
+
+ if ((side_data_size && additional_id == 1) || discard_padding) {
+ block_group = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, 0);
+ blockid = MATROSKA_ID_BLOCK;
+ }
+
put_ebml_id(pb, blockid);
put_ebml_num(pb, size+4, 0);
avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
@@ -1150,6 +1397,24 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
avio_write(pb, data + offset, size);
if (data != pkt->data)
av_free(data);
+
+ if (discard_padding) {
+ put_ebml_sint(pb, MATROSKA_ID_DISCARDPADDING, discard_padding);
+ }
+
+ if (side_data_size && additional_id == 1) {
+ block_additions = start_ebml_master(pb, MATROSKA_ID_BLOCKADDITIONS, 0);
+ block_more = start_ebml_master(pb, MATROSKA_ID_BLOCKMORE, 0);
+ put_ebml_uint(pb, MATROSKA_ID_BLOCKADDID, 1);
+ put_ebml_id(pb, MATROSKA_ID_BLOCKADDITIONAL);
+ put_ebml_num(pb, side_data_size, 0);
+ avio_write(pb, side_data, side_data_size);
+ end_ebml_master(pb, block_more);
+ end_ebml_master(pb, block_additions);
+ }
+ if ((side_data_size && additional_id == 1) || discard_padding) {
+ end_ebml_master(pb, block_group);
+ }
}
static int srt_get_duration(uint8_t **buf)
@@ -1166,7 +1431,7 @@ static int srt_get_duration(uint8_t **buf)
s_hsec += 1000*s_sec; e_hsec += 1000*e_sec;
duration = e_hsec - s_hsec;
}
- *buf += strcspn(*buf, "\n") + 1;
+ *buf += ff_subtitles_next_line(*buf);
}
return duration;
}
@@ -1187,6 +1452,44 @@ static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
return duration;
}
+static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ebml_master blockgroup;
+ int id_size, settings_size, size;
+ uint8_t *id, *settings;
+ int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ const int flags = 0;
+
+ id_size = 0;
+ id = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ &id_size);
+
+ settings_size = 0;
+ settings = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_SETTINGS,
+ &settings_size);
+
+ size = id_size + 1 + settings_size + 1 + pkt->size;
+
+ av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, "
+ "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n",
+ avio_tell(pb), size, pkt->pts, pkt->dts, pkt->duration, flags);
+
+ blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(size));
+
+ put_ebml_id(pb, MATROSKA_ID_BLOCK);
+ put_ebml_num(pb, size+4, 0);
+ avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
+ avio_wb16(pb, ts - mkv->cluster_pts);
+ avio_w8(pb, flags);
+ avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data);
+
+ put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, pkt->duration);
+ end_ebml_master(pb, blockgroup);
+
+ return pkt->duration;
+}
+
static void mkv_flush_dynbuf(AVFormatContext *s)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1211,6 +1514,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
int duration = pkt->duration;
int ret;
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ int64_t relative_packet_pos;
if (ts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n");
@@ -1234,12 +1538,18 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
mkv->cluster_pts = FFMAX(0, ts);
}
+ relative_packet_pos = avio_tell(s->pb) - mkv->cluster.pos;
+
if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7);
+#if FF_API_ASS_SSA
} else if (codec->codec_id == AV_CODEC_ID_SSA) {
duration = mkv_write_ass_blocks(s, pb, pkt);
+#endif
} else if (codec->codec_id == AV_CODEC_ID_SRT) {
duration = mkv_write_srt_blocks(s, pb, pkt);
+ } else if (codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ duration = mkv_write_vtt_blocks(s, pb, pkt);
} else {
ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(pkt->size));
/* For backward compatibility, prefer convergence_duration. */
@@ -1251,8 +1561,9 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
end_ebml_master(pb, blockgroup);
}
- if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) {
- ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos);
+ if ((codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) || codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos,
+ codec->codec_type == AVMEDIA_TYPE_SUBTITLE ? duration : -1);
if (ret < 0) return ret;
}
@@ -1263,24 +1574,41 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
- AVIOContext *pb = s->pb->seekable ? s->pb : mkv->dyn_bc;
- AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
- int ret, keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY);
- int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
- int cluster_size = avio_tell(pb) - (s->pb->seekable ? mkv->cluster_pos : 0);
+ int codec_type = s->streams[pkt->stream_index]->codec->codec_type;
+ int keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY);
+ int cluster_size;
+ int64_t cluster_time;
+ AVIOContext *pb;
+ int ret;
+
+ if (mkv->tracks[pkt->stream_index].write_dts)
+ cluster_time = pkt->dts - mkv->cluster_pts;
+ else
+ cluster_time = pkt->pts - mkv->cluster_pts;
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
// after 4k and on a keyframe
+ if (s->pb->seekable) {
+ pb = s->pb;
+ cluster_size = avio_tell(pb) - mkv->cluster_pos;
+ } else {
+ pb = mkv->dyn_bc;
+ cluster_size = avio_tell(pb);
+ }
+
if (mkv->cluster_pos != -1 &&
- ((!s->pb->seekable && (cluster_size > 32*1024 || ts > mkv->cluster_pts + 1000))
- || cluster_size > 5*1024*1024 || ts > mkv->cluster_pts + 5000
- || (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe && cluster_size > 4*1024))) {
+ (cluster_size > mkv->cluster_size_limit ||
+ cluster_time > mkv->cluster_time_limit ||
+ (codec_type == AVMEDIA_TYPE_VIDEO && keyframe &&
+ cluster_size > 4 * 1024))) {
av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64
- " bytes, pts %" PRIu64 "\n", avio_tell(pb), ts);
+ " bytes, pts %" PRIu64 "dts %" PRIu64 "\n",
+ avio_tell(pb), pkt->pts, pkt->dts);
end_ebml_master(pb, mkv->cluster);
mkv->cluster_pos = -1;
if (mkv->dyn_bc)
mkv_flush_dynbuf(s);
+ avio_flush(s->pb);
}
// check if we have an audio packet cached
@@ -1295,15 +1623,44 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
// buffer an audio packet to ensure the packet containing the video
// keyframe's timecode is contained in the same cluster for WebM
- if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (codec_type == AVMEDIA_TYPE_AUDIO) {
mkv->cur_audio_pkt = *pkt;
- mkv->cur_audio_pkt.buf = av_buffer_ref(pkt->buf);
- ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM);
+ if (pkt->buf) {
+ mkv->cur_audio_pkt.buf = av_buffer_ref(pkt->buf);
+ 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);
+ }
} else
ret = mkv_write_packet_internal(s, pkt);
return ret;
}
+static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ AVIOContext *pb;
+ if (s->pb->seekable)
+ pb = s->pb;
+ else
+ pb = mkv->dyn_bc;
+ if (!pkt) {
+ if (mkv->cluster_pos != -1) {
+ av_log(s, AV_LOG_DEBUG, "Flushing cluster at offset %" PRIu64
+ " bytes\n", avio_tell(pb));
+ end_ebml_master(pb, mkv->cluster);
+ mkv->cluster_pos = -1;
+ if (mkv->dyn_bc)
+ mkv_flush_dynbuf(s);
+ avio_flush(s->pb);
+ }
+ return 0;
+ }
+ return mkv_write_packet(s, pkt);
+}
+
static int mkv_write_trailer(AVFormatContext *s)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1328,9 +1685,35 @@ static int mkv_write_trailer(AVFormatContext *s)
end_ebml_master(pb, mkv->cluster);
}
+ if (mkv->mode != MODE_WEBM) {
+ ret = mkv_write_chapters(s);
+ if (ret < 0) return ret;
+ }
+
if (pb->seekable) {
if (mkv->cues->num_entries) {
- cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams);
+ if (mkv->reserve_cues_space) {
+ int64_t cues_end;
+
+ currentpos = avio_tell(pb);
+ avio_seek(pb, mkv->cues_pos, SEEK_SET);
+
+ cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams);
+ cues_end = avio_tell(pb);
+ if (cues_end > cuespos + mkv->reserve_cues_space) {
+ av_log(s, AV_LOG_ERROR, "Insufficient space reserved for cues: %d "
+ "(needed: %"PRId64").\n", mkv->reserve_cues_space,
+ cues_end - cuespos);
+ return AVERROR(EINVAL);
+ }
+
+ if (cues_end < cuespos + mkv->reserve_cues_space)
+ put_ebml_void(pb, mkv->reserve_cues_space - (cues_end - cuespos));
+
+ avio_seek(pb, currentpos, SEEK_SET);
+ } else {
+ cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams);
+ }
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES, cuespos);
if (ret < 0) return ret;
@@ -1348,7 +1731,7 @@ static int mkv_write_trailer(AVFormatContext *s)
}
end_ebml_master(pb, mkv->segment);
- av_free(mkv->tracks);
+ av_freep(&mkv->tracks);
av_freep(&mkv->cues->entries);
av_freep(&mkv->cues);
@@ -1371,7 +1754,7 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance)
return 0;
}
-const AVCodecTag additional_audio_tags[] = {
+static const AVCodecTag additional_audio_tags[] = {
{ AV_CODEC_ID_ALAC, 0XFFFFFFFF },
{ AV_CODEC_ID_EAC3, 0XFFFFFFFF },
{ AV_CODEC_ID_MLP, 0xFFFFFFFF },
@@ -1384,12 +1767,10 @@ const AVCodecTag additional_audio_tags[] = {
{ AV_CODEC_ID_RA_288, 0xFFFFFFFF },
{ AV_CODEC_ID_COOK, 0xFFFFFFFF },
{ AV_CODEC_ID_TRUEHD, 0xFFFFFFFF },
- { AV_CODEC_ID_WAVPACK, 0xFFFFFFFF },
{ AV_CODEC_ID_NONE, 0xFFFFFFFF }
};
-const AVCodecTag additional_video_tags[] = {
- { AV_CODEC_ID_PRORES, 0xFFFFFFFF },
+static const AVCodecTag additional_video_tags[] = {
{ AV_CODEC_ID_RV10, 0xFFFFFFFF },
{ AV_CODEC_ID_RV20, 0xFFFFFFFF },
{ AV_CODEC_ID_RV30, 0xFFFFFFFF },
@@ -1398,7 +1779,23 @@ const AVCodecTag additional_video_tags[] = {
{ AV_CODEC_ID_NONE, 0xFFFFFFFF }
};
+#define OFFSET(x) offsetof(MatroskaMuxContext, x)
+#define FLAGS AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "reserve_index_space", "Reserve a given amount of space (in bytes) at the beginning of the file for the index (cues).", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "cluster_size_limit", "Store at most the provided amount of bytes in a cluster. ", OFFSET(cluster_size_limit), AV_OPT_TYPE_INT , { .i64 = -1 }, -1, INT_MAX, FLAGS },
+ { "cluster_time_limit", "Store at most the provided number of milliseconds in a cluster.", OFFSET(cluster_time_limit), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS },
+ { NULL },
+};
+
#if CONFIG_MATROSKA_MUXER
+static const AVClass matroska_class = {
+ .class_name = "matroska muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_matroska_muxer = {
.name = "matroska",
.long_name = NULL_IF_CONFIG_SMALL("Matroska"),
@@ -1410,20 +1807,32 @@ AVOutputFormat ff_matroska_muxer = {
.video_codec = CONFIG_LIBX264_ENCODER ?
AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
.write_header = mkv_write_header,
- .write_packet = mkv_write_packet,
+ .write_packet = mkv_write_flush_packet,
.write_trailer = mkv_write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
- AVFMT_TS_NONSTRICT,
+ AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
.codec_tag = (const AVCodecTag* const []){
ff_codec_bmp_tags, ff_codec_wav_tags,
additional_audio_tags, additional_video_tags, 0
},
+#if FF_API_ASS_SSA
.subtitle_codec = AV_CODEC_ID_SSA,
+#else
+ .subtitle_codec = AV_CODEC_ID_ASS,
+#endif
.query_codec = mkv_query_codec,
+ .priv_class = &matroska_class,
};
#endif
#if CONFIG_WEBM_MUXER
+static const AVClass webm_class = {
+ .class_name = "webm muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_webm_muxer = {
.name = "webm",
.long_name = NULL_IF_CONFIG_SMALL("WebM"),
@@ -1432,18 +1841,26 @@ AVOutputFormat ff_webm_muxer = {
.priv_data_size = sizeof(MatroskaMuxContext),
.audio_codec = AV_CODEC_ID_VORBIS,
.video_codec = AV_CODEC_ID_VP8,
+ .subtitle_codec = AV_CODEC_ID_WEBVTT,
.write_header = mkv_write_header,
- .write_packet = mkv_write_packet,
+ .write_packet = mkv_write_flush_packet,
.write_trailer = mkv_write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
- AVFMT_TS_NONSTRICT,
+ AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
+ .priv_class = &webm_class,
};
#endif
#if CONFIG_MATROSKA_AUDIO_MUXER
+static const AVClass mka_class = {
+ .class_name = "matroska audio muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
AVOutputFormat ff_matroska_audio_muxer = {
.name = "matroska",
- .long_name = NULL_IF_CONFIG_SMALL("Matroska"),
+ .long_name = NULL_IF_CONFIG_SMALL("Matroska Audio"),
.mime_type = "audio/x-matroska",
.extensions = "mka",
.priv_data_size = sizeof(MatroskaMuxContext),
@@ -1451,11 +1868,13 @@ AVOutputFormat ff_matroska_audio_muxer = {
AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3,
.video_codec = AV_CODEC_ID_NONE,
.write_header = mkv_write_header,
- .write_packet = mkv_write_packet,
+ .write_packet = mkv_write_flush_packet,
.write_trailer = mkv_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT |
+ AVFMT_ALLOW_FLUSH,
.codec_tag = (const AVCodecTag* const []){
ff_codec_wav_tags, additional_audio_tags, 0
},
+ .priv_class = &mka_class,
};
#endif
diff --git a/ffmpeg/libavformat/md5enc.c b/ffmpeg/libavformat/md5enc.c
index 050efb1..8b14fba 100644
--- a/ffmpeg/libavformat/md5enc.c
+++ b/ffmpeg/libavformat/md5enc.c
@@ -19,21 +19,28 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/md5.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/hash.h"
+#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
struct MD5Context {
- struct AVMD5 *md5;
+ const AVClass *avclass;
+ struct AVHashContext *hash;
+ char *hash_name;
};
static void md5_finish(struct AVFormatContext *s, char *buf)
{
struct MD5Context *c = s->priv_data;
- uint8_t md5[16];
+ uint8_t md5[AV_HASH_MAX_SIZE];
int i, offset = strlen(buf);
- av_md5_final(c->md5, md5);
- for (i = 0; i < sizeof(md5); i++) {
+ int len = av_hash_get_size(c->hash);
+ av_assert0(len > 0 && len <= sizeof(md5));
+ av_hash_final(c->hash, md5);
+ for (i = 0; i < len; i++) {
snprintf(buf + offset, 3, "%02"PRIx8, md5[i]);
offset += 2;
}
@@ -44,32 +51,48 @@ static void md5_finish(struct AVFormatContext *s, char *buf)
avio_flush(s->pb);
}
+#define OFFSET(x) offsetof(struct MD5Context, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption hash_options[] = {
+ { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = "md5"}, 0, 0, ENC },
+ { NULL },
+};
+
+static const AVClass md5enc_class = {
+ .class_name = "hash encoder class",
+ .item_name = av_default_item_name,
+ .option = hash_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
#if CONFIG_MD5_MUXER
static int write_header(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- c->md5 = av_md5_alloc();
- if (!c->md5)
- return AVERROR(ENOMEM);
- av_md5_init(c->md5);
+ int res = av_hash_alloc(&c->hash, c->hash_name);
+ if (res < 0)
+ return res;
+ av_hash_init(c->hash);
return 0;
}
static int write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
struct MD5Context *c = s->priv_data;
- av_md5_update(c->md5, pkt->data, pkt->size);
+ av_hash_update(c->hash, pkt->data, pkt->size);
return 0;
}
static int write_trailer(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- char buf[64] = "MD5=";
+ char buf[256];
+ av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 200);
+ av_strlcat(buf, "=", sizeof(buf) - 200);
md5_finish(s, buf);
- av_freep(&c->md5);
+ av_hash_freep(&c->hash);
return 0;
}
@@ -83,6 +106,7 @@ AVOutputFormat ff_md5_muxer = {
.write_packet = write_packet,
.write_trailer = write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
+ .priv_class = &md5enc_class,
};
#endif
@@ -90,18 +114,23 @@ AVOutputFormat ff_md5_muxer = {
static int framemd5_write_header(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- c->md5 = av_md5_alloc();
- if (!c->md5)
- return AVERROR(ENOMEM);
- return ff_framehash_write_header(s);
+ int res = av_hash_alloc(&c->hash, c->hash_name);
+ if (res < 0)
+ return res;
+ avio_printf(s->pb, "#format: frame checksums\n");
+ avio_printf(s->pb, "#version: 1\n");
+ avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hash));
+ ff_framehash_write_header(s);
+ avio_printf(s->pb, "#stream#, dts, pts, duration, size, hash\n");
+ return 0;
}
static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
struct MD5Context *c = s->priv_data;
char buf[256];
- av_md5_init(c->md5);
- av_md5_update(c->md5, pkt->data, pkt->size);
+ av_hash_init(c->hash);
+ av_hash_update(c->hash, pkt->data, pkt->size);
snprintf(buf, sizeof(buf) - 64, "%d, %10"PRId64", %10"PRId64", %8d, %8d, ",
pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size);
@@ -112,10 +141,17 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
static int framemd5_write_trailer(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- av_freep(&c->md5);
+ av_hash_freep(&c->hash);
return 0;
}
+static const AVClass framemd5_class = {
+ .class_name = "frame hash encoder class",
+ .item_name = av_default_item_name,
+ .option = hash_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_framemd5_muxer = {
.name = "framemd5",
.long_name = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"),
@@ -125,6 +161,8 @@ AVOutputFormat ff_framemd5_muxer = {
.write_header = framemd5_write_header,
.write_packet = framemd5_write_packet,
.write_trailer = framemd5_write_trailer,
- .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
+ AVFMT_TS_NEGATIVE,
+ .priv_class = &framemd5_class,
};
#endif
diff --git a/ffmpeg/libavformat/microdvddec.c b/ffmpeg/libavformat/microdvddec.c
index 4b42846..7b49e43 100644
--- a/ffmpeg/libavformat/microdvddec.c
+++ b/ffmpeg/libavformat/microdvddec.c
@@ -1,7 +1,7 @@
/*
* MicroDVD subtitle demuxer
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
- * Copyright (c) 2012 Clément Bœsch <ubitux@gmail.com>
+ * Copyright (c) 2012 Clément Bœsch <u pkh me>
*
* This file is part of FFmpeg.
*
@@ -47,7 +47,7 @@ static int microdvd_probe(AVProbeData *p)
sscanf(ptr, "{%*d}{%*d}%c", &c) != 1 &&
sscanf(ptr, "{DEFAULT}{}%c", &c) != 1)
return 0;
- ptr += strcspn(ptr, "\n") + 1;
+ ptr += ff_subtitles_next_line(ptr);
}
return AVPROBE_SCORE_MAX;
}
diff --git a/ffmpeg/libavformat/microdvdenc.c b/ffmpeg/libavformat/microdvdenc.c
index 30fd0ea..4d84384 100644
--- a/ffmpeg/libavformat/microdvdenc.c
+++ b/ffmpeg/libavformat/microdvdenc.c
@@ -52,7 +52,6 @@ static int microdvd_write_packet(AVFormatContext *avf, AVPacket *pkt)
avio_printf(avf->pb, "{%"PRId64"}", pkt->pts + pkt->duration);
avio_write(avf->pb, pkt->data, pkt->size);
avio_write(avf->pb, "\n", 1);
- avio_flush(avf->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/mkvtimestamp_v2.c b/ffmpeg/libavformat/mkvtimestamp_v2.c
index 3ed195a..7ba6691 100644
--- a/ffmpeg/libavformat/mkvtimestamp_v2.c
+++ b/ffmpeg/libavformat/mkvtimestamp_v2.c
@@ -37,7 +37,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_WARNING, "More than one stream unsupported\n");
snprintf(buf, sizeof(buf), "%" PRId64 "\n", pkt->dts);
avio_write(s->pb, buf, strlen(buf));
- avio_flush(s->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/mm.c b/ffmpeg/libavformat/mm.c
index 12a11ac..4315802 100644
--- a/ffmpeg/libavformat/mm.c
+++ b/ffmpeg/libavformat/mm.c
@@ -79,7 +79,7 @@ static int probe(AVProbeData *p)
return 0;
/* only return half certainty since this check is a bit sketchy */
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int read_header(AVFormatContext *s)
diff --git a/ffmpeg/libavformat/mmf.c b/ffmpeg/libavformat/mmf.c
index d074d7c..cb87a6d 100644
--- a/ffmpeg/libavformat/mmf.c
+++ b/ffmpeg/libavformat/mmf.c
@@ -21,8 +21,8 @@
#include "libavutil/channel_layout.h"
#include "avformat.h"
-#include "internal.h"
#include "avio_internal.h"
+#include "internal.h"
#include "pcm.h"
#include "rawenc.h"
#include "riff.h"
@@ -37,7 +37,7 @@ static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
static int mmf_rate(int code)
{
- if((code < 0) || (code > 4))
+ if ((code < 0) || (code > 4))
return -1;
return mmf_rates[code];
}
@@ -46,8 +46,8 @@ static int mmf_rate(int code)
static int mmf_rate_code(int rate)
{
int i;
- for(i = 0; i < 5; i++)
- if(mmf_rates[i] == rate)
+ for (i = 0; i < 5; i++)
+ if (mmf_rates[i] == rate)
return i;
return -1;
}
@@ -74,8 +74,9 @@ static int mmf_write_header(AVFormatContext *s)
"VN:"LIBAVFORMAT_IDENT",";
rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
- if(rate < 0) {
- av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n", s->streams[0]->codec->sample_rate);
+ if (rate < 0) {
+ av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n",
+ s->streams[0]->codec->sample_rate);
return AVERROR(EINVAL);
}
@@ -97,6 +98,7 @@ static int mmf_write_header(AVFormatContext *s)
avio_w8(pb, 0); /* status */
avio_w8(pb, 0); /* counts */
end_tag_be(pb, pos);
+
pos = ff_start_tag(pb, "OPDA");
avio_write(pb, version, strlen(version)); /* metadata ("ST:songtitle,VN:version,...") */
end_tag_be(pb, pos);
@@ -129,7 +131,7 @@ static int mmf_write_header(AVFormatContext *s)
/* Write a variable-length symbol */
static void put_varlength(AVIOContext *pb, int val)
{
- if(val < 128)
+ if (val < 128)
avio_w8(pb, val);
else {
val -= 128;
@@ -151,7 +153,7 @@ static int mmf_write_trailer(AVFormatContext *s)
end_tag_be(pb, mmf->atrpos);
end_tag_be(pb, 8);
- pos = avio_tell(pb);
+ pos = avio_tell(pb);
size = pos - mmf->awapos;
/* Fill Atsq chunk */
@@ -206,11 +208,13 @@ static int mmf_read_header(AVFormatContext *s)
avio_skip(pb, 4); /* file_size */
/* Skip some unused chunks that may or may not be present */
- for(;; avio_skip(pb, size)) {
- tag = avio_rl32(pb);
+ for (;; avio_skip(pb, size)) {
+ tag = avio_rl32(pb);
size = avio_rb32(pb);
- if(tag == MKTAG('C','N','T','I')) continue;
- if(tag == MKTAG('O','P','D','A')) continue;
+ if (tag == MKTAG('C', 'N', 'T', 'I'))
+ continue;
+ if (tag == MKTAG('O', 'P', 'D', 'A'))
+ continue;
break;
}
@@ -227,8 +231,8 @@ static int mmf_read_header(AVFormatContext *s)
avio_r8(pb); /* format type */
avio_r8(pb); /* sequence type */
params = avio_r8(pb); /* (channel << 7) | (format << 4) | rate */
- rate = mmf_rate(params & 0x0f);
- if(rate < 0) {
+ rate = mmf_rate(params & 0x0f);
+ if (rate < 0) {
av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
return AVERROR_INVALIDDATA;
}
@@ -237,11 +241,13 @@ static int mmf_read_header(AVFormatContext *s)
avio_r8(pb); /* time base g */
/* Skip some unused chunks that may or may not be present */
- for(;; avio_skip(pb, size)) {
- tag = avio_rl32(pb);
+ for (;; avio_skip(pb, size)) {
+ tag = avio_rl32(pb);
size = avio_rb32(pb);
- if(tag == MKTAG('A','t','s','q')) continue;
- if(tag == MKTAG('A','s','p','I')) continue;
+ if (tag == MKTAG('A', 't', 's', 'q'))
+ continue;
+ if (tag == MKTAG('A', 's', 'p', 'I'))
+ continue;
break;
}
@@ -256,13 +262,14 @@ static int mmf_read_header(AVFormatContext *s)
if (!st)
return AVERROR(ENOMEM);
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA;
- st->codec->sample_rate = rate;
- st->codec->channels = (params >> 7) + 1;
- st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA;
+ st->codec->sample_rate = rate;
+ st->codec->channels = (params >> 7) + 1;
+ st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
st->codec->bits_per_coded_sample = 4;
- st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample;
+ st->codec->bit_rate = st->codec->sample_rate *
+ st->codec->bits_per_coded_sample;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
@@ -271,8 +278,7 @@ static int mmf_read_header(AVFormatContext *s)
#define MAX_SIZE 4096
-static int mmf_read_packet(AVFormatContext *s,
- AVPacket *pkt)
+static int mmf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MMFContext *mmf = s->priv_data;
int64_t left, size;
@@ -303,17 +309,18 @@ AVInputFormat ff_mmf_demuxer = {
.flags = AVFMT_GENERIC_INDEX,
};
#endif
+
#if CONFIG_MMF_MUXER
AVOutputFormat ff_mmf_muxer = {
- .name = "mmf",
- .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
- .mime_type = "application/vnd.smaf",
- .extensions = "mmf",
- .priv_data_size = sizeof(MMFContext),
- .audio_codec = AV_CODEC_ID_ADPCM_YAMAHA,
- .video_codec = AV_CODEC_ID_NONE,
- .write_header = mmf_write_header,
- .write_packet = ff_raw_write_packet,
- .write_trailer = mmf_write_trailer,
+ .name = "mmf",
+ .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
+ .mime_type = "application/vnd.smaf",
+ .extensions = "mmf",
+ .priv_data_size = sizeof(MMFContext),
+ .audio_codec = AV_CODEC_ID_ADPCM_YAMAHA,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = mmf_write_header,
+ .write_packet = ff_raw_write_packet,
+ .write_trailer = mmf_write_trailer,
};
#endif
diff --git a/ffmpeg/libavformat/mms.c b/ffmpeg/libavformat/mms.c
index 46fbede..7e60b3b 100644
--- a/ffmpeg/libavformat/mms.c
+++ b/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/ffmpeg/libavformat/mmsh.c b/ffmpeg/libavformat/mmsh.c
index 86a0575..482ece4 100644
--- a/ffmpeg/libavformat/mmsh.c
+++ b/ffmpeg/libavformat/mmsh.c
@@ -66,9 +66,9 @@ static int mmsh_close(URLContext *h)
MMSHContext *mmsh = (MMSHContext *)h->priv_data;
MMSContext *mms = &mmsh->mms;
if (mms->mms_hd)
- ffurl_close(mms->mms_hd);
- av_free(mms->streams);
- av_free(mms->asf_header);
+ ffurl_closep(&mms->mms_hd);
+ av_freep(&mms->streams);
+ av_freep(&mms->asf_header);
return 0;
}
@@ -368,23 +368,26 @@ static int mmsh_read(URLContext *h, uint8_t *buf, int size)
static int64_t mmsh_read_seek(URLContext *h, int stream_index,
int64_t timestamp, int flags)
{
- MMSHContext *mmsh = h->priv_data;
- MMSContext *mms = &mmsh->mms;
+ MMSHContext *mmsh_old = h->priv_data;
+ MMSHContext *mmsh = av_mallocz(sizeof(*mmsh));
int ret;
- ret= mmsh_open_internal(h, mmsh->location, 0, FFMAX(timestamp, 0), 0);
+ if (!mmsh)
+ return AVERROR(ENOMEM);
+ h->priv_data = mmsh;
+ ret= mmsh_open_internal(h, mmsh_old->location, 0, FFMAX(timestamp, 0), 0);
if(ret>=0){
- if (mms->mms_hd)
- ffurl_close(mms->mms_hd);
- av_freep(&mms->streams);
- av_freep(&mms->asf_header);
+ h->priv_data = mmsh_old;
+ mmsh_close(h);
+ h->priv_data = mmsh;
+ av_free(mmsh_old);
+ mmsh->mms.asf_header_read_size = mmsh->mms.asf_header_size;
+ }else {
+ h->priv_data = mmsh_old;
av_free(mmsh);
- mmsh = h->priv_data;
- mms = &mmsh->mms;
- mms->asf_header_read_size= mms->asf_header_size;
- }else
- h->priv_data= mmsh;
+ }
+
return ret;
}
diff --git a/ffmpeg/libavformat/mmst.c b/ffmpeg/libavformat/mmst.c
index c3d2ebb..ebef3ef 100644
--- a/ffmpeg/libavformat/mmst.c
+++ b/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.
@@ -152,7 +152,7 @@ static int send_command_packet(MMSTContext *mmst)
return 0;
}
-static void mms_put_utf16(MMSContext *mms, const uint8_t *src)
+static int mms_put_utf16(MMSContext *mms, const uint8_t *src)
{
AVIOContext bic;
int size = mms->write_out_ptr - mms->out_buffer;
@@ -161,7 +161,10 @@ static void mms_put_utf16(MMSContext *mms, const uint8_t *src)
sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL);
len = avio_put_str16le(&bic, src);
+ if (len < 0)
+ return len;
mms->write_out_ptr += len;
+ return 0;
}
static int send_time_test_data(MMSTContext *mmst)
@@ -173,6 +176,7 @@ static int send_time_test_data(MMSTContext *mmst)
static int send_protocol_select(MMSTContext *mmst)
{
+ int ret;
char data_string[256];
MMSContext *mms = &mmst->mms;
@@ -189,18 +193,21 @@ static int send_protocol_select(MMSTContext *mmst)
"TCP", // or UDP
LOCAL_PORT);
- mms_put_utf16(mms, data_string);
+ if ((ret = mms_put_utf16(mms, data_string)) < 0)
+ return ret;
return send_command_packet(mmst);
}
static int send_media_file_request(MMSTContext *mmst)
{
+ int ret;
MMSContext *mms = &mmst->mms;
start_command_packet(mmst, CS_PKT_MEDIA_FILE_REQUEST);
insert_command_prefixes(mms, 1, 0xffffffff);
bytestream_put_le32(&mms->write_out_ptr, 0);
bytestream_put_le32(&mms->write_out_ptr, 0);
- mms_put_utf16(mms, mmst->path + 1); // +1 for skip "/"
+ if ((ret = mms_put_utf16(mms, mmst->path + 1)) < 0) // +1 for skip "/"
+ return ret;
return send_command_packet(mmst);
}
@@ -331,16 +338,16 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst)
// if we successfully read everything.
if(packet_id_type == mmst->header_packet_id) {
+ int err;
packet_type = SC_PKT_ASF_HEADER;
// Store the asf header
if(!mms->header_parsed) {
- void *p = av_realloc(mms->asf_header,
- mms->asf_header_size + mms->remaining_in_len);
- if (!p) {
- av_freep(&mms->asf_header);
- return AVERROR(ENOMEM);
+ if ((err = av_reallocp(&mms->asf_header,
+ mms->asf_header_size +
+ mms->remaining_in_len)) < 0) {
+ mms->asf_header_size = 0;
+ return err;
}
- mms->asf_header = p;
memcpy(mms->asf_header + mms->asf_header_size,
mms->read_in_ptr, mms->remaining_in_len);
mms->asf_header_size += mms->remaining_in_len;
@@ -417,6 +424,7 @@ static int send_media_header_request(MMSTContext *mmst)
static int send_startup_packet(MMSTContext *mmst)
{
char data_string[256];
+ int ret;
MMSContext *mms = &mmst->mms;
// SubscriberName is defined in MS specification linked below.
// The guid value can be any valid value.
@@ -429,7 +437,8 @@ static int send_startup_packet(MMSTContext *mmst)
start_command_packet(mmst, CS_PKT_INITIAL);
insert_command_prefixes(mms, 0, 0x0004000b);
bytestream_put_le32(&mms->write_out_ptr, 0x0003001c);
- mms_put_utf16(mms, data_string);
+ if ((ret = mms_put_utf16(mms, data_string)) < 0)
+ return ret;
return send_command_packet(mmst);
}
diff --git a/ffmpeg/libavformat/mov.c b/ffmpeg/libavformat/mov.c
index 577c0e9..8dc6062 100644
--- a/ffmpeg/libavformat/mov.c
+++ b/ffmpeg/libavformat/mov.c
@@ -3,6 +3,9 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
+ * first version by Francois Revol <revol@free.fr>
+ * seek function by Gael Chardon <gael.dev@4now.net>
+ *
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
@@ -21,8 +24,8 @@
*/
#include <limits.h>
+#include <stdint.h>
-//#define DEBUG
//#define MOV_EXPORT_ALL_METADATA
#include "libavutil/attributes.h"
@@ -48,11 +51,6 @@
#include <zlib.h>
#endif
-/*
- * First version by Francois Revol revol@free.fr
- * Seek function by Gael Chardon gael.dev@4now.net
- */
-
#include "qtpalette.h"
@@ -539,7 +537,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] == ':')
@@ -788,6 +787,12 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
int ret;
+ if (c->found_moov) {
+ av_log(c->fc, AV_LOG_WARNING, "Found duplicated MOOV Atom. Skipped it\n");
+ avio_skip(pb, atom.size);
+ return 0;
+ }
+
if ((ret = mov_read_default(c, pb, atom)) < 0)
return ret;
/* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
@@ -833,6 +838,11 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
st = c->fc->streams[c->fc->nb_streams-1];
sc = st->priv_data;
+ if (sc->time_scale) {
+ av_log(c->fc, AV_LOG_ERROR, "Multiple mdhd?\n");
+ return AVERROR_INVALIDDATA;
+ }
+
version = avio_r8(pb);
if (version > 1) {
avpriv_request_sample(c->fc, "Version %d", version);
@@ -880,7 +890,7 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */
// set the AVCodecContext duration because the duration of individual tracks
// may be inaccurate
- if (c->time_scale > 0)
+ if (c->time_scale > 0 && !c->trex_data)
c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
avio_rb32(pb); /* preferred scale */
@@ -973,6 +983,7 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
AVStream *st;
uint64_t size;
uint8_t *buf;
+ int err;
if (c->fc->nb_streams < 1) // will happen with jp2 files
return 0;
@@ -984,15 +995,22 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
return AVERROR_INVALIDDATA;
- buf= av_realloc(st->codec->extradata, size);
- if (!buf)
- return AVERROR(ENOMEM);
- st->codec->extradata= buf;
- buf+= st->codec->extradata_size;
+ if ((err = av_reallocp(&st->codec->extradata, size)) < 0) {
+ st->codec->extradata_size = 0;
+ return err;
+ }
+ buf = st->codec->extradata + st->codec->extradata_size;
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;
}
@@ -1017,6 +1035,38 @@ static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI);
}
+static int mov_read_targa_y216(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_TARGA_Y216);
+
+ if (!ret && c->fc->nb_streams >= 1) {
+ AVCodecContext *avctx = c->fc->streams[c->fc->nb_streams-1]->codec;
+ if (avctx->extradata_size >= 40) {
+ avctx->height = AV_RB16(&avctx->extradata[36]);
+ avctx->width = AV_RB16(&avctx->extradata[38]);
+ }
+ }
+ return ret;
+}
+
+static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ if (c->fc->nb_streams >= 1) {
+ AVCodecContext *codec = c->fc->streams[c->fc->nb_streams-1]->codec;
+ if (codec->codec_tag == MKTAG('A', 'V', 'i', 'n') &&
+ codec->codec_id == AV_CODEC_ID_H264 &&
+ atom.size > 11) {
+ avio_skip(pb, 10);
+ /* For AVID AVCI50, force width of 1440 to be able to select the correct SPS and PPS */
+ if (avio_rb16(pb) == 0xd4d)
+ codec->width = 1440;
+ return 0;
+ }
+ }
+
+ return mov_read_avid(c, pb, atom);
+}
+
static int mov_read_svq3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
return mov_read_extradata(c, pb, atom, AV_CODEC_ID_SVQ3);
@@ -1033,15 +1083,13 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((uint64_t)atom.size > (1<<30))
return AVERROR_INVALIDDATA;
- if (st->codec->codec_id == AV_CODEC_ID_QDM2 || st->codec->codec_id == AV_CODEC_ID_QDMC) {
+ if (st->codec->codec_id == AV_CODEC_ID_QDM2 ||
+ st->codec->codec_id == AV_CODEC_ID_QDMC ||
+ 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);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, atom.size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size;
- 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)
@@ -1076,12 +1124,9 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return mov_read_default(c, pb, atom);
}
av_free(st->codec->extradata);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, atom.size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size;
- avio_read(pb, st->codec->extradata, atom.size);
+
return 0;
}
@@ -1089,6 +1134,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;
@@ -1101,14 +1147,11 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((profile_level & 0xf0) != 0xc0)
return 0;
- av_free(st->codec->extradata);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size - 7;
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;
}
@@ -1130,14 +1173,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);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, atom.size - 40) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size - 40;
- avio_skip(pb, 40);
- avio_read(pb, st->codec->extradata, atom.size - 40);
return 0;
}
@@ -1198,342 +1237,306 @@ enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags)
return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0);
}
-int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
+static int mov_codec_id(AVStream *st, uint32_t format)
{
- AVStream *st;
- MOVStreamContext *sc;
- int j, pseudo_stream_id;
-
- if (c->fc->nb_streams < 1)
- return 0;
- st = c->fc->streams[c->fc->nb_streams-1];
- sc = st->priv_data;
-
- for (pseudo_stream_id = 0;
- pseudo_stream_id < entries && !pb->eof_reached;
- pseudo_stream_id++) {
- //Parsing Sample description table
- enum AVCodecID id;
- int dref_id = 1;
- MOVAtom a = { AV_RL32("stsd") };
- int64_t start_pos = avio_tell(pb);
- int64_t size = avio_rb32(pb); /* size */
- uint32_t format = avio_rl32(pb); /* data format */
-
- if (size >= 16) {
- avio_rb32(pb); /* reserved */
- avio_rb16(pb); /* reserved */
- dref_id = avio_rb16(pb);
- }else if (size <= 7){
- av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRId64" in stsd\n", size);
- return AVERROR_INVALIDDATA;
- }
+ int id = ff_codec_get_id(ff_codec_movaudio_tags, format);
- if (st->codec->codec_tag &&
- st->codec->codec_tag != format &&
- (c->fc->video_codec_id ? ff_codec_get_id(ff_codec_movvideo_tags, format) != c->fc->video_codec_id
- : st->codec->codec_tag != MKTAG('j','p','e','g'))
- ){
- /* Multiple fourcc, we skip JPEG. This is not correct, we should
- * export it as a separate AVStream but this needs a few changes
- * in the MOV demuxer, patch welcome. */
- av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
- avio_skip(pb, size - (avio_tell(pb) - start_pos));
- continue;
- }
- /* we cannot demux concatenated h264 streams because of different extradata */
- if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
- av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n");
- sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
- sc->dref_id= dref_id;
+ if (id <= 0 &&
+ ((format & 0xFFFF) == 'm' + ('s' << 8) ||
+ (format & 0xFFFF) == 'T' + ('S' << 8)))
+ id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format) & 0xFFFF);
- st->codec->codec_tag = format;
- id = ff_codec_get_id(ff_codec_movaudio_tags, format);
- if (id<=0 && ((format&0xFFFF) == 'm'+('s'<<8) || (format&0xFFFF) == 'T'+('S'<<8)))
- id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format)&0xFFFF);
-
- if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) {
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- } else if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO && /* do not overwrite codec type */
- format && format != MKTAG('m','p','4','s')) { /* skip old asf mpeg4 tag */
- id = ff_codec_get_id(ff_codec_movvideo_tags, format);
- if (id <= 0)
- id = ff_codec_get_id(ff_codec_bmp_tags, format);
+ if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) {
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ } else if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO &&
+ /* skip old asf mpeg4 tag */
+ format && format != MKTAG('m','p','4','s')) {
+ id = ff_codec_get_id(ff_codec_movvideo_tags, format);
+ if (id <= 0)
+ id = ff_codec_get_id(ff_codec_bmp_tags, format);
+ if (id > 0)
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ else if (st->codec->codec_type == AVMEDIA_TYPE_DATA ||
+ (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
+ st->codec->codec_id == AV_CODEC_ID_NONE)) {
+ id = ff_codec_get_id(ff_codec_movsubtitle_tags, format);
if (id > 0)
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- else if (st->codec->codec_type == AVMEDIA_TYPE_DATA ||
- (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
- st->codec->codec_id == AV_CODEC_ID_NONE)){
- id = ff_codec_get_id(ff_codec_movsubtitle_tags, format);
- if (id > 0)
- st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- }
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
}
+ }
- av_dlog(c->fc, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size,
- (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff,
- (format >> 24) & 0xff, st->codec->codec_type);
+ st->codec->codec_tag = format;
+
+ return id;
+}
+
+static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
+ AVStream *st, MOVStreamContext *sc)
+{
+ unsigned int color_depth, len, j;
+ int color_greyscale;
+ int color_table_id;
+
+ avio_rb16(pb); /* version */
+ avio_rb16(pb); /* revision level */
+ avio_rb32(pb); /* vendor */
+ avio_rb32(pb); /* temporal quality */
+ avio_rb32(pb); /* spatial quality */
+
+ st->codec->width = avio_rb16(pb); /* width */
+ st->codec->height = avio_rb16(pb); /* height */
+
+ avio_rb32(pb); /* horiz resolution */
+ avio_rb32(pb); /* vert resolution */
+ avio_rb32(pb); /* data size, always 0 */
+ avio_rb16(pb); /* frames per samples */
+
+ 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);
+ if (len < 31)
+ avio_skip(pb, 31 - len);
+ /* 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)) {
+ 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))
+ st->codec->codec_id = AV_CODEC_ID_FLV1;
+
+ st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */
+ color_table_id = avio_rb16(pb); /* colortable id */
+ av_dlog(c->fc, "depth %d, ctab id %d\n",
+ st->codec->bits_per_coded_sample, color_table_id);
+ /* 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 (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
- unsigned int color_depth, len;
- int color_greyscale;
- int color_table_id;
+ /* if the depth is 2, 4, or 8 bpp, file is palettized */
+ if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) {
+ /* for palette traversal */
+ unsigned int color_start, color_count, color_end;
+ unsigned char a, r, g, b;
+
+ if (color_greyscale) {
+ int color_index, color_dec;
+ /* compute the greyscale palette */
+ color_count = 1 << color_depth;
+ color_index = 255;
+ color_dec = 256 / (color_count - 1);
+ for (j = 0; j < color_count; j++) {
+ r = g = b = color_index;
+ sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
+ color_index -= color_dec;
+ if (color_index < 0)
+ color_index = 0;
+ }
+ } else if (color_table_id) {
+ const uint8_t *color_table;
+ /* if flag bit 3 is set, use the default palette */
+ color_count = 1 << color_depth;
+ if (color_depth == 2)
+ color_table = ff_qt_default_palette_4;
+ else if (color_depth == 4)
+ color_table = ff_qt_default_palette_16;
+ else
+ color_table = ff_qt_default_palette_256;
- st->codec->codec_id = id;
- avio_rb16(pb); /* version */
- avio_rb16(pb); /* revision level */
- avio_rb32(pb); /* vendor */
- avio_rb32(pb); /* temporal quality */
- avio_rb32(pb); /* spatial quality */
-
- st->codec->width = avio_rb16(pb); /* width */
- st->codec->height = avio_rb16(pb); /* height */
-
- avio_rb32(pb); /* horiz resolution */
- avio_rb32(pb); /* vert resolution */
- avio_rb32(pb); /* data size, always 0 */
- avio_rb16(pb); /* frames per samples */
-
- 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);
- if (len < 31)
- avio_skip(pb, 31 - len);
- /* 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)){
- st->codec->codec_tag=MKTAG('I', '4', '2', '0');
- st->codec->width &= ~1;
- st->codec->height &= ~1;
+ for (j = 0; j < color_count; j++) {
+ r = color_table[j * 3 + 0];
+ g = color_table[j * 3 + 1];
+ b = color_table[j * 3 + 2];
+ sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
}
- /* Flash Media Server uses tag H263 with Sorenson Spark */
- if (format == MKTAG('H','2','6','3') &&
- !memcmp(st->codec->codec_name, "Sorenson H263", 13))
- st->codec->codec_id = AV_CODEC_ID_FLV1;
-
- st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */
- color_table_id = avio_rb16(pb); /* colortable id */
- av_dlog(c->fc, "depth %d, ctab id %d\n",
- st->codec->bits_per_coded_sample, color_table_id);
- /* figure out the palette situation */
- color_depth = st->codec->bits_per_coded_sample & 0x1F;
- color_greyscale = st->codec->bits_per_coded_sample & 0x20;
-
- /* if the depth is 2, 4, or 8 bpp, file is palettized */
- if ((color_depth == 2) || (color_depth == 4) ||
- (color_depth == 8)) {
- /* for palette traversal */
- unsigned int color_start, color_count, color_end;
- unsigned char a, r, g, b;
-
- if (color_greyscale) {
- int color_index, color_dec;
- /* compute the greyscale palette */
- st->codec->bits_per_coded_sample = color_depth;
- color_count = 1 << color_depth;
- color_index = 255;
- color_dec = 256 / (color_count - 1);
- for (j = 0; j < color_count; j++) {
- if (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;
- if (color_index < 0)
- color_index = 0;
- }
- } else if (color_table_id) {
- const uint8_t *color_table;
- /* if flag bit 3 is set, use the default palette */
- color_count = 1 << color_depth;
- if (color_depth == 2)
- color_table = ff_qt_default_palette_4;
- else if (color_depth == 4)
- color_table = ff_qt_default_palette_16;
- else
- color_table = ff_qt_default_palette_256;
-
- for (j = 0; j < color_count; j++) {
- r = color_table[j * 3 + 0];
- g = color_table[j * 3 + 1];
- b = color_table[j * 3 + 2];
- sc->palette[j] =
- (0xFFU << 24) | (r << 16) | (g << 8) | (b);
- }
- } else {
- /* load the palette from the file */
- color_start = avio_rb32(pb);
- color_count = avio_rb16(pb);
- color_end = avio_rb16(pb);
- if ((color_start <= 255) &&
- (color_end <= 255)) {
- for (j = color_start; j <= color_end; j++) {
- /* each A, R, G, or B component is 16 bits;
- * only use the top 8 bits */
- a = avio_r8(pb);
- avio_r8(pb);
- r = avio_r8(pb);
- avio_r8(pb);
- g = avio_r8(pb);
- avio_r8(pb);
- b = avio_r8(pb);
- avio_r8(pb);
- sc->palette[j] =
- (a << 24 ) | (r << 16) | (g << 8) | (b);
- }
- }
+ } else {
+ /* load the palette from the file */
+ color_start = avio_rb32(pb);
+ color_count = avio_rb16(pb);
+ color_end = avio_rb16(pb);
+ if ((color_start <= 255) && (color_end <= 255)) {
+ for (j = color_start; j <= color_end; j++) {
+ /* each A, R, G, or B component is 16 bits;
+ * only use the top 8 bits */
+ a = avio_r8(pb);
+ avio_r8(pb);
+ r = avio_r8(pb);
+ avio_r8(pb);
+ g = avio_r8(pb);
+ avio_r8(pb);
+ b = avio_r8(pb);
+ avio_r8(pb);
+ sc->palette[j] = (a << 24 ) | (r << 16) | (g << 8) | (b);
}
- sc->has_palette = 1;
}
- } else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
- int bits_per_sample, flags;
- uint16_t version = avio_rb16(pb);
- AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
+ }
+ sc->has_palette = 1;
+ }
+}
- st->codec->codec_id = id;
- avio_rb16(pb); /* revision level */
- avio_rb32(pb); /* vendor */
-
- st->codec->channels = avio_rb16(pb); /* channel count */
- av_dlog(c->fc, "audio channels %d\n", st->codec->channels);
- st->codec->bits_per_coded_sample = avio_rb16(pb); /* sample size */
-
- sc->audio_cid = avio_rb16(pb);
- avio_rb16(pb); /* packet size = 0 */
-
- st->codec->sample_rate = ((avio_rb32(pb) >> 16));
-
- //Read QT version 1 fields. In version 0 these do not exist.
- av_dlog(c->fc, "version =%d, isom =%d\n",version,c->isom);
- if (!c->isom ||
- (compatible_brands && strstr(compatible_brands->value, "qt "))) {
- if (version==1) {
- sc->samples_per_frame = avio_rb32(pb);
- avio_rb32(pb); /* bytes per packet */
- sc->bytes_per_frame = avio_rb32(pb);
- avio_rb32(pb); /* bytes per sample */
- } else if (version==2) {
- avio_rb32(pb); /* sizeof struct only */
- st->codec->sample_rate = av_int2double(avio_rb64(pb)); /* float 64 */
- st->codec->channels = avio_rb32(pb);
- avio_rb32(pb); /* always 0x7F000000 */
- st->codec->bits_per_coded_sample = avio_rb32(pb); /* bits per channel if sound is uncompressed */
- flags = avio_rb32(pb); /* lpcm format specific flag */
- sc->bytes_per_frame = avio_rb32(pb); /* bytes per audio packet if constant */
- sc->samples_per_frame = avio_rb32(pb); /* lpcm frames per audio packet if constant */
- if (format == MKTAG('l','p','c','m'))
- st->codec->codec_id = ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, flags);
- }
- }
+static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
+ AVStream *st, MOVStreamContext *sc)
+{
+ int bits_per_sample, flags;
+ uint16_t version = avio_rb16(pb);
+ AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
- switch (st->codec->codec_id) {
- case AV_CODEC_ID_PCM_S8:
- case AV_CODEC_ID_PCM_U8:
- if (st->codec->bits_per_coded_sample == 16)
- st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
- break;
- case AV_CODEC_ID_PCM_S16LE:
- case AV_CODEC_ID_PCM_S16BE:
- if (st->codec->bits_per_coded_sample == 8)
- st->codec->codec_id = AV_CODEC_ID_PCM_S8;
- else if (st->codec->bits_per_coded_sample == 24)
- st->codec->codec_id =
- st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ?
- AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
- break;
- /* set values for old format before stsd version 1 appeared */
- case AV_CODEC_ID_MACE3:
- sc->samples_per_frame = 6;
- sc->bytes_per_frame = 2*st->codec->channels;
- break;
- case AV_CODEC_ID_MACE6:
- sc->samples_per_frame = 6;
- sc->bytes_per_frame = 1*st->codec->channels;
- break;
- case AV_CODEC_ID_ADPCM_IMA_QT:
- sc->samples_per_frame = 64;
- sc->bytes_per_frame = 34*st->codec->channels;
- break;
- case AV_CODEC_ID_GSM:
- sc->samples_per_frame = 160;
- sc->bytes_per_frame = 33;
- break;
- default:
- break;
- }
+ avio_rb16(pb); /* revision level */
+ avio_rb32(pb); /* vendor */
- bits_per_sample = av_get_bits_per_sample(st->codec->codec_id);
- if (bits_per_sample) {
- st->codec->bits_per_coded_sample = bits_per_sample;
- sc->sample_size = (bits_per_sample >> 3) * st->codec->channels;
- }
- } else if (st->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){
- // ttxt stsd contains display flags, justification, background
- // color, fonts, and default styles, so fake an atom to read it
- MOVAtom fake_atom = { .size = size - (avio_tell(pb) - start_pos) };
- if (format != AV_RL32("mp4s")) // mp4s contains a regular esds atom
- mov_read_glbl(c, pb, fake_atom);
- st->codec->codec_id= id;
- st->codec->width = sc->width;
- st->codec->height = sc->height;
- } else {
- if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
- MOVStreamContext *tmcd_ctx = st->priv_data;
- int val;
- avio_rb32(pb); /* reserved */
- val = avio_rb32(pb); /* flags */
- tmcd_ctx->tmcd_flags = val;
- if (val & 1)
- st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
- avio_rb32(pb); /* time scale */
- avio_rb32(pb); /* frame duration */
- st->codec->time_base.den = avio_r8(pb); /* number of frame */
- st->codec->time_base.num = 1;
- }
- /* other codec type, just skip (rtp, mp4s, ...) */
- avio_skip(pb, size - (avio_tell(pb) - start_pos));
+ st->codec->channels = avio_rb16(pb); /* channel count */
+ st->codec->bits_per_coded_sample = avio_rb16(pb); /* sample size */
+ av_dlog(c->fc, "audio channels %d\n", st->codec->channels);
+
+ sc->audio_cid = avio_rb16(pb);
+ avio_rb16(pb); /* packet size = 0 */
+
+ st->codec->sample_rate = ((avio_rb32(pb) >> 16));
+
+ // Read QT version 1 fields. In version 0 these do not exist.
+ av_dlog(c->fc, "version =%d, isom =%d\n", version, c->isom);
+ if (!c->isom ||
+ (compatible_brands && strstr(compatible_brands->value, "qt "))) {
+
+ if (version == 1) {
+ sc->samples_per_frame = avio_rb32(pb);
+ avio_rb32(pb); /* bytes per packet */
+ sc->bytes_per_frame = avio_rb32(pb);
+ avio_rb32(pb); /* bytes per sample */
+ } else if (version == 2) {
+ avio_rb32(pb); /* sizeof struct only */
+ st->codec->sample_rate = av_int2double(avio_rb64(pb));
+ st->codec->channels = avio_rb32(pb);
+ avio_rb32(pb); /* always 0x7F000000 */
+ st->codec->bits_per_coded_sample = avio_rb32(pb);
+
+ flags = avio_rb32(pb); /* lpcm format specific flag */
+ sc->bytes_per_frame = avio_rb32(pb);
+ sc->samples_per_frame = avio_rb32(pb);
+ if (st->codec->codec_tag == MKTAG('l','p','c','m'))
+ st->codec->codec_id =
+ ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample,
+ flags);
}
- /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */
- a.size = size - (avio_tell(pb) - start_pos);
- if (a.size > 8) {
- int ret;
- if ((ret = mov_read_default(c, pb, a)) < 0)
- return ret;
- } else if (a.size > 0)
- avio_skip(pb, a.size);
}
- if (pb->eof_reached)
- return AVERROR_EOF;
+ switch (st->codec->codec_id) {
+ case AV_CODEC_ID_PCM_S8:
+ case AV_CODEC_ID_PCM_U8:
+ if (st->codec->bits_per_coded_sample == 16)
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+ break;
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ if (st->codec->bits_per_coded_sample == 8)
+ st->codec->codec_id = AV_CODEC_ID_PCM_S8;
+ else if (st->codec->bits_per_coded_sample == 24)
+ st->codec->codec_id =
+ st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ?
+ AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
+ break;
+ /* set values for old format before stsd version 1 appeared */
+ case AV_CODEC_ID_MACE3:
+ sc->samples_per_frame = 6;
+ sc->bytes_per_frame = 2 * st->codec->channels;
+ break;
+ case AV_CODEC_ID_MACE6:
+ sc->samples_per_frame = 6;
+ sc->bytes_per_frame = 1 * st->codec->channels;
+ break;
+ case AV_CODEC_ID_ADPCM_IMA_QT:
+ sc->samples_per_frame = 64;
+ sc->bytes_per_frame = 34 * st->codec->channels;
+ break;
+ case AV_CODEC_ID_GSM:
+ sc->samples_per_frame = 160;
+ sc->bytes_per_frame = 33;
+ break;
+ default:
+ break;
+ }
+
+ bits_per_sample = av_get_bits_per_sample(st->codec->codec_id);
+ if (bits_per_sample) {
+ st->codec->bits_per_coded_sample = bits_per_sample;
+ sc->sample_size = (bits_per_sample >> 3) * st->codec->channels;
+ }
+}
- if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1)
- st->codec->sample_rate= sc->time_scale;
+static void mov_parse_stsd_subtitle(MOVContext *c, AVIOContext *pb,
+ AVStream *st, MOVStreamContext *sc,
+ int size)
+{
+ // ttxt stsd contains display flags, justification, background
+ // color, fonts, and default styles, so fake an atom to read it
+ MOVAtom fake_atom = { .size = size };
+ // mp4s contains a regular esds atom
+ if (st->codec->codec_tag != AV_RL32("mp4s"))
+ mov_read_glbl(c, pb, fake_atom);
+ st->codec->width = sc->width;
+ st->codec->height = sc->height;
+}
+
+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_get_extradata(st->codec, pb, size) < 0)
+ return AVERROR(ENOMEM);
+ if (size > 16) {
+ MOVStreamContext *tmcd_ctx = st->priv_data;
+ int val;
+ val = AV_RB32(st->codec->extradata + 4);
+ tmcd_ctx->tmcd_flags = val;
+ if (val & 1)
+ st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
+ st->codec->time_base.den = st->codec->extradata[16]; /* number of frame */
+ st->codec->time_base.num = 1;
+ }
+ } else {
+ /* other codec type, just skip (rtp, mp4s ...) */
+ avio_skip(pb, size);
+ }
+ return 0;
+}
+
+static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
+ AVStream *st, MOVStreamContext *sc)
+{
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ !st->codec->sample_rate && sc->time_scale > 1)
+ st->codec->sample_rate = sc->time_scale;
/* special codec parameters handling */
switch (st->codec->codec_id) {
#if CONFIG_DV_DEMUXER
case AV_CODEC_ID_DVAUDIO:
- c->dv_fctx = avformat_alloc_context();
+ c->dv_fctx = avformat_alloc_context();
c->dv_demux = avpriv_dv_init_demux(c->dv_fctx);
if (!c->dv_demux) {
av_log(c->fc, AV_LOG_ERROR, "dv demux context init error\n");
return AVERROR(ENOMEM);
}
sc->dv_audio_container = 1;
- st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
break;
#endif
/* no ifdef since parameters are always those */
case AV_CODEC_ID_QCELP:
+ st->codec->channels = 1;
// 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;
- st->codec->channels= 1; /* really needed */
break;
case AV_CODEC_ID_AMR_NB:
- st->codec->channels= 1; /* really needed */
+ st->codec->channels = 1;
/* force sample rate for amr, stsd in 3gp does not store sample rate */
st->codec->sample_rate = 8000;
break;
@@ -1543,19 +1546,23 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
break;
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MP3:
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO; /* force type after stsd for m1a hdlr */
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ /* force type after stsd for m1a hdlr */
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
break;
case AV_CODEC_ID_GSM:
case AV_CODEC_ID_ADPCM_MS:
case AV_CODEC_ID_ADPCM_IMA_WAV:
case AV_CODEC_ID_ILBC:
+ case AV_CODEC_ID_MACE3:
+ case AV_CODEC_ID_MACE6:
+ case AV_CODEC_ID_QDM2:
st->codec->block_align = sc->bytes_per_frame;
break;
case AV_CODEC_ID_ALAC:
if (st->codec->extradata_size == 36) {
- st->codec->channels = AV_RB8 (st->codec->extradata+21);
- st->codec->sample_rate = AV_RB32(st->codec->extradata+32);
+ st->codec->channels = AV_RB8 (st->codec->extradata + 21);
+ st->codec->sample_rate = AV_RB32(st->codec->extradata + 32);
}
break;
case AV_CODEC_ID_AC3:
@@ -1570,10 +1577,111 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
default:
break;
}
+ return 0;
+}
+
+static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
+ int codec_tag, int format,
+ int size)
+{
+ int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
+
+ if (codec_tag &&
+ (codec_tag != format &&
+ (c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
+ : codec_tag != MKTAG('j','p','e','g')))) {
+ /* Multiple fourcc, we skip JPEG. This is not correct, we should
+ * export it as a separate AVStream but this needs a few changes
+ * in the MOV demuxer, patch welcome. */
+
+ av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
+ avio_skip(pb, size);
+ return 1;
+ }
+ if ( codec_tag == AV_RL32("avc1") ||
+ codec_tag == AV_RL32("hvc1") ||
+ codec_tag == AV_RL32("hev1")
+ )
+ av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
return 0;
}
+int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+ int pseudo_stream_id;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+ sc = st->priv_data;
+
+ for (pseudo_stream_id = 0;
+ pseudo_stream_id < entries && !pb->eof_reached;
+ pseudo_stream_id++) {
+ //Parsing Sample description table
+ enum AVCodecID id;
+ int ret, dref_id = 1;
+ MOVAtom a = { AV_RL32("stsd") };
+ int64_t start_pos = avio_tell(pb);
+ int64_t size = avio_rb32(pb); /* size */
+ uint32_t format = avio_rl32(pb); /* data format */
+
+ if (size >= 16) {
+ avio_rb32(pb); /* reserved */
+ avio_rb16(pb); /* reserved */
+ dref_id = avio_rb16(pb);
+ }else if (size <= 7){
+ av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRId64" in stsd\n", size);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (mov_skip_multiple_stsd(c, pb, st->codec->codec_tag, format,
+ size - (avio_tell(pb) - start_pos)))
+ continue;
+
+ sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
+ sc->dref_id= dref_id;
+
+ id = mov_codec_id(st, format);
+
+ av_dlog(c->fc, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size,
+ (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff,
+ (format >> 24) & 0xff, st->codec->codec_type);
+
+ if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
+ st->codec->codec_id = id;
+ mov_parse_stsd_video(c, pb, st, sc);
+ } else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
+ st->codec->codec_id = id;
+ mov_parse_stsd_audio(c, pb, st, sc);
+ } else if (st->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){
+ st->codec->codec_id = id;
+ mov_parse_stsd_subtitle(c, pb, st, sc,
+ size - (avio_tell(pb) - start_pos));
+ } else {
+ ret = mov_parse_stsd_data(c, pb, st, sc,
+ size - (avio_tell(pb) - start_pos));
+ if (ret < 0)
+ return ret;
+ }
+ /* this will read extra atoms at the end (wave, alac, damr, avcC, hvcC, SMI ...) */
+ a.size = size - (avio_tell(pb) - start_pos);
+ if (a.size > 8) {
+ if ((ret = mov_read_default(c, pb, a)) < 0)
+ return ret;
+ } else if (a.size > 0)
+ avio_skip(pb, a.size);
+ }
+
+ if (pb->eof_reached)
+ return AVERROR_EOF;
+
+ return mov_finalize_stsd_codec(c, pb, st, sc);
+}
+
static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
int entries;
@@ -1679,6 +1787,8 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
{
sc->keyframe_absent = 1;
+ if (!st->need_parsing && st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
return 0;
}
if (entries >= UINT_MAX / sizeof(int))
@@ -1720,7 +1830,7 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sample_size = avio_rb32(pb);
if (!sc->sample_size) /* do not overwrite value computed in stsd */
sc->sample_size = sample_size;
- sc->alt_sample_size = sample_size;
+ sc->stsz_sample_size = sample_size;
field_size = 32;
} else {
sample_size = 0;
@@ -1811,11 +1921,16 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sample_count=avio_rb32(pb);
sample_duration = avio_rb32(pb);
+
/* 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);
sample_duration = 1;
}
+ if (sample_count < 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Invalid sample_count=%d\n", sample_count);
+ return AVERROR_INVALIDDATA;
+ }
sc->stts_data[i].count= sample_count;
sc->stts_data[i].duration= sample_duration;
@@ -1838,6 +1953,13 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static void mov_update_dts_shift(MOVStreamContext *sc, int duration)
+{
+ if (duration < 0) {
+ sc->dts_shift = FFMAX(sc->dts_shift, -duration);
+ }
+}
+
static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@@ -1880,8 +2002,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
- if (duration < 0 && i+2<entries)
- sc->dts_shift = FFMAX(sc->dts_shift, -duration);
+ if (i+2<entries)
+ mov_update_dts_shift(sc, duration);
}
sc->ctts_count = i;
@@ -1945,7 +2067,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned int stps_index = 0;
unsigned int i, j;
uint64_t stream_size = 0;
- AVIndexEntry *mem;
/* adjust first dts according to edit list */
if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) {
@@ -1980,17 +2101,31 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
return;
if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
return;
- mem = av_realloc(st->index_entries, (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries));
- if (!mem)
+ if (av_reallocp_array(&st->index_entries,
+ st->nb_index_entries + sc->sample_count,
+ sizeof(*st->index_entries)) < 0) {
+ st->nb_index_entries = 0;
return;
- st->index_entries = mem;
+ }
st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries);
for (i = 0; i < sc->chunk_count; i++) {
+ int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX;
current_offset = sc->chunk_offsets[i];
while (stsc_index + 1 < sc->stsc_count &&
i + 1 == sc->stsc_data[stsc_index + 1].first)
stsc_index++;
+
+ if (next_offset > current_offset && sc->sample_size>0 && sc->sample_size < sc->stsz_sample_size &&
+ sc->stsc_data[stsc_index].count * (int64_t)sc->stsz_sample_size > next_offset - current_offset) {
+ av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too large), ignoring\n", sc->stsz_sample_size);
+ sc->stsz_sample_size = sc->sample_size;
+ }
+ if (sc->stsz_sample_size>0 && sc->stsz_sample_size < sc->sample_size) {
+ av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too small), ignoring\n", sc->stsz_sample_size);
+ sc->stsz_sample_size = sc->sample_size;
+ }
+
for (j = 0; j < sc->stsc_data[stsc_index].count; j++) {
int keyframe = 0;
if (current_sample >= sc->sample_count) {
@@ -2017,7 +2152,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
if (keyframe)
distance = 0;
- sample_size = sc->alt_sample_size > 0 ? sc->alt_sample_size : sc->sample_sizes[current_sample];
+ sample_size = sc->stsz_sample_size > 0 ? sc->stsz_sample_size : sc->sample_sizes[current_sample];
if (sc->pseudo_stream_id == -1 ||
sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {
AVIndexEntry *e = &st->index_entries[st->nb_index_entries++];
@@ -2029,6 +2164,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
av_dlog(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
"size %d, distance %d, keyframe %d\n", st->index, current_sample,
current_offset, current_dts, sample_size, distance, keyframe);
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries < 100)
+ ff_rfps_add_frame(mov->fc, st, current_dts);
}
current_offset += sample_size;
@@ -2078,10 +2215,12 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
av_dlog(mov->fc, "chunk count %d\n", total);
if (total >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
return;
- mem = av_realloc(st->index_entries, (st->nb_index_entries + total) * sizeof(*st->index_entries));
- if (!mem)
+ if (av_reallocp_array(&st->index_entries,
+ st->nb_index_entries + total,
+ sizeof(*st->index_entries)) < 0) {
+ st->nb_index_entries = 0;
return;
- st->index_entries = mem;
+ }
st->index_entries_allocated_size = (st->nb_index_entries + total) * sizeof(*st->index_entries);
// populate index
@@ -2258,8 +2397,10 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
// done for ai5q, ai52, ai55, ai1q, ai12 and ai15.
if (!st->codec->extradata_size && st->codec->codec_id == AV_CODEC_ID_H264 &&
- st->codec->codec_tag != MKTAG('a', 'v', 'c', '1')) {
- ff_generate_avci_extradata(st);
+ TAG_IS_AVCI(st->codec->codec_tag)) {
+ ret = ff_generate_avci_extradata(st);
+ if (ret < 0)
+ return ret;
}
switch (st->codec->codec_id) {
@@ -2322,6 +2463,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *st;
MOVStreamContext *sc;
int version;
+ int flags;
if (c->fc->nb_streams < 1)
return 0;
@@ -2329,13 +2471,8 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc = st->priv_data;
version = avio_r8(pb);
- avio_rb24(pb); /* flags */
- /*
- MOV_TRACK_ENABLED 0x0001
- MOV_TRACK_IN_MOVIE 0x0002
- MOV_TRACK_IN_PREVIEW 0x0004
- MOV_TRACK_IN_POSTER 0x0008
- */
+ flags = avio_rb24(pb);
+ st->disposition |= (flags & MOV_TKHD_FLAG_ENABLED) ? AV_DISPOSITION_DEFAULT : 0;
if (version == 1) {
avio_rb64(pb);
@@ -2456,16 +2593,18 @@ static int mov_read_chap(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVTrackExt *trex;
+ int err;
if ((uint64_t)c->trex_count+1 >= UINT_MAX / sizeof(*c->trex_data))
return AVERROR_INVALIDDATA;
- trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data));
- if (!trex)
- return AVERROR(ENOMEM);
+ if ((err = av_reallocp_array(&c->trex_data, c->trex_count + 1,
+ sizeof(*c->trex_data))) < 0) {
+ c->trex_count = 0;
+ return err;
+ }
c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used.
- c->trex_data = trex;
trex = &c->trex_data[c->trex_count++];
avio_r8(pb); /* version */
avio_rb24(pb); /* flags */
@@ -2487,7 +2626,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int64_t dts;
int data_offset = 0;
unsigned entries, first_sample_flags = frag->flags;
- int flags, distance, i, found_keyframe = 0;
+ int flags, distance, i, found_keyframe = 0, err;
for (i = 0; i < c->fc->nb_streams; i++) {
if (c->fc->streams[i]->id == frag->track_id) {
@@ -2500,7 +2639,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR_INVALIDDATA;
}
sc = st->priv_data;
- if (sc->pseudo_stream_id+1 != frag->stsd_id)
+ if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1)
return 0;
avio_r8(pb); /* version */
flags = avio_rb24(pb);
@@ -2515,7 +2654,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!sc->ctts_count && sc->sample_count)
{
/* Complement ctts table if moov atom doesn't have ctts atom. */
- ctts_data = av_malloc(sizeof(*sc->ctts_data));
+ ctts_data = av_realloc(NULL, sizeof(*sc->ctts_data));
if (!ctts_data)
return AVERROR(ENOMEM);
sc->ctts_data = ctts_data;
@@ -2525,12 +2664,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data))
return AVERROR_INVALIDDATA;
- ctts_data = av_realloc(sc->ctts_data,
- (entries+sc->ctts_count)*sizeof(*sc->ctts_data));
- if (!ctts_data)
- return AVERROR(ENOMEM);
- sc->ctts_data = ctts_data;
-
+ if ((err = av_reallocp_array(&sc->ctts_data, entries + sc->ctts_count,
+ sizeof(*sc->ctts_data))) < 0) {
+ sc->ctts_count = 0;
+ return err;
+ }
if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
dts = sc->track_end - sc->time_offset;
@@ -2549,6 +2687,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->ctts_data[sc->ctts_count].count = 1;
sc->ctts_data[sc->ctts_count].duration = (flags & MOV_TRUN_SAMPLE_CTS) ?
avio_rb32(pb) : 0;
+ mov_update_dts_shift(sc, sc->ctts_data[sc->ctts_count].duration);
sc->ctts_count++;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
keyframe = 1;
@@ -2709,11 +2848,77 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret;
+ uint8_t uuid[16];
+ static const uint8_t uuid_isml_manifest[] = {
+ 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
+ 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
+ };
+
+ if (atom.size < sizeof(uuid) || atom.size == INT64_MAX)
+ return AVERROR_INVALIDDATA;
+
+ ret = avio_read(pb, uuid, sizeof(uuid));
+ if (ret < 0) {
+ return ret;
+ } else if (ret != sizeof(uuid)) {
+ return AVERROR_INVALIDDATA;
+ }
+ if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) {
+ uint8_t *buffer, *ptr;
+ char *endptr;
+ size_t len = atom.size - sizeof(uuid);
+
+ if (len < 4) {
+ return AVERROR_INVALIDDATA;
+ }
+ ret = avio_skip(pb, 4); // zeroes
+ len -= 4;
+
+ buffer = av_mallocz(len + 1);
+ if (!buffer) {
+ return AVERROR(ENOMEM);
+ }
+ ret = avio_read(pb, buffer, len);
+ if (ret < 0) {
+ av_free(buffer);
+ return ret;
+ } else if (ret != len) {
+ av_free(buffer);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ptr = buffer;
+ while ((ptr = av_stristr(ptr, "systemBitrate=\"")) != NULL) {
+ ptr += sizeof("systemBitrate=\"") - 1;
+ c->bitrates_count++;
+ c->bitrates = av_realloc_f(c->bitrates, c->bitrates_count, sizeof(*c->bitrates));
+ if (!c->bitrates) {
+ c->bitrates_count = 0;
+ av_free(buffer);
+ return AVERROR(ENOMEM);
+ }
+ errno = 0;
+ ret = strtol(ptr, &endptr, 10);
+ if (ret < 0 || errno || *endptr != '"') {
+ c->bitrates[c->bitrates_count - 1] = 0;
+ } else {
+ c->bitrates[c->bitrates_count - 1] = ret;
+ }
+ }
+
+ av_free(buffer);
+ }
+ return 0;
+}
+
static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('A','C','L','R'), mov_read_avid },
{ MKTAG('A','P','R','G'), mov_read_avid },
{ MKTAG('A','A','L','P'), mov_read_avid },
-{ MKTAG('A','R','E','S'), mov_read_avid },
+{ MKTAG('A','R','E','S'), mov_read_ares },
{ MKTAG('a','v','s','s'), mov_read_avss },
{ MKTAG('c','h','p','l'), mov_read_chpl },
{ MKTAG('c','o','6','4'), mov_read_stco },
@@ -2772,6 +2977,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */
{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ MKTAG('s','b','g','p'), mov_read_sbgp },
+{ 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 },
{ 0, NULL }
};
@@ -2845,8 +3053,10 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
left = a.size - avio_tell(pb) + start_pos;
if (left > 0) /* skip garbage at atom end */
avio_skip(pb, left);
- else if(left < 0) {
- av_log(c->fc, AV_LOG_DEBUG, "undoing overread of %"PRId64" in '%.4s'\n", -left, (char*)&a.type);
+ else if (left < 0) {
+ av_log(c->fc, AV_LOG_WARNING,
+ "overread end of atom '%.4s' by %"PRId64" bytes\n",
+ (char*)&a.type, -left);
avio_seek(pb, left, SEEK_CUR);
}
}
@@ -2887,7 +3097,7 @@ static int mov_probe(AVProbeData *p)
(AV_RB32(p->buf+offset) != 1 ||
offset + 12 > (unsigned int)p->buf_size ||
AV_RB64(p->buf+offset + 8) == 0)) {
- score = FFMAX(score, AVPROBE_SCORE_MAX - 50);
+ score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
} else {
score = AVPROBE_SCORE_MAX;
}
@@ -2907,7 +3117,7 @@ static int mov_probe(AVProbeData *p)
case MKTAG('u','u','i','d'):
case MKTAG('p','r','f','l'):
/* if we only find those cause probedata is too small at least rate them */
- score = FFMAX(score, AVPROBE_SCORE_MAX - 50);
+ score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
break;
default:
@@ -3088,6 +3298,7 @@ static int mov_read_close(AVFormatContext *s)
}
av_freep(&mov->trex_data);
+ av_freep(&mov->bitrates);
return 0;
}
@@ -3195,11 +3406,19 @@ static int mov_read_header(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MOVStreamContext *sc = st->priv_data;
- if (st->duration)
+ if (st->duration > 0)
st->codec->bit_rate = sc->data_size * 8 * sc->time_scale / st->duration;
}
}
+ for (i = 0; i < mov->bitrates_count && i < s->nb_streams; i++) {
+ if (mov->bitrates[i]) {
+ s->streams[i]->codec->bit_rate = mov->bitrates[i];
+ }
+ }
+
+ ff_rfps_calculate(s);
+
return 0;
}
@@ -3255,6 +3474,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
/* must be done just before reading, to avoid infinite loop on sample */
sc->current_sample++;
+ if (mov->next_root_atom) {
+ sample->pos = FFMIN(sample->pos, mov->next_root_atom);
+ sample->size = FFMIN(sample->size, (mov->next_root_atom - sample->pos));
+ }
+
if (st->discard != AVDISCARD_ALL) {
if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n",
@@ -3387,7 +3611,7 @@ static const AVOption options[] = {
{NULL}
};
-static const AVClass class = {
+static const AVClass mov_class = {
.class_name = "mov,mp4,m4a,3gp,3g2,mj2",
.item_name = av_default_item_name,
.option = options,
@@ -3403,6 +3627,6 @@ AVInputFormat ff_mov_demuxer = {
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
- .priv_class = &class,
+ .priv_class = &mov_class,
.flags = AVFMT_NO_BYTE_SEEK,
};
diff --git a/ffmpeg/libavformat/mov_chan.c b/ffmpeg/libavformat/mov_chan.c
index 7078b4a..e7b5221 100644
--- a/ffmpeg/libavformat/mov_chan.c
+++ b/ffmpeg/libavformat/mov_chan.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/mov_chan.h b/ffmpeg/libavformat/mov_chan.h
index 3fae939..ca28345 100644
--- a/ffmpeg/libavformat/mov_chan.h
+++ b/ffmpeg/libavformat/mov_chan.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/movenc.c b/ffmpeg/libavformat/movenc.c
index 42496b5..a886ab0 100644
--- a/ffmpeg/libavformat/movenc.c
+++ b/ffmpeg/libavformat/movenc.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "movenc.h"
#include "avformat.h"
#include "avio_internal.h"
@@ -52,7 +54,8 @@ static const AVOption options[] = {
{ "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
- { "faststart", "Run a second pass to put the moov at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
{ "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
@@ -62,6 +65,7 @@ static const AVOption options[] = {
{ "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "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},
{ NULL },
};
@@ -73,6 +77,8 @@ static const AVClass flavor ## _muxer_class = {\
.version = LIBAVUTIL_VERSION_INT,\
};
+static int get_moov_size(AVFormatContext *s);
+
//FIXME support 64 bit variant with wide placeholders
static int64_t update_size(AVIOContext *pb, int64_t pos)
{
@@ -86,20 +92,14 @@ static int64_t update_size(AVIOContext *pb, int64_t pos)
static int supports_edts(MOVMuxContext *mov)
{
- // EDTS with fragments is tricky as we dont know the duration when its written
+ // EDTS with fragments is tricky as we don't know the duration when its written
return (mov->use_editlist<0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) || mov->use_editlist>0;
}
-static int is_co64_required(const MOVTrack *track)
+static int co64_required(const MOVTrack *track)
{
- int i;
-
- for (i = 0; i < track->entry; i++) {
- if (!track->cluster[i].chunkNum)
- continue;
- if (track->cluster[i].pos + track->data_offset > UINT32_MAX)
- return 1;
- }
+ if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
+ return 1;
return 0;
}
@@ -107,7 +107,7 @@ static int is_co64_required(const MOVTrack *track)
static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
{
int i;
- int mode64 = is_co64_required(track); // use 32 bit size variant if possible
+ int mode64 = co64_required(track); // use 32 bit size variant if possible
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
if (mode64)
@@ -116,10 +116,10 @@ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "stco");
avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, track->chunkCount); /* entry count */
- for (i=0; i<track->entry; i++) {
- if(!track->cluster[i].chunkNum)
+ for (i = 0; i < track->entry; i++) {
+ if (!track->cluster[i].chunkNum)
continue;
- if(mode64 == 1)
+ if (mode64 == 1)
avio_wb64(pb, track->cluster[i].pos + track->data_offset);
else
avio_wb32(pb, track->cluster[i].pos + track->data_offset);
@@ -138,27 +138,25 @@ static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "stsz");
avio_wb32(pb, 0); /* version & flags */
- for (i=0; i<track->entry; i++) {
- tst = track->cluster[i].size/track->cluster[i].entries;
- if(oldtst != -1 && tst != oldtst) {
+ for (i = 0; i < track->entry; i++) {
+ tst = track->cluster[i].size / track->cluster[i].entries;
+ if (oldtst != -1 && tst != oldtst)
equalChunks = 0;
- }
oldtst = tst;
entries += track->cluster[i].entries;
}
if (equalChunks && track->entry) {
- int sSize = track->entry ? track->cluster[0].size/track->cluster[0].entries : 0;
+ int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
avio_wb32(pb, sSize); // sample size
avio_wb32(pb, entries); // sample count
- }
- else {
+ } else {
avio_wb32(pb, 0); // sample size
avio_wb32(pb, entries); // sample count
- for (i=0; i<track->entry; i++) {
- for (j=0; j<track->cluster[i].entries; j++) {
+ for (i = 0; i < track->entry; i++) {
+ for (j = 0; j < track->cluster[i].entries; j++) {
avio_wb32(pb, track->cluster[i].size /
- track->cluster[i].entries);
+ track->cluster[i].entries);
}
}
}
@@ -177,9 +175,8 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); // version & flags
entryPos = avio_tell(pb);
avio_wb32(pb, track->chunkCount); // entry count
- for (i=0; i<track->entry; i++) {
- if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum)
- {
+ for (i = 0; i < track->entry; i++) {
+ if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
avio_wb32(pb, 0x1); // sample description index
@@ -206,9 +203,9 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
avio_wb32(pb, 0); // version & flags
entryPos = avio_tell(pb);
avio_wb32(pb, track->entry); // entry count
- for (i=0; i<track->entry; i++) {
+ for (i = 0; i < track->entry; i++) {
if (track->cluster[i].flags & flag) {
- avio_wb32(pb, i+1);
+ avio_wb32(pb, i + 1);
index++;
}
}
@@ -268,7 +265,7 @@ static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
put_bits(&pbc, 3, bsmod);
put_bits(&pbc, 3, acmod);
put_bits(&pbc, 1, lfeon);
- put_bits(&pbc, 5, frmsizecod>>1); // bit_rate_code
+ put_bits(&pbc, 5, frmsizecod >> 1); // bit_rate_code
put_bits(&pbc, 5, 0); // reserved
flush_put_bits(&pbc);
@@ -307,8 +304,8 @@ static void put_descr(AVIOContext *pb, int tag, unsigned int size)
{
int i = 3;
avio_w8(pb, tag);
- for(; i>0; i--)
- avio_w8(pb, (size>>(7*i)) | 0x80);
+ for (; i > 0; i--)
+ avio_w8(pb, (size >> (7 * i)) | 0x80);
avio_w8(pb, size & 0x7F);
}
@@ -351,7 +348,7 @@ 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_type == AVMEDIA_TYPE_AUDIO)
avio_w8(pb, 0x15); // flags (= Audiostream)
else
avio_w8(pb, 0x11); // flags (= Visualstream)
@@ -707,7 +704,7 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, 0); /* Reserved */
}
- if(version == 1) { /* SoundDescription V1 extended info */
+ if (version == 1) { /* SoundDescription V1 extended info */
if (mov_pcm_le_gt16(track->enc->codec_id) ||
mov_pcm_be_gt16(track->enc->codec_id))
avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
@@ -718,24 +715,24 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 2); /* Bytes per sample */
}
- if(track->mode == MODE_MOV &&
- (track->enc->codec_id == AV_CODEC_ID_AAC ||
- track->enc->codec_id == AV_CODEC_ID_AC3 ||
- track->enc->codec_id == AV_CODEC_ID_AMR_NB ||
- track->enc->codec_id == AV_CODEC_ID_ALAC ||
- track->enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
- track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
- track->enc->codec_id == AV_CODEC_ID_QDM2 ||
- (mov_pcm_le_gt16(track->enc->codec_id) && version==1) ||
- (mov_pcm_be_gt16(track->enc->codec_id) && version==1)))
+ if (track->mode == MODE_MOV &&
+ (track->enc->codec_id == AV_CODEC_ID_AAC ||
+ track->enc->codec_id == AV_CODEC_ID_AC3 ||
+ track->enc->codec_id == AV_CODEC_ID_AMR_NB ||
+ track->enc->codec_id == AV_CODEC_ID_ALAC ||
+ track->enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
+ track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
+ track->enc->codec_id == AV_CODEC_ID_QDM2 ||
+ (mov_pcm_le_gt16(track->enc->codec_id) && version==1) ||
+ (mov_pcm_be_gt16(track->enc->codec_id) && version==1)))
mov_write_wave_tag(pb, track);
- else if(track->tag == MKTAG('m','p','4','a'))
+ else if (track->tag == MKTAG('m','p','4','a'))
mov_write_esds_tag(pb, track);
- else if(track->enc->codec_id == AV_CODEC_ID_AMR_NB)
+ else if (track->enc->codec_id == AV_CODEC_ID_AMR_NB)
mov_write_amr_tag(pb, track);
- else if(track->enc->codec_id == AV_CODEC_ID_AC3)
+ else if (track->enc->codec_id == AV_CODEC_ID_AC3)
mov_write_ac3_tag(pb, track);
- else if(track->enc->codec_id == AV_CODEC_ID_ALAC)
+ else if (track->enc->codec_id == AV_CODEC_ID_ALAC)
mov_write_extradata_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_WMAPRO)
mov_write_wfex_tag(pb, track);
@@ -796,7 +793,7 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, track->enc->width);
/* values below are based on samples created with quicktime and avid codecs */
if (track->vos_data[5] & 2) { // interlaced
- avio_wb32(pb, track->enc->height/2);
+ avio_wb32(pb, track->enc->height / 2);
avio_wb32(pb, 2); /* unknown */
avio_wb32(pb, 0); /* unknown */
avio_wb32(pb, 4); /* unknown */
@@ -830,18 +827,18 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
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_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');
return tag;
}
static const AVCodecTag codec_ipod_tags[] = {
- { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
- { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
- { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
- { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
- { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
+ { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
+ { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
+ { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
+ { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
+ { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
{ AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
{ AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
{ AV_CODEC_ID_NONE, 0 },
@@ -853,8 +850,8 @@ static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
// keep original tag for subs, ipod supports both formats
if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
- (tag == MKTAG('t','x','3','g') ||
- tag == MKTAG('t','e','x','t'))))
+ (tag == MKTAG('t', 'x', '3', 'g') ||
+ tag == MKTAG('t', 'e', 'x', 't'))))
tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
@@ -871,16 +868,16 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
if (track->enc->width == 720) { /* SD */
if (track->enc->height == 480) { /* NTSC */
if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
- else tag = MKTAG('d','v','c',' ');
+ else tag = MKTAG('d','v','c',' ');
}else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
else if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
- else tag = MKTAG('d','v','p','p');
+ else tag = MKTAG('d','v','p','p');
} else if (track->enc->height == 720) { /* HD 720 line */
- if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q');
- else tag = MKTAG('d','v','h','p');
+ if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q');
+ else tag = MKTAG('d','v','h','p');
} else if (track->enc->height == 1080) { /* HD 1080 line */
- if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5');
- else tag = MKTAG('d','v','h','6');
+ if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5');
+ else tag = MKTAG('d','v','h','6');
} else {
av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
return 0;
@@ -889,6 +886,78 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
return tag;
}
+static AVRational find_fps(AVFormatContext *s, AVStream *st)
+{
+ AVRational rate = {st->codec->time_base.den, st->codec->time_base.num};
+ /* if the codec time base makes no sense, try to fallback on stream frame rate */
+ if (av_timecode_check_frame_rate(rate) < 0) {
+ av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n",
+ rate.num, rate.den, st->avg_frame_rate.num, st->avg_frame_rate.den);
+ rate = st->avg_frame_rate;
+ }
+
+ return rate;
+}
+
+static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
+{
+ int tag = MKTAG('m', '2', 'v', '1'); //fallback tag
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(s, st));
+
+ if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) {
+ if (track->enc->width == 1280 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','4');
+ else if (rate == 25) tag = MKTAG('x','d','v','5');
+ else if (rate == 30) tag = MKTAG('x','d','v','1');
+ else if (rate == 50) tag = MKTAG('x','d','v','a');
+ else if (rate == 60) tag = MKTAG('x','d','v','9');
+ }
+ } else if (track->enc->width == 1440 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','6');
+ else if (rate == 25) tag = MKTAG('x','d','v','7');
+ else if (rate == 30) tag = MKTAG('x','d','v','8');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','v','3');
+ else if (rate == 30) tag = MKTAG('x','d','v','2');
+ }
+ } else if (track->enc->width == 1920 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','d');
+ else if (rate == 25) tag = MKTAG('x','d','v','e');
+ else if (rate == 30) tag = MKTAG('x','d','v','f');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','v','c');
+ else if (rate == 30) tag = MKTAG('x','d','v','b');
+ }
+ }
+ } else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) {
+ if (track->enc->width == 1280 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','5','4');
+ else if (rate == 25) tag = MKTAG('x','d','5','5');
+ else if (rate == 30) tag = MKTAG('x','d','5','1');
+ else if (rate == 50) tag = MKTAG('x','d','5','a');
+ else if (rate == 60) tag = MKTAG('x','d','5','9');
+ }
+ } else if (track->enc->width == 1920 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','5','d');
+ else if (rate == 25) tag = MKTAG('x','d','5','e');
+ else if (rate == 30) tag = MKTAG('x','d','5','f');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','5','c');
+ else if (rate == 30) tag = MKTAG('x','d','5','b');
+ }
+ }
+ }
+
+ return tag;
+}
+
static const struct {
enum AVPixelFormat pix_fmt;
uint32_t tag;
@@ -936,11 +1005,14 @@ static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
(track->enc->codec_id == AV_CODEC_ID_DVVIDEO ||
track->enc->codec_id == AV_CODEC_ID_RAWVIDEO ||
track->enc->codec_id == AV_CODEC_ID_H263 ||
+ track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
if (track->enc->codec_id == AV_CODEC_ID_DVVIDEO)
tag = mov_get_dv_codec_tag(s, track);
else if (track->enc->codec_id == AV_CODEC_ID_RAWVIDEO)
tag = mov_get_rawvideo_codec_tag(s, track);
+ else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->enc->codec_id);
if (!tag) { // if no mac fcc found, try with Microsoft tags
@@ -967,12 +1039,12 @@ static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
}
static const AVCodecTag codec_3gp_tags[] = {
- { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
- { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
- { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
- { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
- { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
- { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
+ { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
+ { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
+ { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
+ { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
+ { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
+ { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
{ AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -981,6 +1053,7 @@ static const AVCodecTag codec_f4v_tags[] = { // XXX: add GIF/PNG/JPEG?
{ AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
{ AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
{ AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
+ { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
{ AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -999,7 +1072,7 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
tag = ipod_get_codec_tag(s, track);
else if (track->mode & MODE_3GP)
tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
- else if (track->mode & MODE_F4V)
+ else if (track->mode == MODE_F4V)
tag = ff_codec_get_tag(codec_f4v_tags, track->enc->codec_id);
else
tag = mov_get_codec_tag(s, track);
@@ -1068,6 +1141,32 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16;
}
+static void find_compressor(char * compressor_name, int len, MOVTrack *track)
+{
+ int xdcam_res = (track->enc->width == 1280 && track->enc->height == 720)
+ || (track->enc->width == 1440 && track->enc->height == 1080)
+ || (track->enc->width == 1920 && track->enc->height == 1080);
+
+ if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name) {
+ av_strlcpy(compressor_name, track->enc->codec->name, 32);
+ } else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(NULL, st));
+ av_strlcatf(compressor_name, len, "XDCAM");
+ if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) {
+ av_strlcatf(compressor_name, len, " HD422");
+ } else if(track->enc->width == 1440) {
+ av_strlcatf(compressor_name, len, " HD");
+ } else
+ av_strlcatf(compressor_name, len, " EX");
+
+ av_strlcatf(compressor_name, len, " %d%c", track->enc->height, interlaced ? 'i' : 'p');
+
+ av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
+ }
+}
+
static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
@@ -1083,7 +1182,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, 0); /* Codec stream revision (=0) */
if (track->mode == MODE_MOV) {
ffio_wfourcc(pb, "FFMP"); /* Vendor */
- if(track->enc->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ if (track->enc->codec_id == AV_CODEC_ID_RAWVIDEO) {
avio_wb32(pb, 0); /* Temporal Quality */
avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
} else {
@@ -1103,8 +1202,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, 1); /* Frame count (= 1) */
/* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
- if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
- av_strlcpy(compressor_name,track->enc->codec->name,32);
+ find_compressor(compressor_name, 32, track);
avio_w8(pb, strlen(compressor_name));
avio_write(pb, compressor_name, 31);
@@ -1113,23 +1211,27 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
else
avio_wb16(pb, 0x18); /* Reserved */
avio_wb16(pb, 0xffff); /* Reserved */
- if(track->tag == MKTAG('m','p','4','v'))
+ if (track->tag == MKTAG('m','p','4','v'))
mov_write_esds_tag(pb, track);
- else if(track->enc->codec_id == AV_CODEC_ID_H263)
+ else if (track->enc->codec_id == AV_CODEC_ID_H263)
mov_write_d263_tag(pb);
- else if(track->enc->codec_id == AV_CODEC_ID_AVUI ||
+ else if (track->enc->codec_id == AV_CODEC_ID_AVUI ||
track->enc->codec_id == AV_CODEC_ID_SVQ3) {
mov_write_extradata_tag(pb, track);
avio_wb32(pb, 0);
- } else if(track->enc->codec_id == AV_CODEC_ID_DNXHD)
+ } 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_H264) {
+ else if (track->enc->codec_id == AV_CODEC_ID_H264) {
mov_write_avcc_tag(pb, track);
- if(track->mode == MODE_IPOD)
+ if (track->mode == MODE_IPOD)
mov_write_uuid_tag_ipod(pb);
} else if (track->enc->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
mov_write_dvc1_tag(pb, track);
- else if (track->vos_len > 0)
+ else if (track->enc->codec_id == AV_CODEC_ID_VP6F ||
+ track->enc->codec_id == AV_CODEC_ID_VP6A) {
+ /* Don't write any potential extradata here - the cropping
+ * is signalled via the normal width/height fields. */
+ } else if (track->vos_len > 0)
mov_write_glbl_tag(pb, track);
if (track->enc->codec_id != AV_CODEC_ID_H264 &&
@@ -1146,9 +1248,30 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
return update_size(pb, pos);
}
+static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
+{
+ int64_t pos = avio_tell(pb);
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "rtp ");
+ avio_wb32(pb, 0); /* Reserved */
+ avio_wb16(pb, 0); /* Reserved */
+ avio_wb16(pb, 1); /* Data-reference index */
+
+ avio_wb16(pb, 1); /* Hint track version */
+ avio_wb16(pb, 1); /* Highest compatible version */
+ avio_wb32(pb, track->max_packet_size); /* Max packet size */
+
+ avio_wb32(pb, 12); /* size */
+ ffio_wfourcc(pb, "tims");
+ avio_wb32(pb, track->timescale);
+
+ return update_size(pb, pos);
+}
+
static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
+#if 1
int frame_duration = av_rescale(track->timescale, track->enc->time_base.num, track->enc->time_base.den);
int nb_frames = 1.0/av_q2d(track->enc->time_base) + 0.5;
@@ -1168,26 +1291,15 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
avio_w8(pb, nb_frames); /* Number of frames */
avio_wb24(pb, 0); /* Reserved */
/* TODO: source reference string */
- return update_size(pb, pos);
-}
+#else
-static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
-{
- int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
- ffio_wfourcc(pb, "rtp ");
- avio_wb32(pb, 0); /* Reserved */
- avio_wb16(pb, 0); /* Reserved */
- avio_wb16(pb, 1); /* Data-reference index */
-
- avio_wb16(pb, 1); /* Hint track version */
- avio_wb16(pb, 1); /* Highest compatible version */
- avio_wb32(pb, track->max_packet_size); /* Max packet size */
-
- avio_wb32(pb, 12); /* size */
- ffio_wfourcc(pb, "tims");
- avio_wb32(pb, track->timescale);
-
+ ffio_wfourcc(pb, "tmcd"); /* Data format */
+ avio_wb32(pb, 0); /* Reserved */
+ avio_wb32(pb, 1); /* Data reference index */
+ if (track->enc->extradata_size)
+ avio_write(pb, track->enc->extradata, track->enc->extradata_size);
+#endif
return update_size(pb, pos);
}
@@ -1221,7 +1333,7 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track)
ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
ctts_entries[0].count = 1;
ctts_entries[0].duration = track->cluster[0].cts;
- for (i=1; i<track->entry; i++) {
+ for (i = 1; i < track->entry; i++) {
if (track->cluster[i].cts == ctts_entries[entries].duration) {
ctts_entries[entries].count++; /* compress */
} else {
@@ -1236,7 +1348,7 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "ctts");
avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, entries); /* entry count */
- for (i=0; i<entries; i++) {
+ for (i = 0; i < entries; i++) {
avio_wb32(pb, ctts_entries[i].count);
avio_wb32(pb, ctts_entries[i].duration);
}
@@ -1261,7 +1373,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
stts_entries = track->entry ?
av_malloc(track->entry * sizeof(*stts_entries)) : /* worst case */
NULL;
- for (i=0; i<track->entry; i++) {
+ for (i = 0; i < track->entry; i++) {
int duration = get_cluster_duration(track, i);
if (i && duration == stts_entries[entries].duration) {
stts_entries[entries].count++; /* compress */
@@ -1278,7 +1390,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "stts");
avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, entries); /* entry count */
- for (i=0; i<entries; i++) {
+ for (i = 0; i < entries; i++) {
avio_wb32(pb, stts_entries[i].count);
avio_wb32(pb, stts_entries[i].duration);
}
@@ -1432,18 +1544,18 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
const char *hdlr, *descr = NULL, *hdlr_type = NULL;
int64_t pos = avio_tell(pb);
- if (!track) { /* no media --> data handler */
- hdlr = "dhlr";
- hdlr_type = "url ";
- descr = "DataHandler";
- } else {
+ hdlr = "dhlr";
+ hdlr_type = "url ";
+ descr = "DataHandler";
+
+ if (track) {
hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
hdlr_type = "vide";
- descr = "VideoHandler";
+ descr = "VideoHandler";
} else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
hdlr_type = "soun";
- descr = "SoundHandler";
+ descr = "SoundHandler";
} else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (track->tag == MKTAG('c','6','0','8')) {
hdlr_type = "clcp";
@@ -1453,16 +1565,20 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
else hdlr_type = "text";
descr = "SubtitleHandler";
}
+ } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
+ hdlr_type = "hint";
+ descr = "HintHandler";
} else if (track->enc->codec_tag == MKTAG('t','m','c','d')) {
hdlr_type = "tmcd";
descr = "TimeCodeHandler";
- } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
- hdlr_type = "hint";
- descr = "HintHandler";
} else {
- hdlr = "dhlr";
- hdlr_type = "url ";
- descr = "DataHandler";
+ char tag_buf[32];
+ av_get_codec_tag_string(tag_buf, sizeof(tag_buf),
+ track->enc->codec_tag);
+
+ av_log(track->enc, AV_LOG_WARNING,
+ "Unknown hldr_type for %s / 0x%04X, writing dummy values\n",
+ tag_buf, track->enc->codec_tag);
}
}
@@ -1471,9 +1587,9 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); /* Version & flags */
avio_write(pb, hdlr, 4); /* handler */
ffio_wfourcc(pb, hdlr_type); /* handler type */
- avio_wb32(pb ,0); /* reserved */
- avio_wb32(pb ,0); /* reserved */
- avio_wb32(pb ,0); /* reserved */
+ avio_wb32(pb, 0); /* reserved */
+ avio_wb32(pb, 0); /* reserved */
+ avio_wb32(pb, 0); /* reserved */
if (!track || track->mode == MODE_MOV)
avio_w8(pb, strlen(descr)); /* pascal string */
avio_write(pb, descr, strlen(descr)); /* handler description */
@@ -1502,7 +1618,7 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "minf");
- if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
+ if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
mov_write_vmhd_tag(pb);
else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
mov_write_smhd_tag(pb);
@@ -1512,10 +1628,10 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
} else {
mov_write_nmhd_tag(pb);
}
- } else if (track->tag == MKTAG('t','m','c','d')) {
- mov_write_gmhd_tag(pb, track);
} else if (track->tag == MKTAG('r','t','p',' ')) {
mov_write_hmhd_tag(pb);
+ } else if (track->tag == MKTAG('t','m','c','d')) {
+ mov_write_gmhd_tag(pb, track);
}
if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
mov_write_hdlr_tag(pb, NULL);
@@ -1550,11 +1666,11 @@ static int mov_write_mdhd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, track->language); /* language */
avio_wb16(pb, 0); /* reserved (quality) */
- if(version!=0 && track->mode == MODE_MOV){
+ if (version != 0 && track->mode == MODE_MOV) {
av_log(NULL, AV_LOG_ERROR,
- "FATAL error, file duration too long for timebase, this file will not be\n"
- "playable with quicktime. Choose a different timebase or a different\n"
- "container format\n");
+ "FATAL error, file duration too long for timebase, this file will not be\n"
+ "playable with quicktime. Choose a different timebase or a different\n"
+ "container format\n");
}
return 32;
@@ -1602,7 +1718,9 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
(version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
ffio_wfourcc(pb, "tkhd");
avio_w8(pb, version);
- avio_wb24(pb, track->secondary ? 0x2 : 0xf); /* flags (first track enabled) */
+ avio_wb24(pb, (track->flags & MOV_TRACK_ENABLED) ?
+ MOV_TKHD_FLAG_ENABLED | MOV_TKHD_FLAG_IN_MOVIE :
+ MOV_TKHD_FLAG_IN_MOVIE);
if (version == 1) {
avio_wb64(pb, track->time);
avio_wb64(pb, track->time);
@@ -1622,7 +1740,7 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
avio_wb16(pb, 0); /* layer */
avio_wb16(pb, st ? st->codec->codec_type : 0); /* alternate group) */
/* Volume, only for audio */
- if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
+ if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
avio_wb16(pb, 0x0100);
else
avio_wb16(pb, 0);
@@ -1643,20 +1761,19 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st)
write_matrix(pb, 1, 0, 0, 1, 0, 0);
}
/* Track width and height, for visual only */
- if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
- track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
- if(track->mode == MODE_MOV) {
+ if (st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
+ track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
+ if (track->mode == MODE_MOV) {
avio_wb32(pb, track->enc->width << 16);
avio_wb32(pb, track->height << 16);
} else {
double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
- if(!sample_aspect_ratio || track->height != track->enc->height)
+ if (!sample_aspect_ratio || track->height != track->enc->height)
sample_aspect_ratio = 1;
- avio_wb32(pb, sample_aspect_ratio * track->enc->width*0x10000);
- avio_wb32(pb, track->height*0x10000);
+ avio_wb32(pb, sample_aspect_ratio * track->enc->width * 0x10000);
+ avio_wb32(pb, track->height * 0x10000);
}
- }
- else {
+ } else {
avio_wb32(pb, 0);
avio_wb32(pb, 0);
}
@@ -1777,7 +1894,6 @@ static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
{
-
AVFormatContext *ctx = track->rtp_ctx;
char buf[1000] = "";
int len;
@@ -1810,14 +1926,14 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_tref_tag(pb, track);
mov_write_mdia_tag(pb, track);
if (track->mode == MODE_PSP)
- mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box
+ 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)
mov_write_tapt_tag(pb, track);
- };
+ }
return update_size(pb, pos);
}
@@ -1828,7 +1944,7 @@ static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
int audio_profile = mov->iods_audio_profile;
int video_profile = mov->iods_video_profile;
for (i = 0; i < mov->nb_streams; i++) {
- if(mov->tracks[i].entry > 0) {
+ if (mov->tracks[i].entry > 0) {
has_audio |= mov->tracks[i].enc->codec_type == AVMEDIA_TYPE_AUDIO;
has_video |= mov->tracks[i].enc->codec_type == AVMEDIA_TYPE_VIDEO;
}
@@ -1880,8 +1996,8 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
int64_t max_track_len_temp, max_track_len = 0;
int version;
- for (i=0; i<mov->nb_streams; i++) {
- if(mov->tracks[i].entry > 0) {
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
max_track_len_temp = av_rescale_rnd(mov->tracks[i].track_duration,
MOV_TIMESCALE,
mov->tracks[i].timescale,
@@ -1945,7 +2061,7 @@ static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
/* helper function to write a data tag with the specified string as data */
static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
{
- if(long_style){
+ if (long_style) {
int size = 16 + strlen(data);
avio_wb32(pb, size); /* size */
ffio_wfourcc(pb, "data");
@@ -1953,7 +2069,7 @@ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang
avio_wb32(pb, 0);
avio_write(pb, data, strlen(data));
return size;
- }else{
+ } else {
if (!lang)
lang = ff_mov_iso639_to_lang("und", 1);
avio_wb16(pb, strlen(data)); /* string length */
@@ -1963,7 +2079,9 @@ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang
}
}
-static int mov_write_string_tag(AVIOContext *pb, const char *name, const char *value, int lang, int long_style){
+static int mov_write_string_tag(AVIOContext *pb, const char *name,
+ const char *value, int lang, int long_style)
+{
int size = 0;
if (value && value[0]) {
int64_t pos = avio_tell(pb);
@@ -1990,8 +2108,8 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
snprintf(tag2, sizeof(tag2), "%s-", tag);
while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
len2 = strlen(t2->key);
- if (len2 == len+4 && !strcmp(t->value, t2->value)
- && (l=ff_mov_iso639_to_lang(&t2->key[len2-3], 1)) >= 0) {
+ if (len2 == len + 4 && !strcmp(t->value, t2->value)
+ && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
lang = l;
break;
}
@@ -2017,23 +2135,29 @@ static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
return size;
}
-/* iTunes track number */
+/* iTunes track or disc number */
static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
- AVFormatContext *s)
+ AVFormatContext *s, int disc)
{
- AVDictionaryEntry *t = av_dict_get(s->metadata, "track", NULL, 0);
+ AVDictionaryEntry *t = av_dict_get(s->metadata,
+ disc ? "disc" : "track",
+ NULL, 0);
int size = 0, track = t ? atoi(t->value) : 0;
if (track) {
+ int tracks = 0;
+ char *slash = strchr(t->value, '/');
+ if (slash)
+ tracks = atoi(slash + 1);
avio_wb32(pb, 32); /* size */
- ffio_wfourcc(pb, "trkn");
- avio_wb32(pb, 24); /* size */
- ffio_wfourcc(pb, "data");
- avio_wb32(pb, 0); // 8 bytes empty
- avio_wb32(pb, 0);
- avio_wb16(pb, 0); // empty
- avio_wb16(pb, track); // track number
- avio_wb16(pb, 0); // total track number
- avio_wb16(pb, 0); // empty
+ ffio_wfourcc(pb, disc ? "disk" : "trkn");
+ avio_wb32(pb, 24); /* size */
+ ffio_wfourcc(pb, "data");
+ avio_wb32(pb, 0); // 8 bytes empty
+ avio_wb32(pb, 0);
+ avio_wb16(pb, 0); // empty
+ avio_wb16(pb, track); // track / disc number
+ avio_wb16(pb, tracks); // total track / disc number
+ avio_wb16(pb, 0); // empty
size = 32;
}
return size;
@@ -2045,16 +2169,25 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
{
AVDictionaryEntry *t = NULL;
uint8_t num;
+ int size = 24 + len;
+
+ if (len != 1 && len != 4)
+ return -1;
if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
return 0;
num = atoi(t->value);
- avio_wb32(pb, len+8);
+ avio_wb32(pb, size);
ffio_wfourcc(pb, name);
+ avio_wb32(pb, size - 8);
+ ffio_wfourcc(pb, "data");
+ avio_wb32(pb, 0x15);
+ avio_wb32(pb, 0);
if (len==4) avio_wb32(pb, num);
else avio_w8 (pb, num);
- return len+8;
+
+ return size;
}
/* iTunes meta data list */
@@ -2086,7 +2219,8 @@ 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_trkn_tag(pb, mov, s);
+ 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);
return update_size(pb, pos);
}
@@ -2108,9 +2242,9 @@ static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
static int utf8len(const uint8_t *b)
{
- int len=0;
+ int len = 0;
int val;
- while(*b){
+ while (*b) {
GET_UTF8(val, *b++, return -1;)
len++;
}
@@ -2120,7 +2254,7 @@ static int utf8len(const uint8_t *b)
static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
{
int val;
- while(*b){
+ while (*b) {
GET_UTF8(val, *b++, return -1;)
avio_wb16(pb, val);
}
@@ -2130,7 +2264,9 @@ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
static uint16_t language_code(const char *str)
{
- return (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F);
+ return (((str[0] - 0x60) & 0x1F) << 10) +
+ (((str[1] - 0x60) & 0x1F) << 5) +
+ (( str[2] - 0x60) & 0x1F);
}
static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
@@ -2147,7 +2283,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
avio_wb16(pb, atoi(t->value));
else {
avio_wb16(pb, language_code("eng")); /* language */
- avio_write(pb, t->value, strlen(t->value)+1); /* UTF8 string value */
+ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
if (!strcmp(tag, "albm") &&
(t = av_dict_get(s->metadata, "track", NULL, 0)))
avio_w8(pb, atoi(t->value));
@@ -2194,7 +2330,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
}
ret = avio_open_dyn_buf(&pb_buf);
- if(ret < 0)
+ if (ret < 0)
return ret;
if (mov->mode & MODE_3GP) {
@@ -2207,18 +2343,18 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
} else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
- mov_write_string_metadata(s, pb_buf, "\251ART", "artist" , 0);
- mov_write_string_metadata(s, pb_buf, "\251nam", "title" , 0);
- mov_write_string_metadata(s, pb_buf, "\251aut", "author" , 0);
- mov_write_string_metadata(s, pb_buf, "\251alb", "album" , 0);
- mov_write_string_metadata(s, pb_buf, "\251day", "date" , 0);
- mov_write_string_metadata(s, pb_buf, "\251swr", "encoder" , 0);
+ mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
+ mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
+ mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
+ mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
+ mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
+ mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
// currently ignored by mov.c
- mov_write_string_metadata(s, pb_buf, "\251des", "comment" , 0);
+ mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
// add support for libquicktime, this atom is also actually read by mov.c
- mov_write_string_metadata(s, pb_buf, "\251cmt", "comment" , 0);
- mov_write_string_metadata(s, pb_buf, "\251gen", "genre" , 0);
- mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright" , 0);
+ mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
+ mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
+ mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
} else {
/* iTunes meta data */
mov_write_meta_tag(pb_buf, mov, s);
@@ -2228,7 +2364,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_chpl_tag(pb_buf, s);
if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) {
- avio_wb32(pb, size+8);
+ avio_wb32(pb, size + 8);
ffio_wfourcc(pb, "udta");
avio_write(pb, buf, size);
}
@@ -2238,12 +2374,12 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
}
static void mov_write_psp_udta_tag(AVIOContext *pb,
- const char *str, const char *lang, int type)
+ const char *str, const char *lang, int type)
{
- int len = utf8len(str)+1;
- if(len<=0)
+ int len = utf8len(str) + 1;
+ if (len <= 0)
return;
- avio_wb16(pb, len*2+10); /* size */
+ avio_wb16(pb, len * 2 + 10); /* size */
avio_wb32(pb, type); /* type */
avio_wb16(pb, language_code(lang)); /* language */
avio_wb16(pb, 0x01); /* ? */
@@ -2290,18 +2426,18 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
static void build_chunks(MOVTrack *trk)
{
int i;
- MOVIentry *chunk= &trk->cluster[0];
+ MOVIentry *chunk = &trk->cluster[0];
uint64_t chunkSize = chunk->size;
- chunk->chunkNum= 1;
+ chunk->chunkNum = 1;
if (trk->chunkCount)
return;
- trk->chunkCount= 1;
- for(i=1; i<trk->entry; i++){
- if(chunk->pos + chunkSize == trk->cluster[i].pos &&
+ trk->chunkCount = 1;
+ for (i = 1; i<trk->entry; i++){
+ if (chunk->pos + chunkSize == trk->cluster[i].pos &&
chunkSize + trk->cluster[i].size < (1<<20)){
chunkSize += trk->cluster[i].size;
chunk->samples_in_chunk += trk->cluster[i].entries;
- }else{
+ } else {
trk->cluster[i].chunkNum = chunk->chunkNum+1;
chunk=&trk->cluster[i];
chunkSize = chunk->size;
@@ -2315,25 +2451,24 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
{
int i;
int64_t pos = avio_tell(pb);
- int not_first[AVMEDIA_TYPE_NB]={0};
avio_wb32(pb, 0); /* size placeholder*/
ffio_wfourcc(pb, "moov");
- for (i=0; i<mov->nb_streams; i++) {
+ for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
continue;
- mov->tracks[i].time = mov->time;
- mov->tracks[i].track_id = i+1;
+ mov->tracks[i].time = mov->time;
+ mov->tracks[i].track_id = i + 1;
if (mov->tracks[i].entry)
build_chunks(&mov->tracks[i]);
}
if (mov->chapter_track)
- for (i=0; i<s->nb_streams; i++) {
+ for (i = 0; i < s->nb_streams; i++) {
mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
- mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
+ mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
}
for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) {
@@ -2354,15 +2489,8 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_mvhd_tag(pb, mov);
if (mov->mode != MODE_MOV && !mov->iods_skip)
mov_write_iods_tag(pb, mov);
- for (i=0; i<mov->nb_streams; i++) {
+ for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT) {
- if(i < s->nb_streams){
- int codec_type= s->streams[i]->codec->codec_type;
- if(codec_type==AVMEDIA_TYPE_AUDIO || codec_type==AVMEDIA_TYPE_SUBTITLE){
- mov->tracks[i].secondary= not_first[codec_type];
- not_first[codec_type]= 1;
- }
- }
mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
}
}
@@ -2390,9 +2518,9 @@ static void param_write_string(AVIOContext *pb, const char *name, const char *va
static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
{
char buf[150];
- len = FFMIN(sizeof(buf)/2 - 1, len);
+ len = FFMIN(sizeof(buf) / 2 - 1, len);
ff_data_to_hex(buf, value, len, 0);
- buf[2*len] = '\0';
+ buf[2 * len] = '\0';
avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
}
@@ -2400,7 +2528,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
{
int64_t pos = avio_tell(pb);
int i;
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
};
@@ -2466,7 +2594,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
param_write_hex(pb, "CodecPrivateData", track->enc->extradata,
track->enc->extradata_size);
param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
- track->enc->codec_id));
+ track->enc->codec_id));
param_write_int(pb, "Channels", track->enc->channels);
param_write_int(pb, "SamplingRate", track->enc->sample_rate);
param_write_int(pb, "BitsPerSample", 16);
@@ -2491,8 +2619,8 @@ static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
return 0;
}
-static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track,
- int64_t moof_offset)
+static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
+ MOVTrack *track, int64_t moof_offset)
{
int64_t pos = avio_tell(pb);
uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
@@ -2502,12 +2630,16 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track,
} else {
flags |= MOV_TFHD_DEFAULT_FLAGS;
}
+ if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
+ flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
/* Don't set a default sample size, the silverlight player refuses
* to play files with that set. Don't set a default sample duration,
- * WMP freaks out if it is set. */
+ * WMP freaks out if it is set. Don't set a base data offset, PIFF
+ * file format says it MUST NOT be set. */
if (track->mode == MODE_ISM)
- flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION);
+ flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
+ MOV_TFHD_BASE_DATA_OFFSET);
avio_wb32(pb, 0); /* size placeholder */
ffio_wfourcc(pb, "tfhd");
@@ -2544,7 +2676,8 @@ static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
(MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
}
-static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
+ MOVTrack *track, int moof_size)
{
int64_t pos = avio_tell(pb);
uint32_t flags = MOV_TRUN_DATA_OFFSET;
@@ -2569,8 +2702,13 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
avio_wb24(pb, flags);
avio_wb32(pb, track->entry); /* sample count */
- track->moof_size_offset = avio_tell(pb);
- avio_wb32(pb, 0); /* data offset */
+ if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
+ !(mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) &&
+ track->track_id != 1)
+ avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
+ else
+ avio_wb32(pb, moof_size + 8 + track->data_offset +
+ track->cluster[0].pos); /* data offset */
if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
avio_wb32(pb, get_sample_flags(track, &track->cluster[0]));
@@ -2591,7 +2729,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
};
@@ -2613,7 +2751,7 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
{
int n = track->nb_frag_info - 1 - entry, i;
int size = 8 + 16 + 4 + 1 + 16*n;
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
};
@@ -2634,11 +2772,10 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb64(pb, track->frag_info[index].duration);
}
if (n < mov->ism_lookahead) {
- int free_size = 16*(mov->ism_lookahead - n);
+ int free_size = 16 * (mov->ism_lookahead - n);
avio_wb32(pb, free_size);
ffio_wfourcc(pb, "free");
- for (i = 0; i < free_size - 8; i++)
- avio_w8(pb, 0);
+ ffio_fill(pb, 0, free_size - 8);
}
return 0;
@@ -2659,19 +2796,20 @@ static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
}
static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
- MOVTrack *track, int64_t moof_offset)
+ MOVTrack *track, int64_t moof_offset,
+ int moof_size)
{
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size placeholder */
ffio_wfourcc(pb, "traf");
- mov_write_tfhd_tag(pb, track, moof_offset);
- mov_write_trun_tag(pb, track);
+ mov_write_tfhd_tag(pb, mov, track, moof_offset);
+ mov_write_trun_tag(pb, mov, track, moof_size);
if (mov->mode == MODE_ISM) {
mov_write_tfxd_tag(pb, track);
if (mov->ism_lookahead) {
- int i, size = 16 + 4 + 1 + 16*mov->ism_lookahead;
+ int i, size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
track->tfrf_offset = avio_tell(pb);
avio_wb32(pb, 8 + size);
@@ -2684,10 +2822,11 @@ static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
return update_size(pb, pos);
}
-static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
+static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
+ int tracks, int moof_size)
{
- int64_t pos = avio_tell(pb), end;
- int i, moof_size;
+ int64_t pos = avio_tell(pb);
+ int i;
avio_wb32(pb, 0); /* size placeholder */
ffio_wfourcc(pb, "moof");
@@ -2699,25 +2838,24 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
continue;
if (!track->entry)
continue;
- mov_write_traf_tag(pb, mov, track, pos);
+ mov_write_traf_tag(pb, mov, track, pos, moof_size);
}
- end = avio_tell(pb);
- moof_size = end - pos;
- for (i = 0; i < mov->nb_streams; i++) {
- MOVTrack *track = &mov->tracks[i];
- if (tracks >= 0 && i != tracks)
- continue;
- if (!track->entry)
- continue;
- avio_seek(pb, mov->tracks[i].moof_size_offset, SEEK_SET);
- avio_wb32(pb, moof_size + 8 + mov->tracks[i].data_offset);
- }
- avio_seek(pb, end, SEEK_SET);
-
return update_size(pb, pos);
}
+static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
+{
+ AVIOContext *avio_buf;
+ int ret, moof_size;
+
+ if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
+ return ret;
+ mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
+ moof_size = ffio_close_null_buf(avio_buf);
+ return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
+}
+
static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
@@ -2805,7 +2943,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
} else if (mov->mode & MODE_3G2) {
ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
minor = has_h264 ? 0x20000 : 0x10000;
- }else if (mov->mode == MODE_PSP)
+ } else if (mov->mode == MODE_PSP)
ffio_wfourcc(pb, "MSNV");
else if (mov->mode == MODE_MP4)
ffio_wfourcc(pb, "isom");
@@ -2820,7 +2958,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
avio_wb32(pb, minor);
- if(mov->mode == MODE_MOV)
+ if (mov->mode == MODE_MOV)
ffio_wfourcc(pb, "qt ");
else if (mov->mode == MODE_ISM) {
ffio_wfourcc(pb, "piff");
@@ -2828,7 +2966,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
} else {
ffio_wfourcc(pb, "isom");
ffio_wfourcc(pb, "iso2");
- if(has_h264)
+ if (has_h264)
ffio_wfourcc(pb, "avc1");
}
@@ -2848,7 +2986,7 @@ static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
AVCodecContext *video_codec = s->streams[0]->codec;
AVCodecContext *audio_codec = s->streams[1]->codec;
int audio_rate = audio_codec->sample_rate;
- int frame_rate = ((video_codec->time_base.den) * (0x10000))/ (video_codec->time_base.num);
+ int frame_rate = ((video_codec->time_base.den) * (0x10000)) / (video_codec->time_base.num);
int audio_kbitrate = audio_codec->bit_rate / 1000;
int video_kbitrate = FFMIN(video_codec->bit_rate / 1000, 800 - audio_kbitrate);
@@ -2870,7 +3008,7 @@ static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
avio_wb32(pb, 0x0); /* ? */
avio_wb32(pb, 0x2c); /* size */
- ffio_wfourcc(pb, "APRF");/* audio */
+ ffio_wfourcc(pb, "APRF"); /* audio */
avio_wb32(pb, 0x0);
avio_wb32(pb, 0x2); /* TrackID */
ffio_wfourcc(pb, "mp4a");
@@ -2910,11 +3048,11 @@ static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
int i, closed_gop = 0;
for (i = 0; i < pkt->size - 4; i++) {
- c = (c<<8) + pkt->data[i];
+ c = (c << 8) + pkt->data[i];
if (c == 0x1b8) { // gop
- closed_gop = pkt->data[i+4]>>6 & 0x01;
+ closed_gop = pkt->data[i + 4] >> 6 & 0x01;
} else if (c == 0x100) { // pic
- int temp_ref = (pkt->data[i+1]<<2) | (pkt->data[i+2]>>6);
+ int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
if (!temp_ref || closed_gop) // I picture is not reordered
*flags = MOV_SYNC_SAMPLE;
else
@@ -2982,21 +3120,6 @@ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk, int fragment)
}
}
-static int get_moov_size(AVFormatContext *s)
-{
- int ret;
- uint8_t *buf;
- AVIOContext *moov_buf;
- MOVMuxContext *mov = s->priv_data;
-
- if ((ret = avio_open_dyn_buf(&moov_buf)) < 0)
- return ret;
- mov_write_moov_tag(moov_buf, mov, s);
- ret = avio_close_dyn_buf(moov_buf, &buf);
- av_free(buf);
- return ret;
-}
-
static int mov_flush_fragment(AVFormatContext *s)
{
MOVMuxContext *mov = s->priv_data;
@@ -3082,9 +3205,14 @@ static int mov_flush_fragment(AVFormatContext *s)
MOVFragmentInfo *info;
avio_flush(s->pb);
track->nb_frag_info++;
- track->frag_info = av_realloc(track->frag_info,
- sizeof(*track->frag_info) *
- track->nb_frag_info);
+ if (track->nb_frag_info >= track->frag_info_capacity) {
+ unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
+ if (av_reallocp_array(&track->frag_info,
+ new_capacity,
+ sizeof(*track->frag_info)))
+ return AVERROR(ENOMEM);
+ track->frag_info_capacity = new_capacity;
+ }
info = &track->frag_info[track->nb_frag_info - 1];
info->offset = avio_tell(s->pb);
info->time = mov->tracks[i].frag_start;
@@ -3124,7 +3252,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
MOVTrack *trk = &mov->tracks[pkt->stream_index];
AVCodecContext *enc = trk->enc;
unsigned int samples_in_chunk = 0;
- int size= pkt->size;
+ int size = pkt->size;
uint8_t *reformatted_data = NULL;
if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
@@ -3168,11 +3296,21 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
/* copy extradata if it exists */
if (trk->vos_len == 0 && enc->extradata_size > 0) {
- trk->vos_len = enc->extradata_size;
+ trk->vos_len = enc->extradata_size;
trk->vos_data = av_malloc(trk->vos_len);
memcpy(trk->vos_data, enc->extradata, trk->vos_len);
}
+ if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
+ (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
+ if (!s->streams[pkt->stream_index]->nb_frames) {
+ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
+ "use audio bitstream filter 'aac_adtstoasc' to fix it "
+ "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
+ return -1;
+ }
+ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
+ }
if (enc->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1) {
/* from x264 or from bytestream h264 */
/* nal reformating needed */
@@ -3183,10 +3321,6 @@ 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_AAC && pkt->size > 2 &&
- (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
- av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n");
- return -1;
} else {
avio_write(pb, pkt->data, size);
}
@@ -3194,25 +3328,27 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
if ((enc->codec_id == AV_CODEC_ID_DNXHD ||
enc->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len) {
/* copy frame to create needed atoms */
- trk->vos_len = size;
+ trk->vos_len = size;
trk->vos_data = av_malloc(size);
if (!trk->vos_data)
return AVERROR(ENOMEM);
memcpy(trk->vos_data, pkt->data, size);
}
- if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
- trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE));
- if (!trk->cluster)
- return -1;
+ if (trk->entry >= trk->cluster_capacity) {
+ unsigned new_capacity = 2 * (trk->entry + MOV_INDEX_CLUSTER_SIZE);
+ if (av_reallocp_array(&trk->cluster, new_capacity,
+ sizeof(*trk->cluster)))
+ return AVERROR(ENOMEM);
+ trk->cluster_capacity = new_capacity;
}
- trk->cluster[trk->entry].pos = avio_tell(pb) - size;
+ trk->cluster[trk->entry].pos = avio_tell(pb) - size;
trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
- trk->cluster[trk->entry].chunkNum = 0;
- trk->cluster[trk->entry].size = size;
- trk->cluster[trk->entry].entries = samples_in_chunk;
- trk->cluster[trk->entry].dts = pkt->dts;
+ trk->cluster[trk->entry].chunkNum = 0;
+ trk->cluster[trk->entry].size = size;
+ trk->cluster[trk->entry].entries = samples_in_chunk;
+ trk->cluster[trk->entry].dts = pkt->dts;
if (!trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
/* First packet of a new fragment. We already wrote the duration
* of the last packet of the previous fragment based on track_duration,
@@ -3234,7 +3370,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
}
if (pkt->dts != pkt->pts)
trk->flags |= MOV_TRACK_CTTS;
- trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
+ trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
trk->cluster[trk->entry].flags = 0;
if (enc->codec_id == AV_CODEC_ID_VC1) {
mov_parse_vc1_frame(pkt, trk, mov->fragments);
@@ -3252,9 +3388,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
}
trk->entry++;
trk->sample_count += samples_in_chunk;
- mov->mdat_size += size;
-
- avio_flush(pb);
+ mov->mdat_size += size;
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams)
ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
@@ -3271,7 +3405,8 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
int64_t frag_duration = 0;
int size = pkt->size;
- if (!pkt->size) return 0; /* Discard 0 sized packets */
+ if (!pkt->size)
+ return 0; /* Discard 0 sized packets */
if (trk->entry && pkt->stream_index < s->nb_streams)
frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
@@ -3360,7 +3495,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
// QuickTime chapters involve an additional text track with the chapter names
// as samples, and a tref pointing from the other tracks to the chapter one.
-static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
+static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
{
AVIOContext *pb;
@@ -3373,8 +3508,16 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
track->tag = MKTAG('t','e','x','t');
track->timescale = MOV_TIMESCALE;
track->enc = avcodec_alloc_context3(NULL);
+ if (!track->enc)
+ return AVERROR(ENOMEM);
track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
-
+#if 0
+ // These properties are required to make QT recognize the chapter track
+ uint8_t chapter_properties[43] = { 0, 0, 0, 0, 0, 0, 0, 1, };
+ if (ff_alloc_extradata(track->enc, sizeof(chapter_properties)))
+ return AVERROR(ENOMEM);
+ memcpy(track->enc->extradata, chapter_properties, sizeof(chapter_properties));
+#else
if (avio_open_dyn_buf(&pb) >= 0) {
int size;
uint8_t *buf;
@@ -3418,6 +3561,7 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
av_free(&buf);
}
}
+#endif
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *c = s->chapters[i];
@@ -3428,15 +3572,19 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
pkt.duration = end - pkt.dts;
if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
- len = strlen(t->value);
- pkt.size = len+2;
+ len = strlen(t->value);
+ pkt.size = len + 2;
pkt.data = av_malloc(pkt.size);
+ if (!pkt.data)
+ return AVERROR(ENOMEM);
AV_WB16(pkt.data, len);
- memcpy(pkt.data+2, t->value, len);
+ memcpy(pkt.data + 2, t->value, len);
ff_mov_write_packet(s, &pkt);
av_freep(&pkt.data);
}
}
+
+ return 0;
}
static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, const char *tcstr)
@@ -3447,14 +3595,7 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde
AVStream *src_st = s->streams[src_index];
AVTimecode tc;
AVPacket pkt = {.stream_index = index, .flags = AV_PKT_FLAG_KEY, .size = 4};
- AVRational rate = {src_st->codec->time_base.den, src_st->codec->time_base.num};
-
- /* if the codec time base makes no sense, try to fallback on stream frame rate */
- if (av_timecode_check_frame_rate(rate) < 0) {
- av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n",
- rate.num, rate.den, src_st->avg_frame_rate.num, src_st->avg_frame_rate.den);
- rate = src_st->avg_frame_rate;
- }
+ AVRational rate = find_fps(s, src_st);
/* compute the frame number */
ret = av_timecode_init_from_string(&tc, rate, tcstr, s);
@@ -3473,7 +3614,7 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde
track->enc = avcodec_alloc_context3(NULL);
track->enc->codec_type = AVMEDIA_TYPE_DATA;
track->enc->codec_tag = track->tag;
- track->enc->time_base = src_st->codec->time_base;
+ track->enc->time_base = av_inv_q(rate);
/* the tmcd track just contains one packet with the frame number */
pkt.data = av_malloc(pkt.size);
@@ -3483,12 +3624,101 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde
return ret;
}
+/*
+ * st->disposition controls the "enabled" flag in the tkhd tag.
+ * QuickTime will not play a track if it is not enabled. So make sure
+ * that one track of each type (audio, video, subtitle) is enabled.
+ *
+ * Subtitles are special. For audio and video, setting "enabled" also
+ * makes the track "default" (i.e. it is rendered when played). For
+ * subtitles, an "enabled" subtitle is not rendered by default, but
+ * if no subtitle is enabled, the subtitle menu in QuickTime will be
+ * empty!
+ */
+static void enable_tracks(AVFormatContext *s)
+{
+ MOVMuxContext *mov = s->priv_data;
+ int i;
+ uint8_t enabled[AVMEDIA_TYPE_NB];
+ int first[AVMEDIA_TYPE_NB];
+
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
+ enabled[i] = 0;
+ first[i] = -1;
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+
+ if (st->codec->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
+ st->codec->codec_type >= AVMEDIA_TYPE_NB)
+ continue;
+
+ if (first[st->codec->codec_type] < 0)
+ first[st->codec->codec_type] = i;
+ if (st->disposition & AV_DISPOSITION_DEFAULT) {
+ mov->tracks[i].flags |= MOV_TRACK_ENABLED;
+ enabled[st->codec->codec_type] = 1;
+ }
+ }
+
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
+ switch (i) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (!enabled[i] && first[i] >= 0)
+ mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
+ break;
+ }
+ }
+}
+
+static void mov_free(AVFormatContext *s)
+{
+ MOVMuxContext *mov = s->priv_data;
+ int i;
+
+ if (mov->chapter_track) {
+ if (mov->tracks[mov->chapter_track].enc)
+ av_freep(&mov->tracks[mov->chapter_track].enc->extradata);
+ av_freep(&mov->tracks[mov->chapter_track].enc);
+ }
+
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].tag == MKTAG('r','t','p',' '))
+ ff_mov_close_hinting(&mov->tracks[i]);
+ else if (mov->tracks[i].tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
+ av_freep(&mov->tracks[i].enc);
+ av_freep(&mov->tracks[i].cluster);
+ av_freep(&mov->tracks[i].frag_info);
+
+ if (mov->tracks[i].vos_len)
+ av_freep(&mov->tracks[i].vos_data);
+ }
+
+ av_freep(&mov->tracks);
+}
+
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;
+
+ if (s->oformat != NULL) {
+ if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
+ else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2;
+ else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
+ else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
+ else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD;
+ else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM;
+ else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V;
+ }
/* Set the FRAGMENT flag if any of the fragmentation methods are
* enabled. */
@@ -3498,11 +3728,19 @@ static int mov_write_header(AVFormatContext *s)
FF_MOV_FLAG_FRAG_CUSTOM))
mov->flags |= FF_MOV_FLAG_FRAGMENT;
+ /* Set other implicit flags immediately */
+ if (mov->mode == MODE_ISM)
+ mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
+ FF_MOV_FLAG_FRAGMENT;
+
/* faststart: moov at the beginning of the file, if supported */
if (mov->flags & FF_MOV_FLAG_FASTSTART) {
- if (mov->flags & FF_MOV_FLAG_FRAGMENT)
+ if ((mov->flags & FF_MOV_FLAG_FRAGMENT) ||
+ (s->flags & AVFMT_FLAG_CUSTOM_IO)) {
+ av_log(s, AV_LOG_WARNING, "The faststart flag is incompatible "
+ "with fragmentation and custom IO, disabling faststart\n");
mov->flags &= ~FF_MOV_FLAG_FASTSTART;
- else
+ } else
mov->reserved_moov_size = -1;
}
@@ -3513,37 +3751,33 @@ static int mov_write_header(AVFormatContext *s)
/* Non-seekable output is ok if using fragmentation. If ism_lookahead
* is enabled, we don't support non-seekable output at all. */
if (!s->pb->seekable &&
- ((!(mov->flags & FF_MOV_FLAG_FRAGMENT) &&
- !(s->oformat && !strcmp(s->oformat->name, "ismv")))
- || mov->ism_lookahead)) {
+ (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead)) {
av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
- return -1;
+ return AVERROR(EINVAL);
}
- /* Default mode == MP4 */
- mov->mode = MODE_MP4;
-
- if (s->oformat != NULL) {
- if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
- else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2;
- else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
- else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
- else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD;
- else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM;
- else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V;
-
- mov_write_ftyp_tag(pb,s);
- if (mov->mode == MODE_PSP) {
- if (s->nb_streams != 2) {
- av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
- return -1;
+ mov_write_ftyp_tag(pb,s);
+ if (mov->mode == MODE_PSP) {
+ int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ video_streams_nb++;
+ else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ audio_streams_nb++;
+ else
+ other_streams_nb++;
}
- mov_write_uuidprof_tag(pb,s);
+
+ if (video_streams_nb != 1 || audio_streams_nb != 1 || other_streams_nb) {
+ av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
+ return AVERROR(EINVAL);
}
+ mov_write_uuidprof_tag(pb, s);
}
mov->nb_streams = s->nb_streams;
- if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters)
+ if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
mov->chapter_track = mov->nb_streams++;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
@@ -3584,75 +3818,93 @@ static int mov_write_header(AVFormatContext *s)
mov->nb_streams += mov->nb_meta_tmcd;
}
- mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks));
+ // Reserve an extra stream for chapters for the case where chapters
+ // are written in the trailer
+ mov->tracks = av_mallocz((mov->nb_streams + 1) * sizeof(*mov->tracks));
if (!mov->tracks)
return AVERROR(ENOMEM);
- for(i=0; i<s->nb_streams; i++){
+ for (i = 0; i < s->nb_streams; i++) {
AVStream *st= s->streams[i];
MOVTrack *track= &mov->tracks[i];
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
track->enc = st->codec;
+ track->st = st;
track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
if (track->language < 0)
track->language = 0;
track->mode = mov->mode;
- track->tag = mov_find_codec_tag(s, track);
+ 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,
* this is updated. */
track->hint_track = -1;
- track->start_dts = AV_NOPTS_VALUE;
- if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
+ track->start_dts = AV_NOPTS_VALUE;
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
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;
+ track->height = track->tag >> 24 == 'n' ? 486 : 576;
+ }
+ if (mov->video_track_timescale) {
+ track->timescale = mov->video_track_timescale;
+ } else {
+ track->timescale = st->codec->time_base.den;
+ while(track->timescale < 10000)
+ track->timescale *= 2;
}
- track->timescale = st->codec->time_base.den;
- while(track->timescale < 10000)
- track->timescale *= 2;
if (track->mode == MODE_MOV && track->timescale > 100000)
av_log(s, AV_LOG_WARNING,
"WARNING codec timebase is very high. If duration is too long,\n"
"file may not be playable by quicktime. Specify a shorter timebase\n"
"or choose different container.\n");
- }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
track->timescale = st->codec->sample_rate;
- if(!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
+ if (!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
track->audio_vbr = 1;
- }else if(st->codec->codec_id == AV_CODEC_ID_ADPCM_MS ||
+ }else if (st->codec->codec_id == AV_CODEC_ID_ADPCM_MS ||
st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
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;
- }else if(st->codec->frame_size > 1){ /* assume compressed audio */
+ }else if (st->codec->frame_size > 1){ /* assume compressed audio */
track->audio_vbr = 1;
}else{
track->sample_size = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
}
+ if (st->codec->codec_id == AV_CODEC_ID_ILBC ||
+ st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
+ track->audio_vbr = 1;
+ }
if (track->mode != MODE_MOV &&
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){
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ track->timescale = st->codec->time_base.den;
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) {
track->timescale = st->codec->time_base.den;
- }else{
+ } else {
track->timescale = MOV_TIMESCALE;
}
if (!track->height)
@@ -3672,24 +3924,27 @@ static int mov_write_header(AVFormatContext *s)
}
}
+ 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->max_fragment_duration = 5000000;
- mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
- FF_MOV_FLAG_FRAGMENT;
+ mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
}
- if(mov->reserved_moov_size){
+ if (mov->reserved_moov_size){
mov->reserved_moov_pos= avio_tell(pb);
if (mov->reserved_moov_size > 0)
avio_skip(pb, mov->reserved_moov_size);
}
- if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
+ if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
+ if (mov->flags & FF_MOV_FLAG_FASTSTART)
+ mov->reserved_moov_pos = avio_tell(pb);
mov_write_mdat_tag(pb, mov);
+ }
if (t = av_dict_get(s->metadata, "creation_time", NULL, 0))
mov->time = ff_iso8601_to_unix_time(t->value);
@@ -3697,7 +3952,8 @@ static int mov_write_header(AVFormatContext *s)
mov->time += 0x7C25B080; // 1970 based -> 1904 based
if (mov->chapter_track)
- mov_create_chapter_track(s, mov->chapter_track);
+ if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
+ goto error;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
/* Initialize the hint tracks for each audio and video stream */
@@ -3705,7 +3961,8 @@ 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) {
- ff_mov_init_hinting(s, hint_track, i);
+ if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
+ goto error;
hint_track++;
}
}
@@ -3722,7 +3979,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++;
}
@@ -3741,15 +3998,27 @@ static int mov_write_header(AVFormatContext *s)
return 0;
error:
- av_freep(&mov->tracks);
- return -1;
+ mov_free(s);
+ return ret;
}
-/**
+static int get_moov_size(AVFormatContext *s)
+{
+ int ret;
+ AVIOContext *moov_buf;
+ MOVMuxContext *mov = s->priv_data;
+
+ if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
+ return ret;
+ mov_write_moov_tag(moov_buf, mov, s);
+ return ffio_close_null_buf(moov_buf);
+}
+
+/*
* This function gets the moov size if moved to the top of the file: the chunk
* offset table can switch between stco (32-bit entries) to co64 (64-bit
- * entries) when the moov is moved to the top, so the size of the moov would
- * change. It also updates the chunk offset tables.
+ * entries) when the moov is moved to the beginning, so the size of the moov
+ * would change. It also updates the chunk offset tables.
*/
static int compute_moov_size(AVFormatContext *s)
{
@@ -3767,7 +4036,7 @@ static int compute_moov_size(AVFormatContext *s)
if (moov_size2 < 0)
return moov_size2;
- /* if the size changed, we just switched from stco to co64 and needs to
+ /* if the size changed, we just switched from stco to co64 and need to
* update the offsets */
if (moov_size2 != moov_size)
for (i = 0; i < mov->nb_streams; i++)
@@ -3843,9 +4112,9 @@ static int mov_write_trailer(AVFormatContext *s)
{
MOVMuxContext *mov = s->priv_data;
AVIOContext *pb = s->pb;
- int64_t moov_pos;
int res = 0;
int i;
+ int64_t moov_pos;
/*
* Before actually writing the trailer, make sure that there are no
@@ -3860,9 +4129,20 @@ static int mov_write_trailer(AVFormatContext *s)
}
}
- moov_pos = avio_tell(pb);
+ // If there were no chapters when the header was written, but there
+ // are chapters now, write them in the trailer. This only works
+ // when we are not doing fragments.
+ if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
+ if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
+ mov->chapter_track = mov->nb_streams++;
+ if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
+ goto error;
+ }
+ }
if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
+ moov_pos = avio_tell(pb);
+
/* Write size of mdat tag */
if (mov->mdat_size + 8 <= UINT32_MAX) {
avio_seek(pb, mov->mdat_pos, SEEK_SET);
@@ -3878,8 +4158,8 @@ static int mov_write_trailer(AVFormatContext *s)
}
avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET);
- if (mov->reserved_moov_size == -1) {
- av_log(s, AV_LOG_INFO, "Starting second pass: moving header on top of the file\n");
+ if (mov->flags & FF_MOV_FLAG_FASTSTART) {
+ av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
res = shift_data(s);
if (res == 0) {
avio_seek(s->pb, mov->reserved_moov_pos, SEEK_SET);
@@ -3889,13 +4169,13 @@ static int mov_write_trailer(AVFormatContext *s)
int64_t size;
mov_write_moov_tag(pb, mov, s);
size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos);
- if(size < 8){
+ if (size < 8){
av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
return -1;
}
avio_wb32(pb, size);
ffio_wfourcc(pb, "free");
- for(i=0; i<size; i++)
+ for (i = 0; i < size; i++)
avio_w8(pb, 0);
avio_seek(pb, moov_pos, SEEK_SET);
} else {
@@ -3906,14 +4186,7 @@ static int mov_write_trailer(AVFormatContext *s)
mov_write_mfra_tag(pb, mov);
}
- if (mov->chapter_track)
- av_freep(&mov->tracks[mov->chapter_track].enc);
-
- for (i=0; i<mov->nb_streams; i++) {
- if (mov->tracks[i].tag == MKTAG('r','t','p',' '))
- ff_mov_close_hinting(&mov->tracks[i]);
- else if (mov->tracks[i].tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
- av_freep(&mov->tracks[i].enc);
+ for (i = 0; i < mov->nb_streams; i++) {
if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
mov->tracks[i].vc1_info.struct_offset && s->pb->seekable) {
int64_t off = avio_tell(pb);
@@ -3924,15 +4197,10 @@ static int mov_write_trailer(AVFormatContext *s)
avio_seek(pb, off, SEEK_SET);
}
}
- av_freep(&mov->tracks[i].cluster);
- av_freep(&mov->tracks[i].frag_info);
-
- if (mov->tracks[i].vos_len)
- av_free(mov->tracks[i].vos_data);
-
}
- av_freep(&mov->tracks);
+error:
+ mov_free(s);
return res;
}
@@ -3950,7 +4218,7 @@ AVOutputFormat ff_mov_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){
ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0
},
@@ -3969,7 +4237,7 @@ AVOutputFormat ff_tgp_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
.priv_class = &tgp_muxer_class,
};
@@ -3988,7 +4256,7 @@ AVOutputFormat ff_mp4_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
.priv_class = &mp4_muxer_class,
};
@@ -4006,7 +4274,7 @@ AVOutputFormat ff_psp_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
.priv_class = &psp_muxer_class,
};
@@ -4023,7 +4291,7 @@ AVOutputFormat ff_tg2_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 },
.priv_class = &tg2_muxer_class,
};
@@ -4041,7 +4309,7 @@ AVOutputFormat ff_ipod_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
.priv_class = &ipod_muxer_class,
};
@@ -4059,7 +4327,7 @@ AVOutputFormat ff_ismv_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
.priv_class = &ismv_muxer_class,
};
diff --git a/ffmpeg/libavformat/movenc.h b/ffmpeg/libavformat/movenc.h
index a5db895..09f3ea7 100644
--- a/ffmpeg/libavformat/movenc.h
+++ b/ffmpeg/libavformat/movenc.h
@@ -26,7 +26,8 @@
#include "avformat.h"
-#define MOV_INDEX_CLUSTER_SIZE 16384
+#define MOV_FRAG_INFO_ALLOC_INCREMENT 64
+#define MOV_INDEX_CLUSTER_SIZE 1024
#define MOV_TIMESCALE 1000
#define RTP_MAX_PACKET_SIZE 1450
@@ -75,7 +76,7 @@ typedef struct MOVFragmentInfo {
int64_t tfrf_offset;
} MOVFragmentInfo;
-typedef struct MOVIndex {
+typedef struct MOVTrack {
int mode;
int entry;
unsigned timescale;
@@ -88,20 +89,22 @@ typedef struct MOVIndex {
int has_keyframes;
#define MOV_TRACK_CTTS 0x0001
#define MOV_TRACK_STPS 0x0002
+#define MOV_TRACK_ENABLED 0x0004
uint32_t flags;
#define MOV_TIMECODE_FLAG_DROPFRAME 0x0001
#define MOV_TIMECODE_FLAG_24HOURSMAX 0x0002
#define MOV_TIMECODE_FLAG_ALLOWNEGATIVE 0x0004
uint32_t timecode_flags;
int language;
- int secondary;
int track_id;
int tag; ///< stsd fourcc
+ AVStream *st;
AVCodecContext *enc;
int vos_len;
uint8_t *vos_data;
MOVIentry *cluster;
+ unsigned cluster_capacity;
int audio_vbr;
int height; ///< active picture (w/o VBI) height for D-10/IMX
uint32_t tref_tag;
@@ -122,13 +125,13 @@ typedef struct MOVIndex {
HintSampleQueue sample_queue;
AVIOContext *mdat_buf;
- int64_t moof_size_offset;
int64_t data_offset;
int64_t frag_start;
int64_t tfrf_offset;
int nb_frag_info;
MOVFragmentInfo *frag_info;
+ unsigned frag_info_capacity;
struct {
int64_t struct_offset;
@@ -153,8 +156,6 @@ typedef struct MOVMuxContext {
int flags;
int rtp_flags;
- int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
- int64_t reserved_moov_pos;
int iods_skip;
int iods_video_profile;
@@ -168,6 +169,10 @@ typedef struct MOVMuxContext {
AVIOContext *mdat_buf;
int use_editlist;
+ int video_track_timescale;
+
+ int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
+ int64_t reserved_moov_pos;
} MOVMuxContext;
#define FF_MOV_FLAG_RTP_HINT 1
@@ -178,6 +183,7 @@ typedef struct MOVMuxContext {
#define FF_MOV_FLAG_FRAG_CUSTOM 32
#define FF_MOV_FLAG_ISML 64
#define FF_MOV_FLAG_FASTSTART 128
+#define FF_MOV_FLAG_OMIT_TFHD_OFFSET 256
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
diff --git a/ffmpeg/libavformat/movenchint.c b/ffmpeg/libavformat/movenchint.c
index cc90f0b..9d6a66e 100644
--- a/ffmpeg/libavformat/movenchint.c
+++ b/ffmpeg/libavformat/movenchint.c
@@ -87,7 +87,7 @@ static void sample_queue_free(HintSampleQueue *queue)
if (queue->samples[i].own_data)
av_free(queue->samples[i].data);
av_freep(&queue->samples);
- queue->len = 0;
+ queue->len = 0;
queue->size = 0;
}
@@ -104,17 +104,17 @@ static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size,
if (size <= 14)
return;
if (!queue->samples || queue->len >= queue->size) {
- HintSample* samples;
- queue->size += 10;
- samples = av_realloc(queue->samples, sizeof(HintSample)*queue->size);
+ HintSample *samples;
+ samples = av_realloc_array(queue->samples, queue->size + 10, sizeof(HintSample));
if (!samples)
return;
+ queue->size += 10;
queue->samples = samples;
}
queue->samples[queue->len].data = data;
queue->samples[queue->len].size = size;
queue->samples[queue->len].sample_number = sample;
- queue->samples[queue->len].offset = 0;
+ queue->samples[queue->len].offset = 0;
queue->samples[queue->len].own_data = 0;
queue->len++;
}
@@ -128,7 +128,7 @@ static void sample_queue_retain(HintSampleQueue *queue)
for (i = 0; i < queue->len; ) {
HintSample *sample = &queue->samples[i];
if (!sample->own_data) {
- uint8_t* ptr = av_malloc(sample->size);
+ uint8_t *ptr = av_malloc(sample->size);
if (!ptr) {
/* Unable to allocate memory for this one, remove it */
memmove(queue->samples + i, queue->samples + i + 1,
@@ -309,11 +309,11 @@ static void describe_payload(const uint8_t *data, int size,
* @param data buffer containing RTP packets
* @param size the size of the data buffer
* @param trk the MOVTrack for the hint track
- * @param pts pointer where the timestamp for the written RTP hint is stored
+ * @param dts pointer where the timestamp for the written RTP hint is stored
* @return the number of RTP packets in the written hint
*/
static int write_hint_packets(AVIOContext *out, const uint8_t *data,
- int size, MOVTrack *trk, int64_t *pts)
+ int size, MOVTrack *trk, int64_t *dts)
{
int64_t curpos;
int64_t count_pos, entries_pos;
@@ -328,6 +328,7 @@ static int write_hint_packets(AVIOContext *out, const uint8_t *data,
uint32_t packet_len = AV_RB32(data);
uint16_t seq;
uint32_t ts;
+ int32_t ts_diff;
data += 4;
size -= 4;
@@ -344,25 +345,35 @@ static int write_hint_packets(AVIOContext *out, const uint8_t *data,
trk->max_packet_size = packet_len;
seq = AV_RB16(&data[2]);
- ts = AV_RB32(&data[4]);
+ ts = AV_RB32(&data[4]);
if (trk->prev_rtp_ts == 0)
trk->prev_rtp_ts = ts;
/* Unwrap the 32-bit RTP timestamp that wraps around often
* into a not (as often) wrapping 64-bit timestamp. */
- trk->cur_rtp_ts_unwrapped += (int32_t) (ts - trk->prev_rtp_ts);
- trk->prev_rtp_ts = ts;
- if (*pts == AV_NOPTS_VALUE)
- *pts = trk->cur_rtp_ts_unwrapped;
+ ts_diff = ts - trk->prev_rtp_ts;
+ if (ts_diff > 0) {
+ trk->cur_rtp_ts_unwrapped += ts_diff;
+ trk->prev_rtp_ts = ts;
+ ts_diff = 0;
+ }
+ if (*dts == AV_NOPTS_VALUE)
+ *dts = trk->cur_rtp_ts_unwrapped;
count++;
/* RTPpacket header */
avio_wb32(out, 0); /* relative_time */
avio_write(out, data, 2); /* RTP header */
avio_wb16(out, seq); /* RTPsequenceseed */
- avio_wb16(out, 0); /* reserved + flags */
+ avio_wb16(out, ts_diff ? 4 : 0); /* reserved + flags (extra_flag) */
entries_pos = avio_tell(out);
avio_wb16(out, 0); /* entry count */
+ if (ts_diff) { /* if extra_flag is set */
+ avio_wb32(out, 16); /* extra_information_length */
+ avio_wb32(out, 12); /* rtpoffsetTLV box */
+ avio_write(out, "rtpo", 4);
+ avio_wb32(out, ts_diff);
+ }
data += 12;
size -= 12;
@@ -417,7 +428,7 @@ int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
* for next time. */
size = avio_close_dyn_buf(rtp_ctx->pb, &buf);
if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb,
- RTP_MAX_PACKET_SIZE)) < 0)
+ RTP_MAX_PACKET_SIZE)) < 0)
goto done;
if (size <= 0)
@@ -445,8 +456,9 @@ done:
return ret;
}
-void ff_mov_close_hinting(MOVTrack *track) {
- AVFormatContext* rtp_ctx = track->rtp_ctx;
+void ff_mov_close_hinting(MOVTrack *track)
+{
+ AVFormatContext *rtp_ctx = track->rtp_ctx;
uint8_t *ptr;
av_freep(&track->enc);
diff --git a/ffmpeg/libavformat/mp3dec.c b/ffmpeg/libavformat/mp3dec.c
index 57e4ba3..5d484e9 100644
--- a/ffmpeg/libavformat/mp3dec.c
+++ b/ffmpeg/libavformat/mp3dec.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/opt.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
@@ -36,11 +37,15 @@
#define XING_TOC_COUNT 100
typedef struct {
+ AVClass *class;
int64_t filesize;
+ int64_t header_filesize;
int xing_toc;
int start_pad;
int end_pad;
-} MP3Context;
+ int usetoc;
+ int is_cbr;
+} MP3DecContext;
/* mp3 read */
@@ -62,6 +67,8 @@ static int mp3_read_probe(AVProbeData *p)
for(; buf < end; buf= buf2+1) {
buf2 = buf;
+ if(ff_mpa_check_header(AV_RB32(buf2)))
+ continue;
for(frames = 0; buf2 < end; frames++) {
header = AV_RB32(buf2);
@@ -76,11 +83,11 @@ static int mp3_read_probe(AVProbeData *p)
}
// keep this in sync with ac3 probe, both need to avoid
// issues with MPEG-files!
- if (first_frames>=4) return AVPROBE_SCORE_MAX/2+1;
- else if(max_frames>200)return AVPROBE_SCORE_MAX/2;
- else if(max_frames>=4) return AVPROBE_SCORE_MAX/4;
+ 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(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size)
- return AVPROBE_SCORE_MAX/8;
+ return p->buf_size < PROBE_BUF_MAX ? AVPROBE_SCORE_EXTENSION / 4 : AVPROBE_SCORE_EXTENSION - 2;
else if(max_frames>=1) return 1;
else return 0;
//mpegps_mp3_unrecognized_format.mpg has max_frames=3
@@ -89,23 +96,25 @@ static int mp3_read_probe(AVProbeData *p)
static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration)
{
int i;
- MP3Context *mp3 = s->priv_data;
+ MP3DecContext *mp3 = s->priv_data;
+ int fill_index = mp3->usetoc && duration > 0;
if (!filesize &&
!(filesize = avio_size(s->pb))) {
av_log(s, AV_LOG_WARNING, "Cannot determine file size, skipping TOC table.\n");
- return;
+ fill_index = 0;
}
for (i = 0; i < XING_TOC_COUNT; i++) {
uint8_t b = avio_r8(s->pb);
-
- av_add_index_entry(s->streams[0],
+ if (fill_index)
+ av_add_index_entry(s->streams[0],
av_rescale(b, filesize, 256),
av_rescale(i, duration, XING_TOC_COUNT),
0, 0, AVINDEX_KEYFRAME);
}
- mp3->xing_toc = 1;
+ if (fill_index)
+ mp3->xing_toc = 1;
}
/**
@@ -113,11 +122,11 @@ static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration
*/
static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
{
- MP3Context *mp3 = s->priv_data;
+ 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 */
- const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
+ static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
MPADecodeHeader c;
int vbrtag_size = 0;
int is_cbr;
@@ -143,7 +152,7 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
frames = avio_rb32(s->pb);
if(v & XING_FLAG_SIZE)
size = avio_rb32(s->pb);
- if (v & XING_FLAG_TOC && frames)
+ 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)
@@ -185,12 +194,15 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t 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;
+
return 0;
}
static int mp3_read_header(AVFormatContext *s)
{
- MP3Context *mp3 = s->priv_data;
+ MP3DecContext *mp3 = s->priv_data;
AVStream *st;
int64_t off;
@@ -226,7 +238,7 @@ static int mp3_read_header(AVFormatContext *s)
static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
{
- MP3Context *mp3 = s->priv_data;
+ MP3DecContext *mp3 = s->priv_data;
int ret, size;
int64_t pos;
@@ -273,29 +285,42 @@ static int check(AVFormatContext *s, int64_t pos)
static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags)
{
- MP3Context *mp3 = s->priv_data;
- AVIndexEntry *ie;
+ MP3DecContext *mp3 = s->priv_data;
+ AVIndexEntry *ie, ie1;
AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags);
int i, j;
+ int dir = (flags&AVSEEK_FLAG_BACKWARD) ? -1 : 1;
+
+ if (mp3->is_cbr && st->duration > 0 && mp3->header_filesize > s->data_offset) {
+ int64_t filesize = avio_size(s->pb);
+ int64_t duration;
+ if (filesize <= s->data_offset)
+ filesize = mp3->header_filesize;
+ filesize -= s->data_offset;
+ duration = av_rescale(st->duration, filesize, mp3->header_filesize - s->data_offset);
+ ie = &ie1;
+ timestamp = av_clip64(timestamp, 0, duration);
+ ie->timestamp = timestamp;
+ ie->pos = av_rescale(timestamp, filesize, duration) + s->data_offset;
+ } else if (mp3->xing_toc) {
+ if (ret < 0)
+ return ret;
- if (!mp3->xing_toc) {
+ ie = &st->index_entries[ret];
+ } else {
st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
return -1;
}
- if (ret < 0)
- return ret;
-
- ie = &st->index_entries[ret];
ret = avio_seek(s->pb, ie->pos, SEEK_SET);
if (ret < 0)
return ret;
#define MIN_VALID 3
for(i=0; i<4096; i++) {
- int64_t pos = ie->pos + i;
+ int64_t pos = ie->pos + i*dir;
for(j=0; j<MIN_VALID; j++) {
ret = check(s, pos);
if(ret < 0)
@@ -308,7 +333,7 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
if(j!=MIN_VALID)
i=0;
- ret = avio_seek(s->pb, ie->pos + i, SEEK_SET);
+ ret = avio_seek(s->pb, ie->pos + i*dir, SEEK_SET);
if (ret < 0)
return ret;
ff_update_cur_dts(s, st, ie->timestamp);
@@ -316,14 +341,28 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
return 0;
}
+static const AVOption options[] = {
+ { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM},
+ { NULL },
+};
+
+static const AVClass demuxer_class = {
+ .class_name = "mp3",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEMUXER,
+};
+
AVInputFormat ff_mp3_demuxer = {
.name = "mp3",
.long_name = NULL_IF_CONFIG_SMALL("MP2/3 (MPEG audio layer 2/3)"),
- .priv_data_size = sizeof(MP3Context),
.read_probe = mp3_read_probe,
.read_header = mp3_read_header,
.read_packet = mp3_read_packet,
.read_seek = mp3_seek,
+ .priv_data_size = sizeof(MP3DecContext),
.flags = AVFMT_GENERIC_INDEX,
- .extensions = "mp2,mp3,m2a", /* XXX: use probe */
+ .extensions = "mp2,mp3,m2a,mpa", /* XXX: use probe */
+ .priv_class = &demuxer_class,
};
diff --git a/ffmpeg/libavformat/mp3enc.c b/ffmpeg/libavformat/mp3enc.c
index ee0956e..a5f672b 100644
--- a/ffmpeg/libavformat/mp3enc.c
+++ b/ffmpeg/libavformat/mp3enc.c
@@ -30,10 +30,6 @@
#include "libavcodec/mpegaudiodecheader.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
-#include "libavcodec/mpegaudio.h"
-#include "libavcodec/mpegaudiodata.h"
-#include "libavcodec/mpegaudiodecheader.h"
-#include "libavformat/avio_internal.h"
#include "libavutil/dict.h"
#include "libavutil/avassert.h"
@@ -385,7 +381,7 @@ AVOutputFormat ff_mp2_muxer = {
.name = "mp2",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
.mime_type = "audio/x-mpeg",
- .extensions = "mp2,m2a",
+ .extensions = "mp2,m2a,mpa",
.audio_codec = AV_CODEC_ID_MP2,
.video_codec = AV_CODEC_ID_NONE,
.write_packet = ff_raw_write_packet,
diff --git a/ffmpeg/libavformat/mpc.c b/ffmpeg/libavformat/mpc.c
index b0f6f53..c3faebe 100644
--- a/ffmpeg/libavformat/mpc.c
+++ b/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;
- st->codec->extradata_size = 16;
- st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
- avio_read(s->pb, st->codec->extradata, 16);
+ if (ff_get_extradata(st->codec, s->pb, 16) < 0)
+ return AVERROR(ENOMEM);
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/ffmpeg/libavformat/mpc8.c b/ffmpeg/libavformat/mpc8.c
index 73f8057..b32bc9c 100644
--- a/ffmpeg/libavformat/mpc8.c
+++ b/ffmpeg/libavformat/mpc8.c
@@ -92,7 +92,7 @@ static int mpc8_probe(AVProbeData *p)
if (size < 2)
return 0;
if (bs + size - 2 >= bs_end)
- return AVPROBE_SCORE_MAX / 4 - 1; //seems to be valid MPC but no header yet
+ return AVPROBE_SCORE_EXTENSION - 1; // seems to be valid MPC but no header yet
if (header_found) {
if (size < 11 || size > 28)
return 0;
@@ -136,11 +136,11 @@ 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) {
- av_log(s, AV_LOG_ERROR, "cannot parse stream table before stream header\n");
+ if (s->nb_streams == 0) {
+ av_log(s, AV_LOG_ERROR, "No stream added before parsing seek table\n");
return;
}
@@ -151,12 +151,19 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
return;
}
if (size > INT_MAX/10 || size<=0) {
- av_log(s, AV_LOG_ERROR, "Seek table size is invalid\n");
+ av_log(s, AV_LOG_ERROR, "Bad seek table size\n");
return;
}
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;
- st->codec->extradata_size = 2;
- st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ if (ff_get_extradata(st->codec, pb, 2) < 0)
+ return AVERROR(ENOMEM);
st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5];
diff --git a/ffmpeg/libavformat/mpeg.c b/ffmpeg/libavformat/mpeg.c
index f36f0db..1777283 100644
--- a/ffmpeg/libavformat/mpeg.c
+++ b/ffmpeg/libavformat/mpeg.c
@@ -89,14 +89,14 @@ static int mpegps_probe(AVProbeData *p)
}
if(vid+audio > invalid+1) /* invalid VDR files nd short PES streams */
- score= AVPROBE_SCORE_MAX/4;
+ score = AVPROBE_SCORE_EXTENSION / 2;
if(sys>invalid && sys*9 <= pspack*10)
- return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg
+ 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_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg
+ 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_MAX/2+2 : AVPROBE_SCORE_MAX/4;
+ 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
@@ -110,31 +110,28 @@ typedef struct MpegDemuxContext {
unsigned char psm_es_type[256];
int sofdec;
int dvd;
+ int imkh_cctv;
#if CONFIG_VOBSUB_DEMUXER
AVFormatContext *sub_ctx;
- FFDemuxSubtitlesQueue q;
+ FFDemuxSubtitlesQueue q[32];
#endif
} MpegDemuxContext;
static int mpegps_read_header(AVFormatContext *s)
{
MpegDemuxContext *m = s->priv_data;
- const char *sofdec = "Sofdec";
- int v, i = 0;
+ char buffer[7];
int64_t last_pos = avio_tell(s->pb);
m->header_state = 0xff;
s->ctx_flags |= AVFMTCTX_NOHEADER;
- m->sofdec = -1;
- do {
- v = avio_r8(s->pb);
- m->sofdec++;
- } while (v == sofdec[i] && i++ < 6);
-
- m->sofdec = (m->sofdec == 6) ? 1 : 0;
-
- if (!m->sofdec)
+ avio_get_str(s->pb, 6, buffer, sizeof(buffer));
+ if (!memcmp("IMKH", buffer, 4)) {
+ m->imkh_cctv = 1;
+ } else if (!memcmp("Sofdec", buffer, 6)) {
+ m->sofdec = 1;
+ } else
avio_seek(s->pb, last_pos, SEEK_SET);
/* no need to do more */
@@ -196,6 +193,8 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb)
/* skip program_stream_info */
avio_skip(pb, ps_info_length);
es_map_length = avio_rb16(pb);
+ /* Ignore es_map_length, trust psm_length */
+ es_map_length = psm_length - ps_info_length - 10;
/* at least one es available? */
while (es_map_length >= 4){
@@ -506,6 +505,9 @@ static int mpegps_read_packet(AVFormatContext *s,
} 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){
+ codec_id = AV_CODEC_ID_PCM_MULAW;
+ 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];
@@ -521,7 +523,13 @@ static int mpegps_read_packet(AVFormatContext *s,
codec_id = AV_CODEC_ID_DVD_NAV;
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
type = AVMEDIA_TYPE_AUDIO;
- codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2;
+ if (m->sofdec > 0) {
+ codec_id = AV_CODEC_ID_ADPCM_ADX;
+ // Auto-detect AC-3
+ request_probe = 50;
+ } else {
+ codec_id = AV_CODEC_ID_MP2;
+ }
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_AC3;
@@ -535,7 +543,6 @@ static int mpegps_read_packet(AVFormatContext *s,
if(lpcm_header_len == 6) {
codec_id = AV_CODEC_ID_MLP;
} else {
- /* 16 bit form will be handled as AV_CODEC_ID_PCM_S16BE */
codec_id = AV_CODEC_ID_PCM_DVD;
}
} else if (startcode >= 0xb0 && startcode <= 0xbf) {
@@ -564,9 +571,13 @@ static int mpegps_read_packet(AVFormatContext *s,
st->id = startcode;
st->codec->codec_type = type;
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;
- if (codec_id != AV_CODEC_ID_PCM_S16BE)
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
found:
if(st->discard >= AVDISCARD_ALL)
goto skip;
@@ -576,28 +587,6 @@ static int mpegps_read_packet(AVFormatContext *s,
goto skip;
avio_skip(s->pb, 6);
len -=6;
- } else {
- int b1, freq;
-
- /* for LPCM, we just skip the header and consider it is raw
- audio data */
- if (len <= 3)
- goto skip;
- avio_r8(s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */
- b1 = avio_r8(s->pb); /* quant (2), freq(2), reserved(1), channels(3) */
- avio_r8(s->pb); /* dynamic range control (0x80 = off) */
- len -= 3;
- freq = (b1 >> 4) & 3;
- st->codec->sample_rate = lpcm_freq_tab[freq];
- st->codec->channels = 1 + (b1 & 7);
- st->codec->bits_per_coded_sample = 16 + ((b1 >> 6) & 3) * 4;
- st->codec->bit_rate = st->codec->channels *
- st->codec->sample_rate *
- st->codec->bits_per_coded_sample;
- if (st->codec->bits_per_coded_sample == 16)
- st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
- else if (st->codec->bits_per_coded_sample == 28)
- return AVERROR(EINVAL);
}
}
ret = av_get_packet(s->pb, pkt, len);
@@ -712,6 +701,12 @@ static int vobsub_read_header(AVFormatContext *s)
stream_id = 0;
}
+ if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) {
+ av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
st = avformat_new_stream(s, NULL);
if (!st) {
ret = AVERROR(ENOMEM);
@@ -720,6 +715,7 @@ static int vobsub_read_header(AVFormatContext *s)
st->id = stream_id;
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE;
+ avpriv_set_pts_info(st, 64, 1, 1000);
av_dict_set(&st->metadata, "language", id, 0);
av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
header_parsed = 1;
@@ -730,7 +726,13 @@ static int vobsub_read_header(AVFormatContext *s)
int64_t pos, timestamp;
const char *p = line + 10;
- if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"PRIx64,
+ if (!s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64,
&hh, &mm, &ss, &ms, &pos) != 5) {
av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', "
"abort parsing\n", line);
@@ -739,7 +741,7 @@ static int vobsub_read_header(AVFormatContext *s)
timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay;
timestamp = av_rescale_q(timestamp, (AVRational){1,1000}, st->time_base);
- sub = ff_subtitles_queue_insert(&vobsub->q, "", 0, 0);
+ sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0);
if (!sub) {
ret = AVERROR(ENOMEM);
goto end;
@@ -785,7 +787,10 @@ static int vobsub_read_header(AVFormatContext *s)
if (langidx < s->nb_streams)
s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT;
- ff_subtitles_queue_finalize(&vobsub->q);
+ for (i = 0; i < s->nb_streams; i++) {
+ vobsub->q[i].sort = SUB_SORT_POS_TS;
+ ff_subtitles_queue_finalize(&vobsub->q[i]);
+ }
if (!av_bprint_is_complete(&header)) {
av_bprint_finalize(&header, NULL);
@@ -810,11 +815,22 @@ end:
static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MpegDemuxContext *vobsub = s->priv_data;
- FFDemuxSubtitlesQueue *q = &vobsub->q;
+ FFDemuxSubtitlesQueue *q;
AVIOContext *pb = vobsub->sub_ctx->pb;
- int ret, psize, len16 = -1;
+ int ret, psize, total_read = 0, i;
AVPacket idx_pkt;
+ int64_t min_ts = INT64_MAX;
+ int sid = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i];
+ int64_t ts = tmpq->subs[tmpq->current_sub_idx].pts;
+ if (ts < min_ts) {
+ min_ts = ts;
+ sid = i;
+ }
+ }
+ q = &vobsub->q[sid];
ret = ff_subtitles_queue_read_packet(q, &idx_pkt);
if (ret < 0)
return ret;
@@ -837,19 +853,23 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
do {
int n, to_read, startcode;
int64_t pts, dts;
+ int64_t old_pos = avio_tell(pb), new_pos;
+ int pkt_size;
ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts);
- if (ret < 0)
+ if (ret < 0) {
+ if (pkt->size) // raise packet even if incomplete
+ break;
FAIL(ret);
+ }
to_read = ret & 0xffff;
+ new_pos = avio_tell(pb);
+ pkt_size = ret + (new_pos - old_pos);
/* this prevents reads above the current packet */
- if (pkt->size + to_read > psize)
- break;
-
- /* if the len is computed, we check for overread */
- if (len16 != -1 && pkt->size + to_read > len16)
+ if (total_read + pkt_size > psize)
break;
+ total_read += pkt_size;
/* the current chunk doesn't match the stream index (unlikely) */
if ((startcode & 0x1f) != idx_pkt.stream_index)
@@ -862,11 +882,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read);
if (n < to_read)
pkt->size -= to_read - n;
-
- /* first chunk contains the total len of the packet to raise */
- if (len16 == -1 && n > 2)
- len16 = AV_RB16(pkt->data);
- } while (len16 != -1 && pkt->size != len16);
+ } while (total_read < psize);
pkt->pts = pkt->dts = idx_pkt.pts;
pkt->pos = idx_pkt.pos;
@@ -876,6 +892,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
fail:
+ av_free_packet(pkt);
av_free_packet(&idx_pkt);
return ret;
}
@@ -884,14 +901,42 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
MpegDemuxContext *vobsub = s->priv_data;
- return ff_subtitles_queue_seek(&vobsub->q, s, stream_index,
+
+ /* Rescale requested timestamps based on the first stream (timebase is the
+ * same for all subtitles stream within a .idx/.sub). Rescaling is done just
+ * like in avformat_seek_file(). */
+ if (stream_index == -1 && s->nb_streams != 1) {
+ int i, ret = 0;
+ AVRational time_base = s->streams[0]->time_base;
+ ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+ min_ts = av_rescale_rnd(min_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
+ max_ts = av_rescale_rnd(max_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+ for (i = 0; i < s->nb_streams; i++) {
+ int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index,
+ min_ts, ts, max_ts, flags);
+ if (r < 0)
+ ret = r;
+ }
+ return ret;
+ }
+
+ if (stream_index == -1) // only 1 stream
+ stream_index = 0;
+ return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index,
min_ts, ts, max_ts, flags);
}
static int vobsub_read_close(AVFormatContext *s)
{
+ int i;
MpegDemuxContext *vobsub = s->priv_data;
- ff_subtitles_queue_clean(&vobsub->q);
+
+ for (i = 0; i < s->nb_streams; i++)
+ ff_subtitles_queue_clean(&vobsub->q[i]);
if (vobsub->sub_ctx)
avformat_close_input(&vobsub->sub_ctx);
return 0;
diff --git a/ffmpeg/libavformat/mpeg.h b/ffmpeg/libavformat/mpeg.h
index a1e8980..cf10d6a 100644
--- a/ffmpeg/libavformat/mpeg.h
+++ b/ffmpeg/libavformat/mpeg.h
@@ -41,7 +41,7 @@
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
#define AC3_ID 0x80
-#define DTS_ID 0x8a
+#define DTS_ID 0x88
#define LPCM_ID 0xa0
#define SUB_ID 0x20
diff --git a/ffmpeg/libavformat/mpegenc.c b/ffmpeg/libavformat/mpegenc.c
index b467bb5..ccf3ec2 100644
--- a/ffmpeg/libavformat/mpegenc.c
+++ b/ffmpeg/libavformat/mpegenc.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
#include "libavutil/fifo.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
@@ -264,8 +267,7 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str
flush_put_bits(&pb);
size = put_bits_ptr(&pb) - pb.buf;
/* patch packet size */
- buf[4] = (size - 6) >> 8;
- buf[5] = (size - 6) & 0xff;
+ AV_WB16(buf + 4, size - 6);
return size;
}
@@ -293,7 +295,7 @@ static int get_system_header_size(AVFormatContext *ctx)
return buf_index;
}
-static int mpeg_mux_init(AVFormatContext *ctx)
+static av_cold int mpeg_mux_init(AVFormatContext *ctx)
{
MpegMuxContext *s = ctx->priv_data;
int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j;
@@ -320,7 +322,7 @@ static int mpeg_mux_init(AVFormatContext *ctx)
} else
s->packet_size = 2048;
if (ctx->max_delay < 0) /* Not set by the caller */
- ctx->max_delay = 0;
+ ctx->max_delay = 0.7*AV_TIME_BASE;
s->vcd_padding_bytes_written = 0;
s->vcd_padding_bitrate=0;
@@ -344,6 +346,15 @@ static int mpeg_mux_init(AVFormatContext *ctx)
switch(st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
+ if (!s->is_mpeg2 &&
+ (st->codec->codec_id == AV_CODEC_ID_AC3 ||
+ st->codec->codec_id == AV_CODEC_ID_DTS ||
+ st->codec->codec_id == AV_CODEC_ID_PCM_S16BE))
+ av_log(ctx, AV_LOG_WARNING,
+ "%s in MPEG-1 system streams is not widely supported, "
+ "consider using the vob or the dvd muxer "
+ "to force a MPEG-2 program stream.\n",
+ avcodec_get_name(st->codec->codec_id));
if (st->codec->codec_id == AV_CODEC_ID_AC3) {
stream->id = ac3_id++;
} else if (st->codec->codec_id == AV_CODEC_ID_DTS) {
@@ -379,6 +390,10 @@ static int mpeg_mux_init(AVFormatContext *ctx)
av_log(ctx, AV_LOG_WARNING, "VBV buffer size not set, muxing may fail\n");
stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default
}
+ if (stream->max_buffer_size > 1024 * 8191) {
+ av_log(ctx, AV_LOG_WARNING, "buffer size %d, too large\n", stream->max_buffer_size);
+ stream->max_buffer_size = 1024 * 8191;
+ }
s->video_bound++;
break;
case AVMEDIA_TYPE_SUBTITLE:
@@ -424,6 +439,10 @@ static int mpeg_mux_init(AVFormatContext *ctx)
bitrate += bitrate / 20;
bitrate += 10000;
s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);
+ if (s->mux_rate >= (1<<22)) {
+ av_log(ctx, AV_LOG_WARNING, "mux rate %d is too large\n", s->mux_rate);
+ s->mux_rate = (1<<22) - 1;
+ }
}
if (s->is_vcd) {
@@ -905,7 +924,7 @@ static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){
if(stream->buffer_index < pkt_desc->size ||
stream->predecode_packet == stream->premux_packet){
av_log(ctx, AV_LOG_ERROR,
- "buffer underflow i=%d bufi=%d size=%d\n",
+ "buffer underflow st=%d bufi=%d size=%d\n",
i, stream->buffer_index, pkt_desc->size);
break;
}
@@ -947,14 +966,16 @@ retry:
return 0;
if(avail_data==0)
continue;
- assert(avail_data>0);
+ av_assert0(avail_data>0);
if(space < s->packet_size && !ignore_constraints)
continue;
if(next_pkt && next_pkt->dts - scr > max_delay)
continue;
-
+ if ( stream->predecode_packet
+ && stream->predecode_packet->size > stream->buffer_index)
+ rel_space += 1<<28;
if(rel_space > best_score){
best_score= rel_space;
best_i = i;
@@ -1144,7 +1165,7 @@ static int mpeg_mux_end(AVFormatContext *ctx)
#define OFFSET(x) offsetof(MpegMuxContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "muxrate", NULL, OFFSET(user_mux_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "muxrate", NULL, OFFSET(user_mux_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, ((1<<22) - 1) * (8 * 50), E },
{ "preload", "Initial demux-decode delay in microseconds.", OFFSET(preload), AV_OPT_TYPE_INT, {.i64 = 500000}, 0, INT_MAX, E},
{ NULL },
};
diff --git a/ffmpeg/libavformat/mpegts.c b/ffmpeg/libavformat/mpegts.c
index 85b5146..39b1b5d 100644
--- a/ffmpeg/libavformat/mpegts.c
+++ b/ffmpeg/libavformat/mpegts.c
@@ -29,6 +29,7 @@
#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"
@@ -52,7 +53,7 @@ enum MpegTSFilterType {
typedef struct MpegTSFilter MpegTSFilter;
-typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos);
+typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos, int64_t cur_pcr);
typedef struct MpegTSPESFilter {
PESCallback *pes_cb;
@@ -89,6 +90,9 @@ struct Program {
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 {
@@ -98,7 +102,11 @@ struct MpegTSContext {
/** raw packet size, including FEC if present */
int raw_packet_size;
- int pos47;
+ int size_stat[3];
+ int size_stat_count;
+#define SIZE_STAT_THRESHOLD 10
+
+ int64_t pos47_full;
/** if true, all pids are analyzed to find streams */
int auto_guess;
@@ -106,6 +114,9 @@ struct MpegTSContext {
/** 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 */
@@ -131,16 +142,33 @@ struct MpegTSContext {
int current_pid;
};
-static const AVOption options[] = {
+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 },
+ {"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_METADATA },
{ NULL },
};
static const AVClass mpegtsraw_class = {
.class_name = "mpegtsraw demuxer",
.item_name = av_default_item_name,
- .option = options,
+ .option = mpegtsraw_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+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_METADATA },
+ { NULL },
+};
+
+static const AVClass mpegts_class = {
+ .class_name = "mpegts demuxer",
+ .item_name = av_default_item_name,
+ .option = mpegts_options,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -179,10 +207,22 @@ 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;
@@ -203,8 +243,10 @@ static void clear_program(MpegTSContext *ts, unsigned int programid)
clear_avprogram(ts, programid);
for(i=0; i<ts->nb_prg; i++)
- if(ts->prg[i].id == programid)
+ if(ts->prg[i].id == programid) {
ts->prg[i].nb_pids = 0;
+ ts->prg[i].pmt_found = 0;
+ }
}
static void clear_programs(MpegTSContext *ts)
@@ -216,26 +258,20 @@ static void clear_programs(MpegTSContext *ts)
static void add_pat_entry(MpegTSContext *ts, unsigned int programid)
{
struct Program *p;
- void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(struct Program));
- if(!tmp)
+ if (av_reallocp_array(&ts->prg, ts->nb_prg + 1, sizeof(*ts->prg)) < 0) {
+ ts->nb_prg = 0;
return;
- ts->prg = tmp;
+ }
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)
{
- 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;
- }
- }
+ struct Program *p = get_program(ts, programid);
if(!p)
return;
@@ -244,6 +280,15 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i
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;
@@ -268,6 +313,17 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid)
int i, j, k;
int used = 0, discarded = 0;
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++) {
+ 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++) {
p = &ts->prg[i];
for(j=0; j<p->nb_pids; j++) {
@@ -419,22 +475,19 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
int stat[TS_MAX_PACKET_SIZE];
int i;
- int x=0;
int best_score=0;
- memset(stat, 0, packet_size*sizeof(int));
+ memset(stat, 0, packet_size*sizeof(*stat));
- for(x=i=0; i<size-3; i++){
+ 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;
}
}
-
- x++;
- if(x == packet_size) x= 0;
}
return best_score;
@@ -566,6 +619,7 @@ static const StreamType ISO_types[] = {
{ 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 },
@@ -600,11 +654,17 @@ static const StreamType REGD_types[] = {
{ 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 },
+ { 0 },
+};
+
/* descriptor present */
static const StreamType DESC_types[] = {
{ 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */
@@ -808,7 +868,7 @@ 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 pos, int64_t pcr)
{
PESContext *pes = filter->u.pes_filter.opaque;
MpegTSContext *ts = pes->ts;
@@ -818,6 +878,9 @@ static int mpegts_push_data(MpegTSFilter *filter,
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);
@@ -932,7 +995,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
if ((flags & 0xc0) == 0x80) {
- pes->dts = pes->pts = ff_parse_pes_pts(r);
+ 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;
r += 5;
} else if ((flags & 0xc0) == 0xc0) {
pes->pts = ff_parse_pes_pts(r);
@@ -964,6 +1030,38 @@ static int mpegts_push_data(MpegTSFilter *filter,
p += sl_header_bytes;
buf_size -= sl_header_bytes;
}
+ if (pes->stream_type == 0x15 && buf_size >= 5) {
+ /* skip metadata access unit header */
+ pes->pes_header_size += 5;
+ p += 5;
+ buf_size -= 5;
+ }
+ if (pes->ts->fix_teletext_pts && pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ AVProgram *p = NULL;
+ while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) {
+ if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) {
+ 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) {
+ // 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;
+ if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) {
+ pes->pts = pes->dts = pcr;
+ } else if (pes->dts > pcr + 3654 + 9000) {
+ pes->pts = pes->dts = pcr + 3654 + 9000;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
}
break;
case MPEGTS_PAYLOAD:
@@ -1020,6 +1118,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int 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);
if (!tss) {
av_free(pes);
@@ -1157,6 +1256,11 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
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);
@@ -1391,9 +1495,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4))
avpriv_request_sample(fc, "DVB sub with multiple IDs");
} else {
- st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata) {
- st->codec->extradata_size = 4;
+ if (!ff_alloc_extradata(st->codec, 4)) {
memcpy(st->codec->extradata, *pp, 4);
}
}
@@ -1426,6 +1528,15 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
case 0x52: /* stream identifier descriptor */
st->stream_identifier = 1 + get8(pp, desc_end);
break;
+ case 0x26: /* metadata descriptor */
+ if (get16(pp, desc_end) == 0xFFFF)
+ *pp += 4;
+ if (get8(pp, desc_end) == 0xFF) {
+ st->codec->codec_tag = bytestream_get_le32(pp);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ mpegts_find_stream_type(st, st->codec->codec_tag, METADATA_types);
+ }
+ break;
default:
break;
}
@@ -1507,6 +1618,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (!ts->stream->nb_streams)
ts->stop_parse = 2;
+ set_pmt_found(ts, h->id);
+
for(;;) {
st = 0;
pes = NULL;
@@ -1625,12 +1738,18 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (sid == 0x0000) {
/* NIT info */
} else {
+ MpegTSFilter *fil = ts->pids[pmt_pid];
program = av_new_program(ts->stream, sid);
program->program_num = sid;
program->pmt_pid = pmt_pid;
- if (ts->pids[pmt_pid])
- mpegts_close_filter(ts, ts->pids[pmt_pid]);
- mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
+ if (fil)
+ if ( fil->type != MPEGTS_SECTION
+ || fil->pid != pmt_pid
+ || fil->u.section_filter.section_cb != pmt_cb)
+ mpegts_close_filter(ts, ts->pids[pmt_pid]);
+
+ 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, pmt_pid);
@@ -1726,6 +1845,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
}
}
+static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
+ const uint8_t *packet);
+
/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
@@ -1790,7 +1912,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
return 0;
pos = avio_tell(ts->stream->pb);
- ts->pos47= pos % ts->raw_packet_size;
+ if (pos >= 0) {
+ av_assert0(pos >= TS_PACKET_SIZE);
+ ts->pos47_full = pos - TS_PACKET_SIZE;
+ }
if (tss->type == MPEGTS_SECTION) {
if (is_start) {
@@ -1817,17 +1942,70 @@ 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) {
+ 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;
// 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)) < 0)
+ pos - ts->raw_packet_size, pcr)) < 0)
return ret;
}
return 0;
}
+static void reanalyze(MpegTSContext *ts) {
+ AVIOContext *pb = ts->stream->pb;
+ int64_t pos = avio_tell(pb);
+ if(pos < 0)
+ return;
+ pos -= ts->pos47_full;
+ if (pos == TS_PACKET_SIZE) {
+ ts->size_stat[0] ++;
+ } else if (pos == TS_DVHS_PACKET_SIZE) {
+ ts->size_stat[1] ++;
+ } else if (pos == TS_FEC_PACKET_SIZE) {
+ ts->size_stat[2] ++;
+ }
+
+ ts->size_stat_count ++;
+ if(ts->size_stat_count > SIZE_STAT_THRESHOLD) {
+ int newsize = 0;
+ if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_PACKET_SIZE;
+ } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_DVHS_PACKET_SIZE;
+ } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_FEC_PACKET_SIZE;
+ }
+ if (newsize && newsize != ts->raw_packet_size) {
+ av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize);
+ ts->raw_packet_size = newsize;
+ }
+ ts->size_stat_count = 0;
+ memset(ts->size_stat, 0, sizeof(ts->size_stat));
+ }
+}
+
/* XXX: try to find a better synchro over several packets (use
get_packet_size() ?) */
static int mpegts_resync(AVFormatContext *s)
@@ -1841,6 +2019,7 @@ static int mpegts_resync(AVFormatContext *s)
return -1;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
+ reanalyze(s->priv_data);
return 0;
}
}
@@ -1850,37 +2029,45 @@ static int mpegts_resync(AVFormatContext *s)
}
/* return -1 if error or EOF. Return 0 if OK. */
-static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size)
+static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, const uint8_t **data)
{
AVIOContext *pb = s->pb;
- int skip, len;
+ int len;
for(;;) {
- len = avio_read(pb, buf, TS_PACKET_SIZE);
+ len = ffio_read_indirect(pb, buf, TS_PACKET_SIZE, data);
if (len != TS_PACKET_SIZE)
return len < 0 ? len : AVERROR_EOF;
/* check packet sync byte */
- if (buf[0] != 0x47) {
+ if ((*data)[0] != 0x47) {
/* find a new packet start */
- avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
+ uint64_t pos = avio_tell(pb);
+ avio_seek(pb, -FFMIN(raw_packet_size, pos), SEEK_CUR);
+
if (mpegts_resync(s) < 0)
return AVERROR(EAGAIN);
else
continue;
} else {
- skip = raw_packet_size - TS_PACKET_SIZE;
- if (skip > 0)
- avio_skip(pb, skip);
break;
}
}
return 0;
}
+static void finished_reading_packet(AVFormatContext *s, int raw_packet_size)
+{
+ AVIOContext *pb = s->pb;
+ int skip = raw_packet_size - TS_PACKET_SIZE;
+ if (skip > 0)
+ avio_skip(pb, skip);
+}
+
static int handle_packets(MpegTSContext *ts, int nb_packets)
{
AVFormatContext *s = ts->stream;
uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ const uint8_t *data;
int packet_num, ret = 0;
if (avio_tell(s->pb) != ts->last_pos) {
@@ -1894,6 +2081,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
av_buffer_unref(&pes->buffer);
pes->data_index = 0;
pes->state = MPEGTS_SKIP; /* skip until pes header */
+ pes->last_pcr = -1;
}
ts->pids[i]->last_cc = -1;
}
@@ -1913,10 +2101,11 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
if (ts->stop_parse > 0)
break;
- ret = read_packet(s, packet, ts->raw_packet_size);
+ ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret != 0)
break;
- ret = handle_packet(ts, packet);
+ ret = handle_packet(ts, data);
+ finished_reading_packet(s, ts->raw_packet_size);
if (ret != 0)
break;
}
@@ -1986,6 +2175,15 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
return 0;
}
+static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) {
+
+ /* NOTE: We attempt to seek on non-seekable files as well, as the
+ * probe buffer usually is big enough. Only warn if the seek failed
+ * on files where the seek should work. */
+ if (avio_seek(pb, pos, SEEK_SET) < 0)
+ av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
+}
+
static int mpegts_read_header(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
@@ -1994,6 +2192,8 @@ static int mpegts_read_header(AVFormatContext *s)
int len;
int64_t pos;
+ ffio_ensure_seekback(pb, s->probesize);
+
/* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
@@ -2009,11 +2209,7 @@ static int mpegts_read_header(AVFormatContext *s)
/* normal demux */
/* first do a scan to get all the services */
- /* NOTE: We attempt to seek on non-seekable files as well, as the
- * probe buffer usually is big enough. Only warn if the seek failed
- * on files where the seek should work. */
- if (avio_seek(pb, pos, SEEK_SET) < 0)
- av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
+ seek_back(s, pb, pos);
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
@@ -2033,6 +2229,7 @@ static int mpegts_read_header(AVFormatContext *s)
int64_t pcrs[2], pcr_h;
int packet_count[2];
uint8_t packet[TS_PACKET_SIZE];
+ const uint8_t *data;
/* only read packets */
@@ -2048,18 +2245,21 @@ static int mpegts_read_header(AVFormatContext *s)
nb_pcrs = 0;
nb_packets = 0;
for(;;) {
- ret = read_packet(s, packet, ts->raw_packet_size);
+ ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret < 0)
- return -1;
- pid = AV_RB16(packet + 1) & 0x1fff;
+ goto fail;
+ pid = AV_RB16(data + 1) & 0x1fff;
if ((pcr_pid == -1 || pcr_pid == pid) &&
- parse_pcr(&pcr_h, &pcr_l, packet) == 0) {
+ parse_pcr(&pcr_h, &pcr_l, data) == 0) {
+ finished_reading_packet(s, ts->raw_packet_size);
pcr_pid = pid;
packet_count[nb_pcrs] = nb_packets;
pcrs[nb_pcrs] = pcr_h * 300 + pcr_l;
nb_pcrs++;
if (nb_pcrs >= 2)
break;
+ } else {
+ finished_reading_packet(s, ts->raw_packet_size);
}
nb_packets++;
}
@@ -2075,7 +2275,7 @@ static int mpegts_read_header(AVFormatContext *s)
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
}
- avio_seek(pb, pos, SEEK_SET);
+ seek_back(s, pb, pos);
return 0;
fail:
return -1;
@@ -2091,15 +2291,19 @@ static int mpegts_raw_read_packet(AVFormatContext *s,
int64_t pcr_h, next_pcr_h, pos;
int pcr_l, next_pcr_l;
uint8_t pcr_buf[12];
+ const uint8_t *data;
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);
+ ret = read_packet(s, pkt->data, ts->raw_packet_size, &data);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
+ if (data != pkt->data)
+ memcpy(pkt->data, data, ts->raw_packet_size);
+ finished_reading_packet(s, ts->raw_packet_size);
if (ts->mpeg2ts_compute_pcr) {
/* compute exact PCR for each packet */
if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) {
@@ -2181,13 +2385,15 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
- pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ 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;
while(pos < pos_limit) {
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
return AV_NOPTS_VALUE;
if (buf[0] != 0x47) {
+ avio_seek(s->pb, -TS_PACKET_SIZE, SEEK_CUR);
if (mpegts_resync(s) < 0)
return AV_NOPTS_VALUE;
pos = avio_tell(s->pb);
@@ -2209,7 +2415,8 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
{
MpegTSContext *ts = s->priv_data;
int64_t pos;
- pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ 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;
ff_read_frame_flush(s);
if (avio_seek(s->pb, pos, SEEK_SET) < 0)
return AV_NOPTS_VALUE;
@@ -2224,7 +2431,7 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
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){
+ if(pkt.stream_index == stream_index && pkt.pos >= *ppos){
*ppos= pkt.pos;
return pkt.dts;
}
@@ -2298,6 +2505,7 @@ AVInputFormat ff_mpegts_demuxer = {
.read_close = mpegts_read_close,
.read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
+ .priv_class = &mpegts_class,
};
AVInputFormat ff_mpegtsraw_demuxer = {
diff --git a/ffmpeg/libavformat/mpegtsenc.c b/ffmpeg/libavformat/mpegtsenc.c
index 7016774..1d51b97 100644
--- a/ffmpeg/libavformat/mpegtsenc.c
+++ b/ffmpeg/libavformat/mpegtsenc.c
@@ -22,10 +22,11 @@
#include "libavutil/bswap.h"
#include "libavutil/crc.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/avassert.h"
-#include "libavcodec/mpegvideo.h"
+#include "libavcodec/internal.h"
#include "avformat.h"
#include "internal.h"
#include "mpegts.h"
@@ -84,6 +85,7 @@ typedef struct MpegTSWrite {
#define MPEGTS_FLAG_AAC_LATM 0x02
int flags;
int copyts;
+ int tables_version;
} MpegTSWrite;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -118,8 +120,10 @@ static const AVOption options[] = {
// backward compatibility
{ "resend_headers", "Reemit PAT/PMT before writing the next packet",
offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
- { "mpegts_copyts", "dont offset dts/pts",
+ { "mpegts_copyts", "don't offset dts/pts",
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},
{ NULL },
};
@@ -251,7 +255,7 @@ static void mpegts_write_pat(AVFormatContext *s)
put16(&q, service->sid);
put16(&q, 0xe000 | service->pmt.pid);
}
- mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, 0, 0, 0,
+ mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, ts->tables_version, 0, 0,
data, q - data);
}
@@ -396,13 +400,23 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
*q++ = 'c';
}
break;
+ case AVMEDIA_TYPE_DATA:
+ if (st->codec->codec_id == AV_CODEC_ID_SMPTE_KLV) {
+ *q++ = 0x05; /* MPEG-2 registration descriptor */
+ *q++ = 4;
+ *q++ = 'K';
+ *q++ = 'L';
+ *q++ = 'V';
+ *q++ = 'A';
+ }
+ break;
}
val = 0xf000 | (q - desc_length_ptr - 2);
desc_length_ptr[0] = val >> 8;
desc_length_ptr[1] = val;
}
- mpegts_write_section1(&service->pmt, PMT_TID, service->sid, 0, 0, 0,
+ mpegts_write_section1(&service->pmt, PMT_TID, service->sid, ts->tables_version, 0, 0,
data, q - data);
}
@@ -457,7 +471,7 @@ static void mpegts_write_sdt(AVFormatContext *s)
desc_list_len_ptr[0] = val >> 8;
desc_list_len_ptr[1] = val;
}
- mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, 0, 0, 0,
+ mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, ts->tables_version, 0, 0,
data, q - data);
}
@@ -976,8 +990,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
*q++ = len >> 8;
*q++ = len;
val = 0x80;
- /* data alignment indicator is required for subtitle data */
- if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ /* data alignment indicator is required for subtitle and data streams */
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA)
val |= 0x04;
*q++ = val;
*q++ = flags;
@@ -1094,13 +1108,16 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
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");
}
do {
- p = avpriv_mpv_find_start_code(p, buf_end, &state);
+ p = avpriv_find_start_code(p, buf_end, &state);
av_dlog(s, "nal %d\n", state & 0x1f);
} while (p < buf_end && (state & 0x1f) != 9 &&
(state & 0x1f) != 5 && (state & 0x1f) != 1);
diff --git a/ffmpeg/libavformat/mpegvideodec.c b/ffmpeg/libavformat/mpegvideodec.c
index 471d2f4..ade76d8 100644
--- a/ffmpeg/libavformat/mpegvideodec.c
+++ b/ffmpeg/libavformat/mpegvideodec.c
@@ -23,6 +23,8 @@
#include "avformat.h"
#include "rawdec.h"
+#include "libavutil/intreadwrite.h"
+
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
@@ -35,14 +37,29 @@ static int mpegvideo_probe(AVProbeData *p)
{
uint32_t code= -1;
int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0, res=0, sicle=0;
- int i;
+ int i, j;
uint32_t last = 0;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
switch(code){
- case SEQ_START_CODE: seq++; break;
+ case SEQ_START_CODE:
+ if (!(p->buf[i+1+3+1+2] & 0x20))
+ break;
+ j = i;
+ if (p->buf[j+8] & 2)
+ j+= 64;
+ if (j >= p->buf_size)
+ break;
+ if (p->buf[j+8] & 1)
+ j+= 64;
+ if (j >= p->buf_size)
+ break;
+ if (AV_RB24(p->buf + j + 9) & 0xFFFFFE)
+ break;
+ seq++;
+ break;
case PICTURE_START_CODE: pic++; break;
case PACK_START_CODE: pspack++; break;
case 0x1b6:
@@ -63,8 +80,8 @@ static int mpegvideo_probe(AVProbeData *p)
}
}
if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !apes && !res && slice > sicle) {
- if(vpes) return AVPROBE_SCORE_MAX/8;
- else return pic>1 ? AVPROBE_SCORE_MAX/2+1 : AVPROBE_SCORE_MAX/4; // +1 for .mpg
+ if(vpes) return AVPROBE_SCORE_EXTENSION / 4;
+ else return pic>1 ? AVPROBE_SCORE_EXTENSION + 1 : AVPROBE_SCORE_EXTENSION / 2; // +1 for .mpg
}
return 0;
}
diff --git a/ffmpeg/libavformat/mpjpeg.c b/ffmpeg/libavformat/mpjpeg.c
index 916938f..2586ea8 100644
--- a/ffmpeg/libavformat/mpjpeg.c
+++ b/ffmpeg/libavformat/mpjpeg.c
@@ -47,7 +47,6 @@ static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
snprintf(buf1, sizeof(buf1), "\r\n--%s\r\n", BOUNDARY_TAG);
avio_write(s->pb, buf1, strlen(buf1));
- avio_flush(s->pb);
return 0;
}
diff --git a/ffmpeg/libavformat/mpl2dec.c b/ffmpeg/libavformat/mpl2dec.c
index ce2061b..17b302d 100644
--- a/ffmpeg/libavformat/mpl2dec.c
+++ b/ffmpeg/libavformat/mpl2dec.c
@@ -40,10 +40,10 @@ static int mpl2_probe(AVProbeData *p)
const unsigned char *ptr_end = ptr + p->buf_size;
for (i = 0; i < 2; i++) {
- if (sscanf(ptr, "[%"PRId64"][%"PRId64"]%c", &start, &end, &c) != 3 &&
- sscanf(ptr, "[%"PRId64"][]%c", &start, &c) != 2)
+ if (sscanf(ptr, "[%"SCNd64"][%"SCNd64"]%c", &start, &end, &c) != 3 &&
+ sscanf(ptr, "[%"SCNd64"][]%c", &start, &c) != 2)
return 0;
- ptr += strcspn(ptr, "\r\n") + 1;
+ ptr += ff_subtitles_next_line(ptr);
if (ptr >= ptr_end)
return 0;
}
@@ -56,13 +56,13 @@ static int read_ts(char **line, int64_t *pts_start, int *duration)
int len;
int64_t end;
- if (sscanf(*line, "[%"PRId64"][]%c%n",
+ if (sscanf(*line, "[%"SCNd64"][]%c%n",
pts_start, &c, &len) >= 2) {
*duration = -1;
*line += len - 1;
return 0;
}
- if (sscanf(*line, "[%"PRId64"][%"PRId64"]%c%n",
+ if (sscanf(*line, "[%"SCNd64"][%"SCNd64"]%c%n",
pts_start, &end, &c, &len) >= 3) {
*duration = end - *pts_start;
*line += len - 1;
diff --git a/ffmpeg/libavformat/mpsubdec.c b/ffmpeg/libavformat/mpsubdec.c
index 2acafaa..c5bdcdb 100644
--- a/ffmpeg/libavformat/mpsubdec.c
+++ b/ffmpeg/libavformat/mpsubdec.c
@@ -37,12 +37,16 @@ static int mpsub_probe(AVProbeData *p)
const char *ptr_end = p->buf + p->buf_size;
while (ptr < ptr_end) {
- int n;
-
- if (!memcmp(ptr, "FORMAT=TIME", 11) ||
- sscanf(ptr, "FORMAT=%d", &n) == 1)
- return AVPROBE_SCORE_MAX/2;
- ptr += strcspn(ptr, "\n") + 1;
+ int inc;
+
+ if (!memcmp(ptr, "FORMAT=TIME", 11))
+ return AVPROBE_SCORE_EXTENSION;
+ if (!memcmp(ptr, "FORMAT=", 7))
+ return AVPROBE_SCORE_EXTENSION / 3;
+ inc = ff_subtitles_next_line(ptr);
+ if (!inc)
+ break;
+ ptr += inc;
}
return 0;
}
diff --git a/ffmpeg/libavformat/mtv.c b/ffmpeg/libavformat/mtv.c
index 6ffbb51..0517dd2 100644
--- a/ffmpeg/libavformat/mtv.c
+++ b/ffmpeg/libavformat/mtv.c
@@ -42,10 +42,10 @@ typedef struct MTVDemuxContext {
unsigned int audio_br; ///< bitrate of audio channel (mp3)
unsigned int img_colorfmt; ///< frame colorfmt rgb 565/555
unsigned int img_bpp; ///< frame bits per pixel
- unsigned int img_width; //
- unsigned int img_height; //
+ unsigned int img_width;
+ unsigned int img_height;
unsigned int img_segment_size; ///< size of image segment
- unsigned int video_fps; //
+ unsigned int video_fps;
unsigned int full_segment_size;
} MTVDemuxContext;
@@ -64,13 +64,13 @@ static int mtv_probe(AVProbeData *p)
if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54]))
{
if(!!AV_RL16(&p->buf[56]))
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
else
return 0;
}
if(p->buf[51] != 16)
- return AVPROBE_SCORE_MAX/4; // But we are going to assume 16bpp anyway ..
+ return AVPROBE_SCORE_EXTENSION / 2; // But we are going to assume 16bpp anyway ..
return AVPROBE_SCORE_MAX;
}
@@ -105,8 +105,8 @@ static int mtv_read_header(AVFormatContext *s)
mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
/ mtv->img_width;
}
- if(!mtv->img_height || !mtv->img_width){
- av_log(s, AV_LOG_ERROR, "width or height is invalid and I cannot calculate them from other information\n");
+ 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);
}
diff --git a/ffmpeg/libavformat/mux.c b/ffmpeg/libavformat/mux.c
index 3578a52..f01b82b 100644
--- a/ffmpeg/libavformat/mux.c
+++ b/ffmpeg/libavformat/mux.c
@@ -19,8 +19,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/* #define DEBUG */
-
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
@@ -34,6 +32,7 @@
#include "id3v2.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
@@ -238,7 +237,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
// 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;
}
@@ -275,13 +274,18 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
if (av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio)
&& FFABS(av_q2d(st->sample_aspect_ratio) - av_q2d(codec->sample_aspect_ratio)) > 0.004*av_q2d(st->sample_aspect_ratio)
) {
- av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between muxer "
- "(%d/%d) and encoder layer (%d/%d)\n",
- st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
- codec->sample_aspect_ratio.num,
- codec->sample_aspect_ratio.den);
- ret = AVERROR(EINVAL);
- goto fail;
+ if (st->sample_aspect_ratio.num != 0 &&
+ st->sample_aspect_ratio.den != 0 &&
+ codec->sample_aspect_ratio.den != 0 &&
+ codec->sample_aspect_ratio.den != 0) {
+ av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between muxer "
+ "(%d/%d) and encoder layer (%d/%d)\n",
+ st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
+ codec->sample_aspect_ratio.num,
+ codec->sample_aspect_ratio.den);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
}
break;
}
@@ -298,12 +302,12 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
}
if (codec->codec_tag) {
if (!validate_codec_tag(s, st)) {
- char tagbuf[32], cortag[32];
+ char tagbuf[32], tagbuf2[32];
av_get_codec_tag_string(tagbuf, sizeof(tagbuf), codec->codec_tag);
- av_get_codec_tag_string(cortag, sizeof(cortag), av_codec_get_tag(s->oformat->codec_tag, codec->codec_id));
+ av_get_codec_tag_string(tagbuf2, sizeof(tagbuf2), av_codec_get_tag(s->oformat->codec_tag, codec->codec_id));
av_log(s, AV_LOG_ERROR,
"Tag %s/0x%08x incompatible with output codec id '%d' (%s)\n",
- tagbuf, codec->codec_tag, codec->codec_id, cortag);
+ tagbuf, codec->codec_tag, codec->codec_id, tagbuf2);
ret = AVERROR_INVALIDDATA;
goto fail;
}
@@ -335,6 +339,8 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
/* set muxer identification string */
if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) {
av_dict_set(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0);
+ } else {
+ av_dict_set(&s->metadata, "encoder", NULL, 0);
}
if (options) {
@@ -398,6 +404,13 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
if ((ret = init_pts(s)) < 0)
return ret;
+ if (s->avoid_negative_ts < 0) {
+ if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
+ s->avoid_negative_ts = 0;
+ } else
+ s->avoid_negative_ts = 1;
+ }
+
return 0;
}
@@ -485,17 +498,52 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
}
/**
- * Move side data from payload to internal struct, call muxer, and restore
- * original packet.
+ * Make timestamps non negative, move side data from payload to internal struct, call muxer, and restore
+ * sidedata.
+ *
+ * FIXME: this function should NEVER get undefined pts/dts beside when the
+ * AVFMT_NOTIMESTAMPS is set.
+ * Those additional safety checks should be dropped once the correct checks
+ * are set in the callers.
*/
-static inline int split_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, did_split;
+ 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) {
+ s->offset = -pkt->dts;
+ s->offset_timebase = st->time_base;
+ }
+
+ if (s->offset && !offset) {
+ offset = st->mux_ts_offset =
+ av_rescale_q_rnd(s->offset,
+ s->offset_timebase,
+ st->time_base,
+ AV_ROUND_UP);
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+
+ av_assert2(pkt->dts == AV_NOPTS_VALUE || pkt->dts >= 0);
+ }
+
did_split = av_packet_split_side_data(pkt);
ret = s->oformat->write_packet(s, pkt);
+
+ if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ avio_flush(s->pb);
+
if (did_split)
av_packet_merge_side_data(pkt);
+
return ret;
}
@@ -506,6 +554,8 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
if (!pkt) {
if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
ret = s->oformat->write_packet(s, NULL);
+ if (s->flush_packets && s->pb && s->pb->error >= 0)
+ avio_flush(s->pb);
if (ret >= 0 && s->pb && s->pb->error < 0)
ret = s->pb->error;
return ret;
@@ -518,7 +568,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
return ret;
- ret = split_write_packet(s, pkt);
+ ret = write_packet(s, pkt);
if (ret >= 0 && s->pb && s->pb->error < 0)
ret = s->pb->error;
@@ -541,10 +591,13 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
return AVERROR(ENOMEM);
this_pktl->pkt = *pkt;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = NULL; // do not free original but only the copy
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
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 (s->streams[pkt->stream_index]->last_in_packet_buffer) {
next_point = &(st->last_in_packet_buffer->next);
@@ -596,7 +649,8 @@ next_non_null:
return 0;
}
-static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt)
+static int interleave_compare_dts(AVFormatContext *s, AVPacket *next,
+ AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
AVStream *st2 = s->streams[next->stream_index];
@@ -627,7 +681,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
int i, ret;
if (pkt) {
- ret = ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts);
+ ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts);
if (ret < 0)
return ret;
}
@@ -675,23 +729,6 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
st->last_in_packet_buffer = NULL;
av_freep(&pktl);
- if (s->avoid_negative_ts > 0) {
- if (out->dts != AV_NOPTS_VALUE) {
- if (!st->mux_ts_offset && out->dts < 0) {
- for (i = 0; i < s->nb_streams; i++) {
- s->streams[i]->mux_ts_offset =
- av_rescale_q_rnd(-out->dts,
- st->time_base,
- s->streams[i]->time_base,
- AV_ROUND_UP);
- }
- }
- out->dts += st->mux_ts_offset;
- }
- if (out->pts != AV_NOPTS_VALUE)
- out->pts += st->mux_ts_offset;
- }
-
return 1;
} else {
av_init_packet(out);
@@ -748,7 +785,7 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
if (ret <= 0) //FIXME cleanup needed for ret<0 ?
return ret;
- ret = split_write_packet(s, &opkt);
+ ret = write_packet(s, &opkt);
if (ret >= 0)
s->streams[opkt.stream_index]->nb_frames++;
@@ -774,7 +811,7 @@ int av_write_trailer(AVFormatContext *s)
if (!ret)
break;
- ret = split_write_packet(s, &pkt);
+ ret = write_packet(s, &pkt);
if (ret >= 0)
s->streams[pkt.stream_index]->nb_frames++;
@@ -812,3 +849,25 @@ int av_get_output_timestamp(struct AVFormatContext *s, int stream,
s->oformat->get_output_timestamp(s, stream, dts, wall);
return 0;
}
+
+int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
+ AVFormatContext *src)
+{
+ AVPacket local_pkt;
+
+ local_pkt = *pkt;
+ local_pkt.stream_index = dst_stream;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ local_pkt.pts = av_rescale_q(pkt->pts,
+ src->streams[pkt->stream_index]->time_base,
+ dst->streams[dst_stream]->time_base);
+ if (pkt->dts != AV_NOPTS_VALUE)
+ local_pkt.dts = av_rescale_q(pkt->dts,
+ src->streams[pkt->stream_index]->time_base,
+ dst->streams[dst_stream]->time_base);
+ if (pkt->duration)
+ local_pkt.duration = av_rescale_q(pkt->duration,
+ src->streams[pkt->stream_index]->time_base,
+ dst->streams[dst_stream]->time_base);
+ return av_write_frame(dst, &local_pkt);
+}
diff --git a/ffmpeg/libavformat/mvi.c b/ffmpeg/libavformat/mvi.c
index 953c182..5efc443 100644
--- a/ffmpeg/libavformat/mvi.c
+++ b/ffmpeg/libavformat/mvi.c
@@ -52,9 +52,7 @@ static int read_header(AVFormatContext *s)
if (!vst)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 2;
- vst->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!vst->codec->extradata)
+ if (ff_alloc_extradata(vst->codec, 2))
return AVERROR(ENOMEM);
version = avio_r8(pb);
@@ -96,10 +94,12 @@ static int read_header(AVFormatContext *s)
mvi->get_int = (vst->codec->width * vst->codec->height < (1 << 16)) ? avio_rl16 : avio_rl24;
mvi->audio_frame_size = ((uint64_t)mvi->audio_data_size << MVI_FRAC_BITS) / frames_count;
- if (!mvi->audio_frame_size) {
- av_log(s, AV_LOG_ERROR, "audio_frame_size is 0\n");
+ 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",
+ mvi->audio_data_size, frames_count);
return AVERROR_INVALIDDATA;
}
+
mvi->audio_size_counter = (ast->codec->sample_rate * 830 / mvi->audio_frame_size - 1) * mvi->audio_frame_size;
mvi->audio_size_left = mvi->audio_data_size;
diff --git a/ffmpeg/libavformat/mxfdec.c b/ffmpeg/libavformat/mxfdec.c
index 4580e1b..61c0cb2 100644
--- a/ffmpeg/libavformat/mxfdec.c
+++ b/ffmpeg/libavformat/mxfdec.c
@@ -43,12 +43,13 @@
* Only tracks with associated descriptors will be decoded. "Highly Desirable" SMPTE 377M D.1
*/
-//#define DEBUG
+#include <stdint.h>
#include "libavutil/aes.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/timecode.h"
#include "avformat.h"
#include "internal.h"
@@ -215,6 +216,7 @@ typedef struct {
struct AVAES *aesc;
uint8_t *local_tags;
int local_tags_count;
+ uint64_t last_partition;
uint64_t footer_partition;
KLVPacket current_klv_data;
int current_klv_index;
@@ -256,6 +258,7 @@ static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x
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_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)))
@@ -435,10 +438,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
uint64_t footer_partition;
uint32_t nb_essence_containers;
- if (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions))
- return AVERROR(ENOMEM);
-
- tmp_part = av_realloc(mxf->partitions, (mxf->partitions_count + 1) * sizeof(*mxf->partitions));
+ tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions));
if (!tmp_part)
return AVERROR(ENOMEM);
mxf->partitions = tmp_part;
@@ -565,9 +565,8 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set)
{
MXFMetadataSet **tmp;
- if (mxf->metadata_sets_count+1 >= UINT_MAX / sizeof(*mxf->metadata_sets))
- return AVERROR(ENOMEM);
- tmp = av_realloc(mxf->metadata_sets, (mxf->metadata_sets_count + 1) * sizeof(*mxf->metadata_sets));
+
+ tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets));
if (!tmp)
return AVERROR(ENOMEM);
mxf->metadata_sets = tmp;
@@ -941,6 +940,7 @@ static const MXFCodecUL mxf_intra_only_essence_container_uls[] = {
/* 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 */
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE },
};
@@ -1518,6 +1518,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
av_log(mxf->fc, AV_LOG_VERBOSE, ".");
}
av_log(mxf->fc, AV_LOG_VERBOSE, "\n");
+
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
source_track->intra_only = mxf_is_intra_only(descriptor);
container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul);
@@ -1574,11 +1575,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
st->codec->bits_per_coded_sample = descriptor->bits_per_sample;
if (descriptor->sample_rate.den > 0) {
- avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num);
st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den;
+ avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num);
} else {
- av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) found for stream #%d, time base forced to 1/48000\n",
- descriptor->sample_rate.num, descriptor->sample_rate.den, st->index);
+ av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) "
+ "found for stream #%d, time base forced to 1/48000\n",
+ descriptor->sample_rate.num, descriptor->sample_rate.den,
+ st->index);
avpriv_set_pts_info(st, 64, 1, 48000);
}
@@ -1602,11 +1605,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
}
}
if (descriptor->extradata) {
- st->codec->extradata = av_mallocz(descriptor->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata)
+ if (!ff_alloc_extradata(st->codec, descriptor->extradata_size)) {
memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size);
- } else if(st->codec->codec_id == AV_CODEC_ID_H264) {
- ff_generate_avci_extradata(st);
+ }
+ } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
+ ret = ff_generate_avci_extradata(st);
+ if (ret < 0)
+ return ret;
}
if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
/* TODO: decode timestamps */
@@ -1619,6 +1624,124 @@ fail_and_free:
return ret;
}
+static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
+{
+ int ret;
+ size_t buf_size;
+
+ if (size < 0)
+ return AVERROR(EINVAL);
+
+ buf_size = size + size/2 + 1;
+ *str = av_malloc(buf_size);
+ if (!*str)
+ return AVERROR(ENOMEM);
+
+ if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
+ av_freep(str);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxf_uid_to_str(UID uid, char **str)
+{
+ int i;
+ char *p;
+ p = *str = av_mallocz(sizeof(UID) * 2 + 4 + 1);
+ if (!p)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < sizeof(UID); i++) {
+ snprintf(p, 2 + 1, "%.2x", uid[i]);
+ p += 2;
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ snprintf(p, 1 + 1, "-");
+ p++;
+ }
+ }
+ return 0;
+}
+
+static int mxf_timestamp_to_str(uint64_t timestamp, char **str)
+{
+ struct tm time = {0};
+ time.tm_year = (timestamp >> 48) - 1900;
+ time.tm_mon = (timestamp >> 40 & 0xFF) - 1;
+ time.tm_mday = (timestamp >> 32 & 0xFF);
+ time.tm_hour = (timestamp >> 24 & 0xFF);
+ 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);
+
+ *str = av_mallocz(32);
+ if (!*str)
+ return AVERROR(ENOMEM);
+ strftime(*str, 32, "%Y-%m-%d %H:%M:%S", &time);
+
+ return 0;
+}
+
+#define SET_STR_METADATA(pb, name, str) do { \
+ if ((ret = mxf_read_utf16_string(pb, size, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+#define SET_UID_METADATA(pb, name, var, str) do { \
+ avio_read(pb, var, 16); \
+ if ((ret = mxf_uid_to_str(var, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+#define SET_TS_METADATA(pb, name, var, str) do { \
+ var = avio_rb64(pb); \
+ if ((ret = mxf_timestamp_to_str(var, &str)) < 0) \
+ return ret; \
+ av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
+} while (0)
+
+static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag, int size, UID _uid, int64_t klv_offset)
+{
+ MXFContext *mxf = arg;
+ AVFormatContext *s = mxf->fc;
+ int ret;
+ UID uid = { 0 };
+ char *str = NULL;
+ uint64_t ts;
+ switch (tag) {
+ case 0x3C01:
+ SET_STR_METADATA(pb, "company_name", str);
+ break;
+ case 0x3C02:
+ SET_STR_METADATA(pb, "product_name", str);
+ break;
+ case 0x3C04:
+ SET_STR_METADATA(pb, "product_version", str);
+ break;
+ case 0x3C05:
+ SET_UID_METADATA(pb, "product_uid", uid, str);
+ break;
+ case 0x3C06:
+ SET_TS_METADATA(pb, "modification_date", ts, str);
+ break;
+ case 0x3C08:
+ SET_STR_METADATA(pb, "application_platform", str);
+ break;
+ case 0x3C09:
+ SET_UID_METADATA(pb, "generation_uid", uid, str);
+ break;
+ case 0x3C0A:
+ SET_UID_METADATA(pb, "uid", uid, str);
+ break;
+ }
+ return 0;
+}
+
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 },
@@ -1631,6 +1754,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 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 },
@@ -1736,31 +1860,33 @@ static int mxf_parse_handle_essence(MXFContext *mxf)
if (mxf->parsing_backward) {
return mxf_seek_to_previous_partition(mxf);
- } else {
- if (!mxf->footer_partition) {
- av_dlog(mxf->fc, "no footer\n");
- return 0;
- }
+ } else if (mxf->footer_partition || mxf->last_partition){
+ uint64_t offset;
- av_dlog(mxf->fc, "seeking to footer\n");
+ offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition;
+
+ av_dlog(mxf->fc, "seeking to last partition\n");
/* remember where we were so we don't end up seeking further back than this */
mxf->last_forward_tell = avio_tell(pb);
if (!pb->seekable) {
- av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing footer\n");
+ av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
return -1;
}
- /* seek to footer partition and parse backward */
- if ((ret = avio_seek(pb, mxf->run_in + mxf->footer_partition, SEEK_SET)) < 0) {
- av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to footer @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
- mxf->run_in + mxf->footer_partition, ret);
+ /* 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",
+ 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;
@@ -1852,6 +1978,34 @@ static void mxf_handle_small_eubc(AVFormatContext *s)
mxf->edit_units_per_packet = 1920;
}
+static void mxf_read_random_index_pack(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ uint32_t length;
+ int64_t file_size;
+ KLVPacket klv;
+
+ if (!s->pb->seekable)
+ return;
+
+ file_size = avio_size(s->pb);
+ avio_seek(s->pb, file_size - 4, SEEK_SET);
+ length = avio_rb32(s->pb);
+ if (length <= 32 || length >= FFMIN(file_size, INT_MAX))
+ goto end;
+ avio_seek(s->pb, file_size - length, SEEK_SET);
+ if (klv_read_packet(&klv, s->pb) < 0 ||
+ !IS_KLV_KEY(klv.key, mxf_random_index_pack_key) ||
+ klv.length != length - 20)
+ goto end;
+
+ avio_skip(s->pb, klv.length - 12);
+ mxf->last_partition = avio_rb64(s->pb);
+
+end:
+ avio_seek(s->pb, mxf->run_in, SEEK_SET);
+}
+
static int mxf_read_header(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
@@ -1870,6 +2024,8 @@ static int mxf_read_header(AVFormatContext *s)
mxf->fc = s;
mxf->run_in = avio_tell(s->pb);
+ mxf_read_random_index_pack(s);
+
while (!url_feof(s->pb)) {
const MXFMetadataReadTableEntry *metadata;
@@ -2080,7 +2236,9 @@ static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, AVPacket *p
{
MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data;
pkt->pts = track->sample_count;
- if (codec->channels <= 0 || av_get_bits_per_sample(codec->codec_id) <= 0)
+ 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)
return AVERROR(EINVAL);
track->sample_count += pkt->size / (codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) / 8);
return 0;
@@ -2091,10 +2249,8 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
KLVPacket klv;
MXFContext *mxf = s->priv_data;
- while (!url_feof(s->pb)) {
+ while (klv_read_packet(&klv, s->pb) == 0) {
int ret;
- if (klv_read_packet(&klv, s->pb) < 0)
- return -1;
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)) {
@@ -2179,7 +2335,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
skip:
avio_skip(s->pb, klv.length);
}
- return AVERROR_EOF;
+ return url_feof(s->pb) ? AVERROR_EOF : -1;
}
static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -2306,10 +2462,19 @@ static int mxf_probe(AVProbeData *p) {
/* Must skip Run-In Sequence and search for MXF header partition pack key SMPTE 377M 5.5 */
end -= sizeof(mxf_header_partition_pack_key);
- for (; bufp < end; bufp++) {
- if (IS_KLV_KEY(bufp, mxf_header_partition_pack_key))
- return AVPROBE_SCORE_MAX;
+
+ for (; bufp < end;) {
+ if (!((bufp[13] - 1) & 0xF2)){
+ if (AV_RN32(bufp ) == AV_RN32(mxf_header_partition_pack_key ) &&
+ AV_RN32(bufp+ 4) == AV_RN32(mxf_header_partition_pack_key+ 4) &&
+ AV_RN32(bufp+ 8) == AV_RN32(mxf_header_partition_pack_key+ 8) &&
+ AV_RN16(bufp+12) == AV_RN16(mxf_header_partition_pack_key+12))
+ return AVPROBE_SCORE_MAX;
+ bufp ++;
+ } else
+ bufp += 10;
}
+
return 0;
}
@@ -2322,6 +2487,7 @@ 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;
@@ -2336,9 +2502,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 ((ret = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0)
- return ret;
+ if ((ret64 = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0)
+ return ret64;
ff_update_cur_dts(s, st, sample_time);
+ mxf->current_edit_unit = sample_time;
} else {
t = &mxf->index_tables[0];
diff --git a/ffmpeg/libavformat/mxfenc.c b/ffmpeg/libavformat/mxfenc.c
index cf9b77d..5e77a3f 100644
--- a/ffmpeg/libavformat/mxfenc.c
+++ b/ffmpeg/libavformat/mxfenc.c
@@ -30,8 +30,7 @@
* SMPTE RP224: Registry of SMPTE Universal Labels
*/
-//#define DEBUG
-
+#include <inttypes.h>
#include <math.h>
#include <time.h>
@@ -43,6 +42,7 @@
#include "libavcodec/dnxhddata.h"
#include "audiointerleave.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "mxf.h"
#include "config.h"
@@ -76,6 +76,7 @@ typedef struct {
int temporal_reordering;
AVRational aspect_ratio; ///< display aspect ratio
int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing
+ int video_bit_rate;
} MXFStreamContext;
typedef struct {
@@ -976,13 +977,14 @@ static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st)
{
AVIOContext *pb = s->pb;
+ MXFStreamContext *sc = st->priv_data;
int profile_and_level = (st->codec->profile<<4) | st->codec->level;
mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5);
// bit rate
mxf_write_local_tag(pb, 4, 0x8000);
- avio_wb32(pb, st->codec->bit_rate);
+ avio_wb32(pb, sc->video_bit_rate);
// profile and level
mxf_write_local_tag(pb, 1, 0x8007);
@@ -1295,13 +1297,12 @@ static void mxf_write_klv_fill(AVFormatContext *s)
avio_write(s->pb, klv_fill_key, 16);
pad -= 16 + 4;
klv_encode_ber4_length(s->pb, pad);
- for (; pad; pad--)
- avio_w8(s->pb, 0);
+ ffio_fill(s->pb, 0, pad);
av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
}
}
-static void mxf_write_partition(AVFormatContext *s, int bodysid,
+static int mxf_write_partition(AVFormatContext *s, int bodysid,
int indexsid,
const uint8_t *key, int write_metadata)
{
@@ -1310,6 +1311,7 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid,
int64_t header_byte_count_offset;
unsigned index_byte_count = 0;
uint64_t partition_offset = avio_tell(pb);
+ int err;
if (!mxf->edit_unit_byte_count && mxf->edit_units_count)
index_byte_count = 85 + 12+(s->nb_streams+1)*6 +
@@ -1324,10 +1326,11 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid,
}
if (!memcmp(key, body_partition_key, 16)) {
- mxf->body_partition_offset =
- av_realloc(mxf->body_partition_offset,
- (mxf->body_partitions_count+1)*
- sizeof(*mxf->body_partition_offset));
+ if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1,
+ sizeof(*mxf->body_partition_offset))) < 0) {
+ mxf->body_partitions_count = 0;
+ return err;
+ }
mxf->body_partition_offset[mxf->body_partitions_count++] = partition_offset;
}
@@ -1392,6 +1395,8 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid,
}
avio_flush(pb);
+
+ return 0;
}
static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st,
@@ -1655,7 +1660,7 @@ static void mxf_gen_umid(AVFormatContext *s)
AV_WB64(mxf->umid , umid);
AV_WB64(mxf->umid+8, umid>>8);
- mxf->instance_number = seed;
+ mxf->instance_number = seed & 0xFFFFFF;
}
static int mxf_write_header(AVFormatContext *s)
@@ -1705,14 +1710,15 @@ static int mxf_write_header(AVFormatContext *s)
ret = av_timecode_init(&mxf->tc, rate, 0, 0, s);
if (ret < 0)
return ret;
+ sc->video_bit_rate = st->codec->bit_rate ? st->codec->bit_rate : st->codec->rc_max_rate;
if (s->oformat == &ff_mxf_d10_muxer) {
- if (st->codec->bit_rate == 50000000) {
+ if (sc->video_bit_rate == 50000000) {
if (mxf->time_base.den == 25) sc->index = 3;
else sc->index = 5;
- } else if (st->codec->bit_rate == 40000000) {
+ } else if (sc->video_bit_rate == 40000000) {
if (mxf->time_base.den == 25) sc->index = 7;
else sc->index = 9;
- } else if (st->codec->bit_rate == 30000000) {
+ } else if (sc->video_bit_rate == 30000000) {
if (mxf->time_base.den == 25) sc->index = 11;
else sc->index = 13;
} else {
@@ -1721,7 +1727,7 @@ static int mxf_write_header(AVFormatContext *s)
}
mxf->edit_unit_byte_count = KAG_SIZE; // system element
- mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)st->codec->bit_rate *
+ mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)sc->video_bit_rate *
mxf->time_base.num / (8*mxf->time_base.den);
mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
mxf->edit_unit_byte_count += 16 + 4 + 4 + spf->samples_per_frame[0]*8*4;
@@ -1855,7 +1861,8 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- int packet_size = (uint64_t)st->codec->bit_rate*mxf->time_base.num /
+ MXFStreamContext *sc = st->priv_data;
+ int packet_size = (uint64_t)sc->video_bit_rate*mxf->time_base.num /
(8*mxf->time_base.den); // frame size
int pad;
@@ -1871,13 +1878,11 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke
avio_write(s->pb, klv_fill_key, 16);
pad -= 16 + 4;
klv_encode_ber4_length(s->pb, pad);
- for (; pad; pad--)
- avio_w8(s->pb, 0);
+ ffio_fill(s->pb, 0, pad);
av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
} else {
av_log(s, AV_LOG_WARNING, "cannot fill d-10 video packet\n");
- for (; pad > 0; pad--)
- avio_w8(s->pb, 0);
+ ffio_fill(s->pb, 0, pad);
}
}
@@ -1920,13 +1925,14 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *st = s->streams[pkt->stream_index];
MXFStreamContext *sc = st->priv_data;
MXFIndexEntry ie = {0};
+ int err;
if (!mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) {
- mxf->index_entries = av_realloc(mxf->index_entries,
- (mxf->edit_units_count + EDIT_UNITS_PER_BODY)*sizeof(*mxf->index_entries));
- if (!mxf->index_entries) {
+ if ((err = av_reallocp_array(&mxf->index_entries, mxf->edit_units_count
+ + EDIT_UNITS_PER_BODY, sizeof(*mxf->index_entries))) < 0) {
+ mxf->edit_units_count = 0;
av_log(s, AV_LOG_ERROR, "could not allocate index entries\n");
- return -1;
+ return err;
}
}
@@ -1949,11 +1955,13 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
if (!mxf->header_written) {
if (mxf->edit_unit_byte_count) {
- mxf_write_partition(s, 1, 2, header_open_partition_key, 1);
+ if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
+ return err;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
} else {
- mxf_write_partition(s, 0, 0, header_open_partition_key, 1);
+ if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0)
+ return err;
}
mxf->header_written = 1;
}
@@ -1963,8 +1971,8 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
(!mxf->edit_units_count || mxf->edit_units_count > EDIT_UNITS_PER_BODY) &&
!(ie.flags & 0x33)) { // I frame, Gop start
mxf_write_klv_fill(s);
- mxf_write_partition(s, 1, 2, body_partition_key, 0);
-
+ if ((err = mxf_write_partition(s, 1, 2, body_partition_key, 0)) < 0)
+ return err;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
}
@@ -2033,16 +2041,18 @@ static int mxf_write_footer(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
+ int err;
mxf->duration = mxf->last_indexed_edit_unit + mxf->edit_units_count;
mxf_write_klv_fill(s);
mxf->footer_partition_offset = avio_tell(pb);
if (mxf->edit_unit_byte_count) { // no need to repeat index
- mxf_write_partition(s, 0, 0, footer_partition_key, 0);
+ if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0)
+ return err;
} else {
- mxf_write_partition(s, 0, 2, footer_partition_key, 0);
-
+ if ((err = mxf_write_partition(s, 0, 2, footer_partition_key, 0)) < 0)
+ return err;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
}
@@ -2053,11 +2063,13 @@ static int mxf_write_footer(AVFormatContext *s)
if (s->pb->seekable) {
avio_seek(pb, 0, SEEK_SET);
if (mxf->edit_unit_byte_count) {
- mxf_write_partition(s, 1, 2, header_closed_partition_key, 1);
+ if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
+ return err;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
} else {
- mxf_write_partition(s, 0, 0, header_closed_partition_key, 1);
+ if ((err = mxf_write_partition(s, 0, 0, header_closed_partition_key, 1)) < 0)
+ return err;
}
}
diff --git a/ffmpeg/libavformat/mxg.c b/ffmpeg/libavformat/mxg.c
index 604be78..b2b5b86 100644
--- a/ffmpeg/libavformat/mxg.c
+++ b/ffmpeg/libavformat/mxg.c
@@ -20,6 +20,7 @@
*/
#include "libavutil/channel_layout.h"
+#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/mjpeg.h"
#include "avformat.h"
@@ -74,7 +75,7 @@ static int mxg_read_header(AVFormatContext *s)
static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end)
{
for (; p < end - 3; p += 4) {
- uint32_t x = *(uint32_t*)p;
+ uint32_t x = AV_RN32(p);
if (x & (~(x+0x01010101)) & 0x80808080) {
if (p[0] == 0xff) {
@@ -171,7 +172,9 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->pts = pkt->dts = mxg->dts;
pkt->stream_index = 0;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
pkt->size = mxg->buffer_ptr - mxg->soi_ptr;
@@ -212,7 +215,9 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8);
pkt->stream_index = 1;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
pkt->size = size - 14;
diff --git a/ffmpeg/libavformat/network.c b/ffmpeg/libavformat/network.c
index ceed719..5e2bcf8 100644
--- a/ffmpeg/libavformat/network.c
+++ b/ffmpeg/libavformat/network.c
@@ -1,37 +1,38 @@
/*
- * Copyright (c) 2007 The Libav Project
+ * Copyright (c) 2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * 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/avutil.h"
+#include <fcntl.h>
#include "network.h"
+#include "url.h"
#include "libavcodec/internal.h"
+#include "libavutil/avutil.h"
#include "libavutil/mem.h"
-#include "url.h"
#include "libavutil/time.h"
#if HAVE_THREADS
#if HAVE_PTHREADS
#include <pthread.h>
#elif HAVE_OS2THREADS
-#include "libavcodec/os2threads.h"
+#include "compat/os2threads.h"
#else
-#include "libavcodec/w32pthreads.h"
+#include "compat/w32pthreads.h"
#endif
#endif
@@ -40,7 +41,6 @@
static int openssl_init;
#if HAVE_THREADS
#include <openssl/crypto.h>
-#include "libavutil/avutil.h"
pthread_mutex_t *openssl_mutexes;
static void openssl_lock(int mode, int type, const char *file, int line)
{
@@ -156,12 +156,12 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt
int64_t wait_start = 0;
while (1) {
+ if (ff_check_interrupt(int_cb))
+ return AVERROR_EXIT;
ret = ff_network_wait_fd(fd, write);
if (ret != AVERROR(EAGAIN))
return ret;
- if (ff_check_interrupt(int_cb))
- return AVERROR_EXIT;
- if (timeout) {
+ if (timeout > 0) {
if (!wait_start)
wait_start = av_gettime();
else if (av_gettime() - wait_start > timeout)
@@ -212,3 +212,176 @@ int ff_is_multicast_address(struct sockaddr *addr)
return 0;
}
+
+static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
+ AVIOInterruptCB *cb)
+{
+ int runs = timeout / POLLING_TIME;
+ int ret = 0;
+
+ do {
+ if (ff_check_interrupt(cb))
+ return AVERROR_EXIT;
+ ret = poll(p, nfds, POLLING_TIME);
+ if (ret != 0)
+ break;
+ } while (timeout <= 0 || runs-- > 0);
+
+ if (!ret)
+ return AVERROR(ETIMEDOUT);
+ if (ret < 0)
+ return AVERROR(errno);
+ return ret;
+}
+
+int ff_socket(int af, int type, int proto)
+{
+ int fd;
+
+#ifdef SOCK_CLOEXEC
+ fd = socket(af, type | SOCK_CLOEXEC, proto);
+ if (fd == -1 && errno == EINVAL)
+#endif
+ {
+ fd = socket(af, type, proto);
+#if HAVE_FCNTL
+ if (fd != -1) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n");
+ }
+#endif
+ }
+ return fd;
+}
+
+int ff_listen_bind(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout, URLContext *h)
+{
+ int ret;
+ int reuse = 1;
+ struct pollfd lp = { fd, POLLIN, 0 };
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+ av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
+ }
+ ret = bind(fd, addr, addrlen);
+ if (ret)
+ return ff_neterrno();
+
+ ret = listen(fd, 1);
+ if (ret)
+ return ff_neterrno();
+
+ ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
+ if (ret < 0)
+ return ret;
+
+ ret = accept(fd, NULL, NULL);
+ if (ret < 0)
+ return ff_neterrno();
+
+ closesocket(fd);
+
+ if (ff_socket_nonblock(ret, 1) < 0)
+ av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
+
+ return ret;
+}
+
+int ff_listen_connect(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout, URLContext *h,
+ int will_try_next)
+{
+ struct pollfd p = {fd, POLLOUT, 0};
+ int ret;
+ socklen_t optlen;
+
+ 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();
+ switch (ret) {
+ case AVERROR(EINTR):
+ if (ff_check_interrupt(&h->interrupt_callback))
+ return AVERROR_EXIT;
+ continue;
+ case AVERROR(EINPROGRESS):
+ case AVERROR(EAGAIN):
+ ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
+ if (ret < 0)
+ return ret;
+ optlen = sizeof(ret);
+ if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
+ ret = AVUNERROR(ff_neterrno());
+ if (ret != 0) {
+ char errbuf[100];
+ ret = AVERROR(ret);
+ av_strerror(ret, errbuf, sizeof(errbuf));
+ if (will_try_next)
+ av_log(h, AV_LOG_WARNING,
+ "Connection to %s failed (%s), trying next address\n",
+ h->filename, errbuf);
+ else
+ av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
+ h->filename, errbuf);
+ }
+ default:
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int match_host_pattern(const char *pattern, const char *hostname)
+{
+ int len_p, len_h;
+ if (!strcmp(pattern, "*"))
+ return 1;
+ // Skip a possible *. at the start of the pattern
+ if (pattern[0] == '*')
+ pattern++;
+ if (pattern[0] == '.')
+ pattern++;
+ len_p = strlen(pattern);
+ len_h = strlen(hostname);
+ if (len_p > len_h)
+ return 0;
+ // Simply check if the end of hostname is equal to 'pattern'
+ if (!strcmp(pattern, &hostname[len_h - len_p])) {
+ if (len_h == len_p)
+ return 1; // Exact match
+ if (hostname[len_h - len_p - 1] == '.')
+ return 1; // The matched substring is a domain and not just a substring of a domain
+ }
+ return 0;
+}
+
+int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
+{
+ char *buf, *start;
+ int ret = 0;
+ if (!no_proxy)
+ return 0;
+ if (!hostname)
+ return 0;
+ buf = av_strdup(no_proxy);
+ if (!buf)
+ return 0;
+ start = buf;
+ while (start) {
+ char *sep, *next = NULL;
+ start += strspn(start, " ,");
+ sep = start + strcspn(start, " ,");
+ if (*sep) {
+ next = sep + 1;
+ *sep = '\0';
+ }
+ if (match_host_pattern(start, hostname)) {
+ ret = 1;
+ break;
+ }
+ start = next;
+ }
+ av_free(buf);
+ return ret;
+}
diff --git a/ffmpeg/libavformat/network.h b/ffmpeg/libavformat/network.h
index f8b4dee..c60e142 100644
--- a/ffmpeg/libavformat/network.h
+++ b/ffmpeg/libavformat/network.h
@@ -28,6 +28,7 @@
#include "libavutil/error.h"
#include "os_support.h"
#include "avio.h"
+#include "url.h"
#if HAVE_UNISTD_H
#include <unistd.h>
@@ -89,7 +90,7 @@ int ff_network_wait_fd(int fd, int write);
* @fd Socket descriptor
* @write Set 1 to wait for socket able to be read, 0 to be written
* @timeout Timeout interval, in microseconds. Actual precision is 100000 mcs, due to ff_network_wait_fd usage
- * @param int_cb Interrupt callback, is checked after each ff_network_wait_fd call
+ * @param int_cb Interrupt callback, is checked before each ff_network_wait_fd call
* @return 0 if data can be read/written, AVERROR(ETIMEDOUT) if timeout expired, or negative error code
*/
int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb);
@@ -222,4 +223,45 @@ const char *ff_gai_strerror(int ecode);
int ff_is_multicast_address(struct sockaddr *addr);
+#define POLLING_TIME 100 /// Time in milliseconds between interrupt check
+
+/**
+ * Bind to a file descriptor and poll for a connection.
+ *
+ * @param fd First argument of bind().
+ * @param addr Second argument of bind().
+ * @param addrlen Third argument of bind().
+ * @param timeout Polling timeout in milliseconds.
+ * @param h URLContext providing interrupt check
+ * callback and logging context.
+ * @return A non-blocking file descriptor on success
+ * or an AVERROR on failure.
+ */
+int ff_listen_bind(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout,
+ URLContext *h);
+
+/**
+ * Connect to a file descriptor and poll for result.
+ *
+ * @param fd First argument of connect(),
+ * will be set as non-blocking.
+ * @param addr Second argument of connect().
+ * @param addrlen Third argument of connect().
+ * @param timeout Polling timeout in milliseconds.
+ * @param h URLContext providing interrupt check
+ * callback and logging context.
+ * @param will_try_next Whether the caller will try to connect to another
+ * address for the same host name, affecting the form of
+ * logged errors.
+ * @return 0 on success, AVERROR on failure.
+ */
+int ff_listen_connect(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout,
+ URLContext *h, int will_try_next);
+
+int ff_http_match_no_proxy(const char *no_proxy, const char *hostname);
+
+int ff_socket(int domain, int type, int protocol);
+
#endif /* AVFORMAT_NETWORK_H */
diff --git a/ffmpeg/libavformat/nistspheredec.c b/ffmpeg/libavformat/nistspheredec.c
index c09df9c..2c96686 100644
--- a/ffmpeg/libavformat/nistspheredec.c
+++ b/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/ffmpeg/libavformat/noproxy-test.c b/ffmpeg/libavformat/noproxy-test.c
index a156620..4524764 100644
--- a/ffmpeg/libavformat/noproxy-test.c
+++ b/ffmpeg/libavformat/noproxy-test.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "internal.h"
+#include "network.h"
static void test(const char *pattern, const char *host)
{
diff --git a/ffmpeg/libavformat/nsvdec.c b/ffmpeg/libavformat/nsvdec.c
index bcc2180..4a749a2 100644
--- a/ffmpeg/libavformat/nsvdec.c
+++ b/ffmpeg/libavformat/nsvdec.c
@@ -2,6 +2,8 @@
* NSV demuxer
* Copyright (c) 2004 The FFmpeg Project
*
+ * first version by Francois Revol <revol@free.fr>
+ *
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
@@ -26,10 +28,6 @@
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
-//#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!!
-#define CHECK_SUBSEQUENT_NSVS
-//#define DISABLE_AUDIO
-
/* max bytes to crawl for trying to resync
* stupid streaming servers don't start at chunk boundaries...
*/
@@ -37,7 +35,6 @@
#define NSV_MAX_RESYNC_TRIES 300
/*
- * First version by Francois Revol - revol@free.fr
* References:
* (1) http://www.multimedia.cx/nsv-format.txt
* seems someone came to the same conclusions as me, and updated it:
@@ -369,25 +366,6 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb));
-#ifdef DEBUG_DUMP_INDEX
-#define V(v) ((v<0x20 || v > 127)?'.':v)
- /* dump index */
- av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries);
- av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries);
- for (i = 0; i < table_entries; i++) {
- unsigned char b[8];
- avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET);
- avio_read(pb, b, 8);
- av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
- "%c%c%c%c%c%c%c%c\n",
- nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i],
- b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
- V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) );
- }
- //avio_seek(pb, size, SEEK_SET); /* go back to end of header */
-#undef V
-#endif
-
avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */
if (url_feof(pb))
@@ -478,7 +456,6 @@ static int nsv_parse_NSVs_header(AVFormatContext *s)
}
}
if (atag != T_NONE) {
-#ifndef DISABLE_AUDIO
st = avformat_new_stream(s, NULL);
if (!st)
goto fail;
@@ -498,15 +475,12 @@ static int nsv_parse_NSVs_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, framerate.num*1000);
st->start_time = 0;
st->duration = (int64_t)nsv->duration * framerate.num;
-#endif
}
-#ifdef CHECK_SUBSEQUENT_NSVS
} else {
if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
av_dlog(s, "NSV NSVs header values differ from the first one!!!\n");
//return -1;
}
-#endif /* CHECK_SUBSEQUENT_NSVS */
}
nsv->state = NSV_HAS_READ_NSVS;
@@ -785,7 +759,7 @@ static int nsv_probe(AVProbeData *p)
}
/* so we'll have more luck on extension... */
if (av_match_ext(p->filename, "nsv"))
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
/* FIXME: add mime-type check */
return score;
}
diff --git a/ffmpeg/libavformat/nullenc.c b/ffmpeg/libavformat/nullenc.c
index 7da297b..7c08c39 100644
--- a/ffmpeg/libavformat/nullenc.c
+++ b/ffmpeg/libavformat/nullenc.c
@@ -32,5 +32,5 @@ AVOutputFormat ff_null_muxer = {
.audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),
.video_codec = AV_CODEC_ID_RAWVIDEO,
.write_packet = null_write_packet,
- .flags = AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE,
};
diff --git a/ffmpeg/libavformat/nut.c b/ffmpeg/libavformat/nut.c
index 2abe969..8b8a4cb 100644
--- a/ffmpeg/libavformat/nut.c
+++ b/ffmpeg/libavformat/nut.c
@@ -26,125 +26,138 @@
#include "internal.h"
const AVCodecTag ff_nut_subtitle_tags[] = {
- { AV_CODEC_ID_TEXT , MKTAG('U', 'T', 'F', '8') },
- { AV_CODEC_ID_SSA , MKTAG('S', 'S', 'A', 0 ) },
- { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('D', 'V', 'D', 'S') },
- { AV_CODEC_ID_DVB_SUBTITLE, MKTAG('D', 'V', 'B', 'S') },
- { AV_CODEC_ID_DVB_TELETEXT, MKTAG('D', 'V', 'B', 'T') },
- { AV_CODEC_ID_NONE , 0 }
+ { AV_CODEC_ID_TEXT, MKTAG('U', 'T', 'F', '8') },
+ { AV_CODEC_ID_SSA, MKTAG('S', 'S', 'A', 0 ) },
+ { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('D', 'V', 'D', 'S') },
+ { AV_CODEC_ID_DVB_SUBTITLE, MKTAG('D', 'V', 'B', 'S') },
+ { AV_CODEC_ID_DVB_TELETEXT, MKTAG('D', 'V', 'B', 'T') },
+ { AV_CODEC_ID_NONE, 0 }
};
const AVCodecTag ff_nut_data_tags[] = {
- { AV_CODEC_ID_TEXT , MKTAG('U', 'T', 'F', '8') },
- { AV_CODEC_ID_NONE , 0 }
+ { AV_CODEC_ID_TEXT, MKTAG('U', 'T', 'F', '8') },
+ { AV_CODEC_ID_NONE, 0 }
};
const AVCodecTag ff_nut_video_tags[] = {
- { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 'A') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 0 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 'A') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 0 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '1', '1', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '1', 'W', '0') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '0', 'W', '1') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '4', 'B', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', 'B', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48 ) },
- { 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(64 , 'R', 'B', '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 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 10 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 12 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 11 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 12 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 10 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 12 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 0 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 14 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 11 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 14 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 10 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 14 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 0 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 8 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 8 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 8 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0 , 8 ) },
+ { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 'A') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 0 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 'A') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 0 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '1', '1', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '1', 'W', '0') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '0', 'W', '1') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '4', 'B', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', 'B', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48 ) },
+ { 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(64 , 'R', 'B', '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 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 10 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0 , 8 ) },
+
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 0, '1', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 11, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 10, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 0, '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 9 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 0 , '1', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 9 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 11 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 9 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 10 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 9 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 0 , '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '1', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 11, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 10, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 10 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '1', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 10 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 10 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 10 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '1', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 11, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 10, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '4', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 16 ) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 8) },
- { AV_CODEC_ID_NONE , 0 }
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 9, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 12) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 14) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '3', 'G') },
+
+ { AV_CODEC_ID_NONE, 0 }
};
static const AVCodecTag nut_audio_extra_tags[] = {
@@ -186,45 +199,57 @@ const AVCodecTag * const ff_nut_codec_tags[] = {
ff_codec_bmp_tags, ff_codec_wav_tags, nut_audio_extra_tags, ff_nut_data_tags, 0
};
-void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val){
+void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val)
+{
int i;
- for(i=0; i<nut->avf->nb_streams; i++){
- nut->stream[i].last_pts= av_rescale_rnd(
- val,
- time_base.num * (int64_t)nut->stream[i].time_base->den,
- time_base.den * (int64_t)nut->stream[i].time_base->num,
- AV_ROUND_DOWN);
- }
+ for (i = 0; i < nut->avf->nb_streams; i++)
+ nut->stream[i].last_pts =
+ av_rescale_rnd(val,
+ time_base.num * (int64_t)nut->stream[i].time_base->den,
+ time_base.den * (int64_t)nut->stream[i].time_base->num,
+ AV_ROUND_DOWN);
}
-int64_t ff_lsb2full(StreamContext *stream, int64_t lsb){
- int64_t mask = (1ULL<<stream->msb_pts_shift)-1;
- int64_t delta= stream->last_pts - mask/2;
- return ((lsb - delta)&mask) + delta;
+int64_t ff_lsb2full(StreamContext *stream, int64_t lsb)
+{
+ int64_t mask = (1ULL << stream->msb_pts_shift) - 1;
+ int64_t delta = stream->last_pts - mask / 2;
+ return ((lsb - delta) & mask) + delta;
}
-int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b){
+int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b)
+{
return ((a->pos - b->pos) >> 32) - ((b->pos - a->pos) >> 32);
}
-int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b){
+int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b)
+{
return ((a->ts - b->ts) >> 32) - ((b->ts - a->ts) >> 32);
}
-void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){
- Syncpoint *sp= av_mallocz(sizeof(Syncpoint));
+int ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts)
+{
+ Syncpoint *sp = av_mallocz(sizeof(Syncpoint));
struct AVTreeNode *node = av_tree_node_alloc();
+ if (!sp || !node) {
+ av_freep(&sp);
+ av_freep(&node);
+ return AVERROR(ENOMEM);
+ }
+
nut->sp_count++;
- sp->pos= pos;
- sp->back_ptr= back_ptr;
- sp->ts= ts;
+ sp->pos = pos;
+ sp->back_ptr = back_ptr;
+ sp->ts = ts;
av_tree_insert(&nut->syncpoints, sp, (void *) ff_nut_sp_pos_cmp, &node);
- if(node){
+ if (node) {
av_free(sp);
av_free(node);
}
+
+ return 0;
}
static int enu_free(void *opaque, void *elem)
@@ -240,13 +265,13 @@ void ff_nut_free_sp(NUTContext *nut)
}
const Dispositions ff_nut_dispositions[] = {
- {"default" , AV_DISPOSITION_DEFAULT},
- {"dub" , AV_DISPOSITION_DUB},
- {"original" , AV_DISPOSITION_ORIGINAL},
- {"comment" , AV_DISPOSITION_COMMENT},
- {"lyrics" , AV_DISPOSITION_LYRICS},
- {"karaoke" , AV_DISPOSITION_KARAOKE},
- {"" , 0}
+ { "default", AV_DISPOSITION_DEFAULT },
+ { "dub", AV_DISPOSITION_DUB },
+ { "original", AV_DISPOSITION_ORIGINAL },
+ { "comment", AV_DISPOSITION_COMMENT },
+ { "lyrics", AV_DISPOSITION_LYRICS },
+ { "karaoke", AV_DISPOSITION_KARAOKE },
+ { "", 0 }
};
const AVMetadataConv ff_nut_metadata_conv[] = {
diff --git a/ffmpeg/libavformat/nut.h b/ffmpeg/libavformat/nut.h
index ab31c27..18b688a 100644
--- a/ffmpeg/libavformat/nut.h
+++ b/ffmpeg/libavformat/nut.h
@@ -22,9 +22,6 @@
#ifndef AVFORMAT_NUT_H
#define AVFORMAT_NUT_H
-//#include <limits.h>
-//#include "libavutil/adler32.h"
-//#include "libavcodec/mpegaudio.h"
#include "avformat.h"
#include "internal.h"
#include "metadata.h"
@@ -39,6 +36,8 @@
#define MAX_DISTANCE (1024*32-1)
+#define NUT_VERSION 3
+
typedef enum{
FLAG_KEY = 1, ///<if set, frame is keyframe
FLAG_EOR = 2, ///<if set, stream has no relevance on presentation. (EOR)
@@ -105,6 +104,8 @@ 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[];
@@ -123,7 +124,7 @@ void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val);
int64_t ff_lsb2full(StreamContext *stream, int64_t lsb);
int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b);
int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b);
-void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts);
+int ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts);
void ff_nut_free_sp(NUTContext *nut);
extern const Dispositions ff_nut_dispositions[];
diff --git a/ffmpeg/libavformat/nutdec.c b/ffmpeg/libavformat/nutdec.c
index 8896518..ba9ff02 100644
--- a/ffmpeg/libavformat/nutdec.c
+++ b/ffmpeg/libavformat/nutdec.c
@@ -196,7 +196,7 @@ static int nut_probe(AVProbeData *p)
tmp = ffio_read_varlen(bc); \
if (!(check)) { \
av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \
- return -1; \
+ return AVERROR_INVALIDDATA; \
} \
dst = tmp; \
} while (0)
@@ -206,7 +206,7 @@ static int skip_reserved(AVIOContext *bc, int64_t pos)
pos -= avio_tell(bc);
if (pos < 0) {
avio_seek(bc, pos, SEEK_CUR);
- return -1;
+ return AVERROR_INVALIDDATA;
} else {
while (pos--)
avio_r8(bc);
@@ -226,7 +226,16 @@ static int decode_main_header(NUTContext *nut)
end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);
end += avio_tell(bc);
- GET_V(tmp, tmp >= 2 && tmp <= 3);
+ tmp = ffio_read_varlen(bc);
+ if (tmp < 2 && tmp > NUT_VERSION) {
+ 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);
nut->max_distance = ffio_read_varlen(bc);
@@ -237,6 +246,8 @@ static int decode_main_header(NUTContext *nut)
GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational));
nut->time_base = av_malloc(nut->time_base_count * sizeof(AVRational));
+ if (!nut->time_base)
+ return AVERROR(ENOMEM);
for (i = 0; i < nut->time_base_count; i++) {
GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31));
@@ -332,7 +343,9 @@ static int decode_main_header(NUTContext *nut)
return AVERROR_INVALIDDATA;
}
- nut->stream = av_mallocz(sizeof(StreamContext) * stream_count);
+ nut->stream = av_calloc(stream_count, sizeof(StreamContext));
+ if (!nut->stream)
+ return AVERROR(ENOMEM);
for (i = 0; i < stream_count; i++)
avformat_new_stream(s, NULL);
@@ -389,7 +402,7 @@ static int decode_stream_header(NUTContext *nut)
break;
default:
av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class);
- return -1;
+ return AVERROR(ENOSYS);
}
if (class < 3 && st->codec->codec_id == AV_CODEC_ID_NONE)
av_log(s, AV_LOG_ERROR,
@@ -405,9 +418,8 @@ static int decode_stream_header(NUTContext *nut)
GET_V(st->codec->extradata_size, tmp < (1 << 30));
if (st->codec->extradata_size) {
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- avio_read(bc, st->codec->extradata, st->codec->extradata_size);
+ if (ff_get_extradata(st->codec, bc, st->codec->extradata_size) < 0)
+ return AVERROR(ENOMEM);
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -418,7 +430,7 @@ static int decode_stream_header(NUTContext *nut)
if ((!st->sample_aspect_ratio.num) != (!st->sample_aspect_ratio.den)) {
av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n",
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
- return -1;
+ return AVERROR_INVALIDDATA;
}
ffio_read_varlen(bc); /* csp type */
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -429,7 +441,7 @@ static int decode_stream_header(NUTContext *nut)
if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
av_log(s, AV_LOG_ERROR,
"stream header %d checksum mismatch\n", stream_id);
- return -1;
+ return AVERROR_INVALIDDATA;
}
stc->time_base = &nut->time_base[stc->time_base_id];
avpriv_set_pts_info(s->streams[stream_id], 63, stc->time_base->num,
@@ -537,7 +549,7 @@ static int decode_info_header(NUTContext *nut)
if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
return 0;
}
@@ -548,6 +560,7 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
AVIOContext *bc = s->pb;
int64_t end;
uint64_t tmp;
+ int ret;
nut->last_syncpoint_pos = avio_tell(bc) - 8;
@@ -569,7 +582,9 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
*ts = tmp / nut->time_base_count *
av_q2d(nut->time_base[tmp % nut->time_base_count]) * AV_TIME_BASE;
- ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts);
+
+ if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts)) < 0)
+ return ret;
return 0;
}
@@ -580,14 +595,8 @@ static int64_t find_duration(NUTContext *nut, int64_t filesize)
AVFormatContext *s = nut->avf;
int64_t duration = 0;
- int64_t pos = FFMAX(0, filesize - 2*nut->max_distance);
- for(;;){
- int64_t ts = nut_read_timestamp(s, -1, &pos, INT64_MAX);
- if(ts < 0)
- break;
- duration = FFMAX(duration, ts);
- pos++;
- }
+ ff_find_last_ts(s, -1, &duration, NULL, nut_read_timestamp);
+
if(duration > 0)
s->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
return duration;
@@ -601,8 +610,9 @@ static int find_and_decode_index(NUTContext *nut)
int i, j, syncpoint_count;
int64_t filesize = avio_size(bc);
int64_t *syncpoints;
+ uint64_t max_pts;
int8_t *has_keyframe;
- int ret = -1;
+ int ret = AVERROR_INVALIDDATA;
if(filesize <= 0)
return -1;
@@ -614,16 +624,25 @@ static int find_and_decode_index(NUTContext *nut)
if(s->duration<=0)
s->duration = find_duration(nut, filesize);
- return -1;
+ return ret;
}
end = get_packetheader(nut, bc, 1, INDEX_STARTCODE);
end += avio_tell(bc);
- ffio_read_varlen(bc); // max_pts
+ max_pts = ffio_read_varlen(bc);
+ s->duration = av_rescale_q(max_pts / nut->time_base_count,
+ nut->time_base[max_pts % nut->time_base_count],
+ AV_TIME_BASE_Q);
+ s->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
+
GET_V(syncpoint_count, tmp < INT_MAX / 8 && tmp > 0);
- syncpoints = av_malloc(sizeof(int64_t) * syncpoint_count);
- has_keyframe = av_malloc(sizeof(int8_t) * (syncpoint_count + 1));
+ syncpoints = av_malloc_array(syncpoint_count, sizeof(int64_t));
+ has_keyframe = av_malloc_array(syncpoint_count + 1, sizeof(int8_t));
+ if (!syncpoints || !has_keyframe) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
for (i = 0; i < syncpoint_count; i++) {
syncpoints[i] = ffio_read_varlen(bc);
if (syncpoints[i] <= 0)
@@ -891,7 +910,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
} else {
frame_code = avio_r8(bc);
if (url_feof(bc))
- return -1;
+ return AVERROR_EOF;
if (frame_code == 'N') {
tmp = frame_code;
for (i = 1; i < 8; i++)
diff --git a/ffmpeg/libavformat/nutenc.c b/ffmpeg/libavformat/nutenc.c
index 2d8d265..107e57b 100644
--- a/ffmpeg/libavformat/nutenc.c
+++ b/ffmpeg/libavformat/nutenc.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/tree.h"
@@ -91,7 +93,7 @@ static int find_expected_header(AVCodecContext *c, int size, int key_frame,
header |= (bitrate_index & 1) << 9;
return 2; //FIXME actually put the needed ones in build_elision_headers()
- return 3; //we guess that the private bit is not set
+ //return 3; //we guess that the private bit is not set
//FIXME the above assumptions should be checked, if these turn out false too often something should be done
}
return 0;
@@ -335,7 +337,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc)
tmp_head_idx;
int64_t tmp_match;
- ff_put_v(bc, 3); /* 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);
@@ -584,8 +588,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++;
@@ -680,10 +691,10 @@ static int nut_write_header(AVFormatContext *s)
nut->avf = s;
- nut->stream = av_mallocz(sizeof(StreamContext ) * s->nb_streams);
- nut->chapter = av_mallocz(sizeof(ChapterContext) * s->nb_chapters);
- nut->time_base= av_mallocz(sizeof(AVRational ) *(s->nb_streams +
- s->nb_chapters));
+ nut->stream = av_calloc(s->nb_streams, sizeof(*nut->stream ));
+ nut->chapter = av_calloc(s->nb_chapters, sizeof(*nut->chapter));
+ nut->time_base= av_calloc(s->nb_streams +
+ s->nb_chapters, sizeof(*nut->time_base));
if (!nut->stream || !nut->chapter || !nut->time_base) {
av_freep(&nut->stream);
av_freep(&nut->chapter);
@@ -858,13 +869,14 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);
put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
- ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts);
+ if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
+ return ret;
if ((1ll<<60) % nut->sp_count == 0)
for (i=0; i<s->nb_streams; i++) {
int j;
StreamContext *nus = &nut->stream[i];
- nus->keyframe_pts = av_realloc(nus->keyframe_pts, 2*nut->sp_count*sizeof(*nus->keyframe_pts));
+ av_reallocp_array(&nus->keyframe_pts, 2*nut->sp_count, sizeof(*nus->keyframe_pts));
if (!nus->keyframe_pts)
return AVERROR(ENOMEM);
for (j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++)
diff --git a/ffmpeg/libavformat/nuv.c b/ffmpeg/libavformat/nuv.c
index fc9e916..2c02de1 100644
--- a/ffmpeg/libavformat/nuv.c
+++ b/ffmpeg/libavformat/nuv.c
@@ -86,11 +86,8 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst,
av_freep(&vst->codec->extradata);
vst->codec->extradata_size = 0;
}
- vst->codec->extradata = av_malloc(size);
- if (!vst->codec->extradata)
+ if (ff_get_extradata(vst->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = size;
- avio_read(pb, vst->codec->extradata, size);
size = 0;
if (!myth)
return 0;
diff --git a/ffmpeg/libavformat/oggdec.c b/ffmpeg/libavformat/oggdec.c
index fdb5e96..8639eae 100644
--- a/ffmpeg/libavformat/oggdec.c
+++ b/ffmpeg/libavformat/oggdec.c
@@ -30,6 +30,7 @@
#include <stdio.h>
#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
#include "oggdec.h"
#include "avformat.h"
#include "internal.h"
@@ -88,7 +89,7 @@ static int ogg_restore(AVFormatContext *s, int discard)
struct ogg *ogg = s->priv_data;
AVIOContext *bc = s->pb;
struct ogg_state *ost = ogg->state;
- int i;
+ int i, err;
if (!ost)
return 0;
@@ -96,25 +97,21 @@ static int ogg_restore(AVFormatContext *s, int discard)
ogg->state = ost->next;
if (!discard) {
- struct ogg_stream *old_streams = ogg->streams;
for (i = 0; i < ogg->nstreams; i++)
- av_free(ogg->streams[i].buf);
+ av_freep(&ogg->streams[i].buf);
avio_seek(bc, ost->pos, SEEK_SET);
ogg->page_pos = -1;
ogg->curidx = ost->curidx;
ogg->nstreams = ost->nstreams;
- ogg->streams = av_realloc(ogg->streams,
- ogg->nstreams * sizeof(*ogg->streams));
-
- if (ogg->streams) {
+ if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
+ sizeof(*ogg->streams))) < 0) {
+ ogg->nstreams = 0;
+ return err;
+ } else
memcpy(ogg->streams, ost->streams,
ost->nstreams * sizeof(*ogg->streams));
- } else {
- av_free(old_streams);
- ogg->nstreams = 0;
- }
}
av_free(ost);
@@ -145,6 +142,7 @@ static int ogg_reset(AVFormatContext *s)
if (start_pos <= s->data_offset) {
os->lastpts = 0;
}
+ os->end_trimming = 0;
}
ogg->page_pos = -1;
@@ -636,14 +634,14 @@ static int ogg_read_close(AVFormatContext *s)
int i;
for (i = 0; i < ogg->nstreams; i++) {
- av_free(ogg->streams[i].buf);
+ av_freep(&ogg->streams[i].buf);
if (ogg->streams[i].codec &&
ogg->streams[i].codec->cleanup) {
ogg->streams[i].codec->cleanup(s, i);
}
- av_free(ogg->streams[i].private);
+ av_freep(&ogg->streams[i].private);
}
- av_free(ogg->streams);
+ av_freep(&ogg->streams);
return 0;
}
@@ -671,7 +669,12 @@ static int ogg_read_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
ogg->streams[i].codec = NULL;
} else if (os->codec && os->nb_header < os->codec->nb_header) {
- av_log(s, AV_LOG_WARNING, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i);
+ av_log(s, AV_LOG_WARNING,
+ "Headers mismatch for stream %d: "
+ "expected %d received %d.\n",
+ i, os->codec->nb_header, os->nb_header);
+ if (s->error_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
}
if (os->start_granule != OGG_NOGRANULE_VALUE)
os->lastpts = s->streams[i]->start_time =
@@ -735,6 +738,11 @@ static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
int pstart, psize;
int64_t fpos, pts, dts;
+ if (s->io_repositioned) {
+ ogg_reset(s);
+ s->io_repositioned = 0;
+ }
+
//Get an ogg packet
retry:
do {
@@ -767,6 +775,19 @@ retry:
pkt->duration = os->pduration;
pkt->pos = fpos;
+ if (os->end_trimming) {
+ 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);
+ }
+ AV_WL32(side_data + 4, os->end_trimming);
+ os->end_trimming = 0;
+ }
+
return psize;
}
@@ -849,5 +870,5 @@ AVInputFormat ff_ogg_demuxer = {
.read_seek = ogg_read_seek,
.read_timestamp = ogg_read_timestamp,
.extensions = "ogg",
- .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
};
diff --git a/ffmpeg/libavformat/oggdec.h b/ffmpeg/libavformat/oggdec.h
index e9a300d..c31859f 100644
--- a/ffmpeg/libavformat/oggdec.h
+++ b/ffmpeg/libavformat/oggdec.h
@@ -84,6 +84,7 @@ struct ogg_stream {
int got_start;
int got_data; ///< 1 if the stream got some data (non-initial packets), 0 otherwise
int nb_header; ///< set to the number of parsed headers
+ int end_trimming; ///< set the number of packets to drop from the end
void *private;
};
diff --git a/ffmpeg/libavformat/oggenc.c b/ffmpeg/libavformat/oggenc.c
index 3d4519c..d9ef23c 100644
--- a/ffmpeg/libavformat/oggenc.c
+++ b/ffmpeg/libavformat/oggenc.c
@@ -19,8 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "libavutil/crc.h"
-#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
@@ -81,18 +82,10 @@ static const AVOption options[] = {
{ "pagesize", "preferred page size in bytes (deprecated)",
OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM },
{ "page_duration", "preferred page duration, in microseconds",
- OFFSET(pref_duration), AV_OPT_TYPE_INT, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
+ OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
{ NULL },
};
-static const AVClass ogg_muxer_class = {
- .class_name = "Ogg muxer",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-
static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset)
{
int64_t pos = avio_tell(pb);
@@ -447,11 +440,13 @@ static int ogg_write_header(AVFormatContext *s)
} while (j < i);
oggstream->serial_num = serial_num;
+ av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE);
+
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->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
av_freep(&st->priv_data);
@@ -460,7 +455,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->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
av_freep(&st->priv_data);
@@ -469,7 +464,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->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
av_freep(&st->priv_data);
@@ -490,7 +485,7 @@ static int ogg_write_header(AVFormatContext *s)
}
p = ogg_write_vorbiscomment(7, st->codec->flags & CODEC_FLAG_BITEXACT,
- &oggstream->header_len[1], &s->metadata,
+ &oggstream->header_len[1], &st->metadata,
framing_bit);
oggstream->header[1] = p;
if (!p)
@@ -621,16 +616,81 @@ static int ogg_write_trailer(AVFormatContext *s)
return 0;
}
+#if CONFIG_OGG_MUXER
+static const AVClass ogg_muxer_class = {
+ .class_name = "Ogg muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_ogg_muxer = {
.name = "ogg",
.long_name = NULL_IF_CONFIG_SMALL("Ogg"),
.mime_type = "application/ogg",
- .extensions = "ogg,ogv,spx,opus",
+ .extensions = "ogg,ogv"
+#if !CONFIG_SPEEX_MUXER
+ ",spx"
+#endif
+#if !CONFIG_OPUS_MUXER
+ ",opus"
+#endif
+ ,
.priv_data_size = sizeof(OGGContext),
.audio_codec = AV_CODEC_ID_FLAC,
.video_codec = AV_CODEC_ID_THEORA,
.write_header = ogg_write_header,
.write_packet = ogg_write_packet,
.write_trailer = ogg_write_trailer,
+ .flags = AVFMT_TS_NEGATIVE,
.priv_class = &ogg_muxer_class,
};
+#endif
+
+#if CONFIG_SPEEX_MUXER
+static const AVClass speex_muxer_class = {
+ .class_name = "Speex muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_speex_muxer = {
+ .name = "speex",
+ .long_name = NULL_IF_CONFIG_SMALL("Speex"),
+ .mime_type = "audio/ogg",
+ .extensions = "spx",
+ .priv_data_size = sizeof(OGGContext),
+ .audio_codec = AV_CODEC_ID_SPEEX,
+ .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 = &speex_muxer_class,
+};
+#endif
+
+#if CONFIG_OPUS_MUXER
+static const AVClass opus_muxer_class = {
+ .class_name = "Opus muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_opus_muxer = {
+ .name = "opus",
+ .long_name = NULL_IF_CONFIG_SMALL("Opus"),
+ .mime_type = "audio/ogg",
+ .extensions = "opus",
+ .priv_data_size = sizeof(OGGContext),
+ .audio_codec = AV_CODEC_ID_OPUS,
+ .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 = &opus_muxer_class,
+};
+#endif
diff --git a/ffmpeg/libavformat/oggparsecelt.c b/ffmpeg/libavformat/oggparsecelt.c
index afc4392..f3c2c1a 100644
--- a/ffmpeg/libavformat/oggparsecelt.c
+++ b/ffmpeg/libavformat/oggparsecelt.c
@@ -44,16 +44,12 @@ static int celt_header(AVFormatContext *s, int idx)
uint32_t version, sample_rate, nb_channels, frame_size;
uint32_t overlap, extra_headers;
- uint8_t *extradata;
- extradata = av_malloc(2 * sizeof(uint32_t) +
- FF_INPUT_BUFFER_PADDING_SIZE);
priv = av_malloc(sizeof(struct oggcelt_private));
- if (!extradata || !priv) {
- av_free(extradata);
- av_free(priv);
+ if (!priv)
+ return AVERROR(ENOMEM);
+ if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0)
return AVERROR(ENOMEM);
- }
version = AV_RL32(p + 28);
/* unused header size field skipped */
sample_rate = AV_RL32(p + 36);
@@ -67,16 +63,13 @@ static int celt_header(AVFormatContext *s, int idx)
st->codec->sample_rate = sample_rate;
st->codec->channels = nb_channels;
st->codec->frame_size = frame_size;
- av_free(st->codec->extradata);
- st->codec->extradata = extradata;
- st->codec->extradata_size = 2 * sizeof(uint32_t);
if (sample_rate)
avpriv_set_pts_info(st, 64, 1, sample_rate);
priv->extra_headers_left = 1 + extra_headers;
av_free(os->private);
os->private = priv;
- AV_WL32(extradata + 0, overlap);
- AV_WL32(extradata + 4, version);
+ AV_WL32(st->codec->extradata + 0, overlap);
+ AV_WL32(st->codec->extradata + 4, version);
return 1;
} else if (priv && priv->extra_headers_left) {
/* Extra headers (vorbiscomment) */
diff --git a/ffmpeg/libavformat/oggparseflac.c b/ffmpeg/libavformat/oggparseflac.c
index 3ff594e..f69533f 100644
--- a/ffmpeg/libavformat/oggparseflac.c
+++ b/ffmpeg/libavformat/oggparseflac.c
@@ -62,10 +62,9 @@ flac_header (AVFormatContext * s, int idx)
st->codec->codec_id = AV_CODEC_ID_FLAC;
st->need_parsing = AVSTREAM_PARSE_HEADERS;
- st->codec->extradata =
- av_malloc(FLAC_STREAMINFO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- memcpy(st->codec->extradata, streaminfo_start, FLAC_STREAMINFO_SIZE);
- st->codec->extradata_size = FLAC_STREAMINFO_SIZE;
+ if (ff_alloc_extradata(st->codec, FLAC_STREAMINFO_SIZE) < 0)
+ return AVERROR(ENOMEM);
+ memcpy(st->codec->extradata, streaminfo_start, st->codec->extradata_size);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
} else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
@@ -78,11 +77,32 @@ flac_header (AVFormatContext * s, int idx)
static int
old_flac_header (AVFormatContext * s, int idx)
{
+ struct ogg *ogg = s->priv_data;
AVStream *st = s->streams[idx];
+ struct ogg_stream *os = ogg->streams + idx;
+ AVCodecParserContext *parser = av_parser_init(AV_CODEC_ID_FLAC);
+ int size;
+ uint8_t *data;
+
+ if (!parser)
+ return -1;
+
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_FLAC;
- return 0;
+ parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ av_parser_parse2(parser, st->codec,
+ &data, &size, os->buf + os->pstart, os->psize,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+
+ av_parser_close(parser);
+
+ if (st->codec->sample_rate) {
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ return 0;
+ }
+
+ return 1;
}
const struct ogg_codec ff_flac_codec = {
diff --git a/ffmpeg/libavformat/oggparseogm.c b/ffmpeg/libavformat/oggparseogm.c
index a3caac0..fe4c1f2 100644
--- a/ffmpeg/libavformat/oggparseogm.c
+++ b/ffmpeg/libavformat/oggparseogm.c
@@ -38,34 +38,35 @@ ogm_header(AVFormatContext *s, int idx)
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
AVStream *st = s->streams[idx];
- const uint8_t *p = os->buf + os->pstart;
+ GetByteContext p;
uint64_t time_unit;
uint64_t spu;
uint32_t size;
- if(!(*p & 1))
+ bytestream2_init(&p, os->buf + os->pstart, os->psize);
+ if (!(bytestream2_peek_byte(&p) & 1))
return 0;
- if(*p == 1) {
- p++;
+ if (bytestream2_peek_byte(&p) == 1) {
+ bytestream2_skip(&p, 1);
- if(*p == 'v'){
+ if (bytestream2_peek_byte(&p) == 'v'){
int tag;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- p += 8;
- tag = bytestream_get_le32(&p);
+ bytestream2_skip(&p, 8);
+ tag = bytestream2_get_le32(&p);
st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
st->codec->codec_tag = tag;
- } else if (*p == 't') {
+ } else if (bytestream2_peek_byte(&p) == 't') {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id = AV_CODEC_ID_TEXT;
- p += 12;
+ bytestream2_skip(&p, 12);
} else {
- uint8_t acid[5];
+ uint8_t acid[5] = { 0 };
int cid;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- p += 8;
- bytestream_get_buffer(&p, acid, 4);
+ bytestream2_skip(&p, 8);
+ bytestream2_get_buffer(&p, acid, 4);
acid[4] = 0;
cid = strtol(acid, NULL, 16);
st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid);
@@ -74,38 +75,38 @@ ogm_header(AVFormatContext *s, int idx)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
- size = bytestream_get_le32(&p);
+ size = bytestream2_get_le32(&p);
size = FFMIN(size, os->psize);
- time_unit = bytestream_get_le64(&p);
- spu = bytestream_get_le64(&p);
- p += 4; /* default_len */
- p += 8; /* buffersize + bits_per_sample */
+ time_unit = bytestream2_get_le64(&p);
+ spu = bytestream2_get_le64(&p);
+ bytestream2_skip(&p, 4); /* default_len */
+ bytestream2_skip(&p, 8); /* buffersize + bits_per_sample */
if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
- st->codec->width = bytestream_get_le32(&p);
- st->codec->height = bytestream_get_le32(&p);
+ st->codec->width = bytestream2_get_le32(&p);
+ st->codec->height = bytestream2_get_le32(&p);
avpriv_set_pts_info(st, 64, time_unit, spu * 10000000);
} else {
- st->codec->channels = bytestream_get_le16(&p);
- p += 2; /* block_align */
- st->codec->bit_rate = bytestream_get_le32(&p) * 8;
+ 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;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) {
- p += 4;
+ bytestream2_skip(&p, 4);
size -= 4;
}
if (size > 52) {
av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52);
size -= 52;
- st->codec->extradata_size = size;
- st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- bytestream_get_buffer(&p, st->codec->extradata, size);
+ ff_alloc_extradata(st->codec, size);
+ bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size);
}
}
- } else if (*p == 3) {
- if (os->psize > 8)
- ff_vorbis_comment(s, &st->metadata, p+7, os->psize-8);
+ } else if (bytestream2_peek_byte(&p) == 3) {
+ bytestream2_skip(&p, 7);
+ if (bytestream2_get_bytes_left(&p) > 1)
+ ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1);
}
return 1;
@@ -125,15 +126,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/ffmpeg/libavformat/oggparseopus.c b/ffmpeg/libavformat/oggparseopus.c
index 0e8f1ca..aafefbb 100644
--- a/ffmpeg/libavformat/oggparseopus.c
+++ b/ffmpeg/libavformat/oggparseopus.c
@@ -36,35 +36,34 @@ struct oggopus_private {
static int opus_header(AVFormatContext *avf, int idx)
{
- struct ogg *ogg = avf->priv_data;
- struct ogg_stream *os = &ogg->streams[idx];
- AVStream *st = avf->streams[idx];
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[idx];
+ AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
- uint8_t *packet = os->buf + os->pstart;
- uint8_t *extradata;
+ uint8_t *packet = os->buf + os->pstart;
if (!priv) {
priv = os->private = av_mallocz(sizeof(*priv));
if (!priv)
return AVERROR(ENOMEM);
}
+
if (os->flags & OGG_FLAG_BOS) {
if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
return AVERROR_INVALIDDATA;
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_OPUS;
- st->codec->channels = AV_RL8 (packet + 9);
- priv->pre_skip = AV_RL16(packet + 10);
- /*orig_sample_rate = AV_RL32(packet + 12);*/
- /*gain = AV_RL16(packet + 16);*/
- /*channel_map = AV_RL8 (packet + 18);*/
-
- extradata = av_malloc(os->psize + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!extradata)
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_OPUS;
+ st->codec->channels = AV_RL8 (packet + 9);
+ priv->pre_skip = AV_RL16(packet + 10);
+ st->codec->delay = priv->pre_skip;
+ /*orig_sample_rate = AV_RL32(packet + 12);*/
+ /*gain = AV_RL16(packet + 16);*/
+ /*channel_map = AV_RL8 (packet + 18);*/
+
+ if (ff_alloc_extradata(st->codec, os->psize))
return AVERROR(ENOMEM);
- memcpy(extradata, packet, os->psize);
- st->codec->extradata = extradata;
- st->codec->extradata_size = os->psize;
+
+ memcpy(st->codec->extradata, packet, os->psize);
st->codec->sample_rate = 48000;
avpriv_set_pts_info(st, 64, 1, 48000);
@@ -79,57 +78,104 @@ static int opus_header(AVFormatContext *avf, int idx)
priv->need_comments--;
return 1;
}
+
return 0;
}
+static int opus_duration(uint8_t *src, int size)
+{
+ unsigned nb_frames = 1;
+ unsigned toc = src[0];
+ unsigned toc_config = toc >> 3;
+ unsigned toc_count = toc & 3;
+ unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
+ toc_config < 16 ? 480 << (toc_config & 1) :
+ 120 << (toc_config & 3);
+ if (toc_count == 3) {
+ if (size<2)
+ return AVERROR_INVALIDDATA;
+ nb_frames = src[1] & 0x3F;
+ } else if (toc_count) {
+ nb_frames = 2;
+ }
+
+ return frame_size * nb_frames;
+}
+
static int opus_packet(AVFormatContext *avf, int idx)
{
- struct ogg *ogg = avf->priv_data;
- struct ogg_stream *os = &ogg->streams[idx];
- AVStream *st = avf->streams[idx];
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[idx];
+ AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
- uint8_t *packet = os->buf + os->pstart;
- unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
+ uint8_t *packet = os->buf + os->pstart;
+ int ret;
if (!os->psize)
return AVERROR_INVALIDDATA;
- toc = *packet;
- toc_config = toc >> 3;
- toc_count = toc & 3;
- frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
- toc_config < 16 ? 480 << (toc_config & 1) :
- 120 << (toc_config & 3);
- if (toc_count == 3) {
- if (os->psize < 2)
- return AVERROR_INVALIDDATA;
- nb_frames = packet[1] & 0x3F;
- } else if (toc_count) {
- nb_frames = 2;
+
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg, d;
+ int duration;
+ uint8_t *last_pkt = os->buf + os->pstart;
+ uint8_t *next_pkt = last_pkt;
+
+ duration = 0;
+ seg = os->segp;
+ d = opus_duration(last_pkt, os->psize);
+ if (d < 0) {
+ os->pflags |= AV_PKT_FLAG_CORRUPT;
+ return 0;
+ }
+ 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];
+ }
+ os->lastpts =
+ os->lastdts = os->granule - duration;
}
- os->pduration = frame_size * nb_frames;
+
+ if ((ret = opus_duration(packet, os->psize)) < 0)
+ return ret;
+
+ os->pduration = ret;
if (os->lastpts != AV_NOPTS_VALUE) {
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = os->lastpts;
priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
}
+
priv->cur_dts += os->pduration;
if ((os->flags & OGG_FLAG_EOS)) {
int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
skip = FFMIN(skip, os->pduration);
if (skip > 0) {
os->pduration = skip < os->pduration ? os->pduration - skip : 1;
- av_log(avf, AV_LOG_WARNING,
- "Last packet must be truncated to %d (unimplemented).\n",
+ os->end_trimming = skip;
+ av_log(avf, AV_LOG_DEBUG,
+ "Last packet was truncated to %d due to end trimming.\n",
os->pduration);
}
}
+
return 0;
}
const struct ogg_codec ff_opus_codec = {
- .name = "Opus",
- .magic = "OpusHead",
- .magicsize = 8,
- .header = opus_header,
- .packet = opus_packet,
+ .name = "Opus",
+ .magic = "OpusHead",
+ .magicsize = 8,
+ .header = opus_header,
+ .packet = opus_packet,
+ .nb_header = 1,
};
diff --git a/ffmpeg/libavformat/oggparseskeleton.c b/ffmpeg/libavformat/oggparseskeleton.c
index 307387d..d94b0c2 100644
--- a/ffmpeg/libavformat/oggparseskeleton.c
+++ b/ffmpeg/libavformat/oggparseskeleton.c
@@ -37,6 +37,9 @@ static int skeleton_header(AVFormatContext *s, int idx)
strcpy(st->codec->codec_name, "skeleton");
st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ if ((os->flags & OGG_FLAG_EOS) && os->psize == 0)
+ return 1;
+
if (os->psize < 8)
return -1;
@@ -74,12 +77,16 @@ static int skeleton_header(AVFormatContext *s, int idx)
target_idx = ogg_find_stream(ogg, AV_RL32(buf+12));
start_granule = AV_RL64(buf+36);
+ if (target_idx < 0) {
+ av_log(s, AV_LOG_WARNING, "Serial number in fisbone doesn't match any stream\n");
+ return 1;
+ }
+ os = ogg->streams + target_idx;
if (os->start_granule != OGG_NOGRANULE_VALUE) {
- avpriv_report_missing_feature(s,
- "Multiple fisbone for the same stream");
+ av_log(s, AV_LOG_WARNING, "Multiple fisbone for the same stream\n");
return 1;
}
- if (target_idx >= 0 && start_granule != OGG_NOGRANULE_VALUE) {
+ if (start_granule != OGG_NOGRANULE_VALUE) {
os->start_granule = start_granule;
}
}
diff --git a/ffmpeg/libavformat/oggparsespeex.c b/ffmpeg/libavformat/oggparsespeex.c
index 63e6370..1b9de9c 100644
--- a/ffmpeg/libavformat/oggparsespeex.c
+++ b/ffmpeg/libavformat/oggparsespeex.c
@@ -77,9 +77,8 @@ static int speex_header(AVFormatContext *s, int idx) {
if (frames_per_packet)
spxp->packet_size *= frames_per_packet;
- st->codec->extradata_size = os->psize;
- st->codec->extradata = av_malloc(st->codec->extradata_size
- + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (ff_alloc_extradata(st->codec, os->psize) < 0)
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, p, st->codec->extradata_size);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
diff --git a/ffmpeg/libavformat/oggparsetheora.c b/ffmpeg/libavformat/oggparsetheora.c
index 6877d1e..59df17e 100644
--- a/ffmpeg/libavformat/oggparsetheora.c
+++ b/ffmpeg/libavformat/oggparsetheora.c
@@ -1,26 +1,26 @@
/**
- Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use, copy,
- modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
-**/
+ * Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ **/
#include <stdlib.h>
#include "libavutil/bswap.h"
@@ -29,64 +29,67 @@
#include "internal.h"
#include "oggdec.h"
-struct theora_params {
+typedef struct TheoraParams {
int gpshift;
int gpmask;
unsigned version;
-};
+} TheoraParams;
-static int
-theora_header (AVFormatContext * s, int idx)
+static int theora_header(AVFormatContext *s, int idx)
{
- struct ogg *ogg = s->priv_data;
+ struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
- AVStream *st = s->streams[idx];
- struct theora_params *thp = os->private;
- int cds = st->codec->extradata_size + os->psize + 2;
+ AVStream *st = s->streams[idx];
+ TheoraParams *thp = os->private;
+ int cds = st->codec->extradata_size + os->psize + 2;
+ int err;
uint8_t *cdp;
- if(!(os->buf[os->pstart] & 0x80))
+ if (!(os->buf[os->pstart] & 0x80))
return 0;
- if(!thp){
+ if (!thp) {
thp = av_mallocz(sizeof(*thp));
+ if (!thp)
+ return AVERROR(ENOMEM);
os->private = thp;
}
switch (os->buf[os->pstart]) {
case 0x80: {
GetBitContext gb;
- int width, height;
AVRational timebase;
- init_get_bits(&gb, os->buf + os->pstart, os->psize*8);
+ init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
- skip_bits_long(&gb, 7*8); /* 0x80"theora" */
+ /* 0x80"theora" */
+ skip_bits_long(&gb, 7 * 8);
thp->version = get_bits_long(&gb, 24);
- if (thp->version < 0x030100)
- {
+ if (thp->version < 0x030100) {
av_log(s, AV_LOG_ERROR,
- "Too old or unsupported Theora (%x)\n", thp->version);
- return -1;
+ "Too old or unsupported Theora (%x)\n", thp->version);
+ return AVERROR(ENOSYS);
}
- width = get_bits(&gb, 16) << 4;
- height = get_bits(&gb, 16) << 4;
- avcodec_set_dimensions(st->codec, width, height);
+ st->codec->width = get_bits(&gb, 16) << 4;
+ st->codec->height = get_bits(&gb, 16) << 4;
if (thp->version >= 0x030400)
skip_bits(&gb, 100);
if (thp->version >= 0x030200) {
- width = get_bits_long(&gb, 24);
- height = get_bits_long(&gb, 24);
- if ( width <= st->codec->width && width > st->codec->width-16
- && height <= st->codec->height && height > st->codec->height-16)
- avcodec_set_dimensions(st->codec, width, height);
+ int width = get_bits_long(&gb, 24);
+ int height = get_bits_long(&gb, 24);
+ if (width <= st->codec->width && width > st->codec->width - 16 &&
+ height <= st->codec->height && height > st->codec->height - 16) {
+ st->codec->width = width;
+ st->codec->height = height;
+ }
skip_bits(&gb, 16);
}
+
timebase.den = get_bits_long(&gb, 32);
timebase.num = get_bits_long(&gb, 32);
if (!(timebase.num > 0 && timebase.den > 0)) {
@@ -105,41 +108,46 @@ theora_header (AVFormatContext * s, int idx)
skip_bits(&gb, 2);
thp->gpshift = get_bits(&gb, 5);
- thp->gpmask = (1 << thp->gpshift) - 1;
+ thp->gpmask = (1 << thp->gpshift) - 1;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_THEORA;
- st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ st->codec->codec_id = AV_CODEC_ID_THEORA;
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
}
break;
case 0x81:
ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
case 0x82:
if (!thp->version)
- return -1;
+ return AVERROR_INVALIDDATA;
break;
default:
av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
- return -1;
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((err = av_reallocp(&st->codec->extradata,
+ cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
+ st->codec->extradata_size = 0;
+ return err;
}
+ memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- st->codec->extradata = av_realloc (st->codec->extradata,
- cds + FF_INPUT_BUFFER_PADDING_SIZE);
- cdp = st->codec->extradata + st->codec->extradata_size;
+ cdp = st->codec->extradata + st->codec->extradata_size;
*cdp++ = os->psize >> 8;
*cdp++ = os->psize & 0xff;
- memcpy (cdp, os->buf + os->pstart, os->psize);
+ memcpy(cdp, os->buf + os->pstart, os->psize);
st->codec->extradata_size = cds;
return 1;
}
-static uint64_t
-theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
+static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
+ int64_t *dts)
{
- struct ogg *ogg = ctx->priv_data;
+ struct ogg *ogg = ctx->priv_data;
struct ogg_stream *os = ogg->streams + idx;
- struct theora_params *thp = os->private;
+ TheoraParams *thp = os->private;
uint64_t iframe, pframe;
if (!thp)
@@ -151,7 +159,7 @@ theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
if (thp->version < 0x030201)
iframe++;
- if(!pframe)
+ if (!pframe)
os->pflags |= AV_PKT_FLAG_KEY;
if (dts)
@@ -197,10 +205,10 @@ static int theora_packet(AVFormatContext *s, int idx)
}
const struct ogg_codec ff_theora_codec = {
- .magic = "\200theora",
+ .magic = "\200theora",
.magicsize = 7,
- .header = theora_header,
- .packet = theora_packet,
- .gptopts = theora_gptopts,
+ .header = theora_header,
+ .packet = theora_packet,
+ .gptopts = theora_gptopts,
.nb_header = 3,
};
diff --git a/ffmpeg/libavformat/oggparsevorbis.c b/ffmpeg/libavformat/oggparsevorbis.c
index da029a4..36ad738 100644
--- a/ffmpeg/libavformat/oggparsevorbis.c
+++ b/ffmpeg/libavformat/oggparsevorbis.c
@@ -1,35 +1,38 @@
-/**
- Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use, copy,
- modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
-**/
+/*
+ * Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
#include <stdlib.h>
+
#include "libavutil/avstring.h"
+#include "libavutil/base64.h"
#include "libavutil/bswap.h"
#include "libavutil/dict.h"
-#include "libavcodec/get_bits.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/get_bits.h"
#include "libavcodec/vorbis_parser.h"
#include "avformat.h"
+#include "flac_picture.h"
#include "internal.h"
#include "oggdec.h"
#include "vorbiscomment.h"
@@ -39,19 +42,19 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
int i, cnum, h, m, s, ms, keylen = strlen(key);
AVChapter *chapter = NULL;
- if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
+ if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1)
return 0;
- if (keylen == 9) {
+ if (keylen <= 10) {
if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
return 0;
- avpriv_new_chapter(as, cnum, (AVRational){1,1000},
- ms + 1000*(s + 60*(m + 60*h)),
- AV_NOPTS_VALUE, NULL);
+ avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 },
+ ms + 1000 * (s + 60 * (m + 60 * h)),
+ AV_NOPTS_VALUE, NULL);
av_free(val);
- } else if (!strcmp(key+9, "NAME")) {
- for(i = 0; i < as->nb_chapters; i++)
+ } else if (!strcmp(key + keylen - 4, "NAME")) {
+ for (i = 0; i < as->nb_chapters; i++)
if (as->chapters[i]->id == cnum) {
chapter = as->chapters[i];
break;
@@ -59,8 +62,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
if (!chapter)
return 0;
- av_dict_set(&chapter->metadata, "title", val,
- AV_DICT_DONT_STRDUP_VAL);
+ av_dict_set(&chapter->metadata, "title", val, AV_DICT_DONT_STRDUP_VAL);
} else
return 0;
@@ -68,21 +70,22 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
return 1;
}
-int
-ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size)
+int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
+ const uint8_t *buf, int size)
{
- const uint8_t *p = buf;
+ const uint8_t *p = buf;
const uint8_t *end = buf + size;
unsigned n, j;
int s;
- if (size < 8) /* must have vendor_length and user_comment_list_length */
- return -1;
+ /* must have vendor_length and user_comment_list_length */
+ if (size < 8)
+ return AVERROR_INVALIDDATA;
s = bytestream_get_le32(&p);
if (end - p - 4 < s || s < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
p += s;
@@ -97,7 +100,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
if (end - p < s || s < 0)
break;
- t = p;
+ t = p;
p += s;
n--;
@@ -117,8 +120,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
if (!tt || !ct) {
av_freep(&tt);
av_freep(&ct);
- av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
- continue;
+ return AVERROR(ENOMEM);
}
for (j = 0; j < tl; j++)
@@ -128,15 +130,41 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
memcpy(ct, v, vl);
ct[vl] = 0;
- if (!ogm_chapter(as, tt, ct))
+ /* The format in which the pictures are stored is the FLAC format.
+ * Xiph says: "The binary FLAC picture structure is base64 encoded
+ * and placed within a VorbisComment with the tag name
+ * 'METADATA_BLOCK_PICTURE'. This is the preferred and
+ * recommended way of embedding cover art within VorbisComments."
+ */
+ if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) {
+ int ret;
+ char *pict = av_malloc(vl);
+
+ if (!pict) {
+ av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n");
+ av_freep(&tt);
+ av_freep(&ct);
+ continue;
+ }
+ if ((ret = av_base64_decode(pict, ct, vl)) > 0)
+ ret = ff_flac_parse_picture(as, pict, ret);
+ av_freep(&tt);
+ av_freep(&ct);
+ av_freep(&pict);
+ if (ret < 0) {
+ av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n");
+ continue;
+ }
+ } else if (!ogm_chapter(as, tt, ct))
av_dict_set(m, tt, ct,
- AV_DICT_DONT_STRDUP_KEY |
- AV_DICT_DONT_STRDUP_VAL);
+ AV_DICT_DONT_STRDUP_KEY |
+ AV_DICT_DONT_STRDUP_VAL);
}
}
if (p != end)
- av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);
+ av_log(as, AV_LOG_INFO,
+ "%ti 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);
@@ -146,8 +174,9 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
return 0;
}
-
-/** Parse the vorbis header
+/*
+ * Parse the vorbis header
+ *
* Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
* [vorbis_version] = read 32 bits as unsigned integer | Not used
* [audio_channels] = read 8 bit integer as unsigned | Used
@@ -158,7 +187,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
* [blocksize_0] = read 4 bits as unsigned integer | Not Used
* [blocksize_1] = read 4 bits as unsigned integer | Not Used
* [framing_flag] = read one bit | Not Used
- * */
+ */
struct oggvorbis_private {
unsigned int len[3];
@@ -168,23 +197,23 @@ struct oggvorbis_private {
int final_duration;
};
-
-static unsigned int
-fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
- uint8_t **buf)
+static int fixup_vorbis_headers(AVFormatContext *as,
+ struct oggvorbis_private *priv,
+ uint8_t **buf)
{
- int i,offset, len, buf_len;
+ int i, offset, len, err;
+ int buf_len;
unsigned char *ptr;
len = priv->len[0] + priv->len[1] + priv->len[2];
- buf_len = len + len/255 + 64;
+ buf_len = len + len / 255 + 64;
ptr = *buf = av_realloc(NULL, buf_len);
- if (!*buf)
- return 0;
+ if (!ptr)
+ return AVERROR(ENOMEM);
memset(*buf, '\0', buf_len);
- ptr[0] = 2;
- offset = 1;
+ ptr[0] = 2;
+ offset = 1;
offset += av_xiphlacing(&ptr[offset], priv->len[0]);
offset += av_xiphlacing(&ptr[offset], priv->len[1]);
for (i = 0; i < 3; i++) {
@@ -192,7 +221,8 @@ fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
offset += priv->len[i];
av_freep(&priv->packet[i]);
}
- *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
+ if ((err = av_reallocp(buf, offset + FF_INPUT_BUFFER_PADDING_SIZE)) < 0)
+ return err;
return offset;
}
@@ -207,35 +237,34 @@ static void vorbis_cleanup(AVFormatContext *s, int idx)
av_freep(&priv->packet[i]);
}
-static int
-vorbis_header (AVFormatContext * s, int idx)
+static int vorbis_header(AVFormatContext *s, int idx)
{
struct ogg *ogg = s->priv_data;
+ AVStream *st = s->streams[idx];
struct ogg_stream *os = ogg->streams + idx;
- AVStream *st = s->streams[idx];
struct oggvorbis_private *priv;
int pkt_type = os->buf[os->pstart];
- if (!(pkt_type & 1))
- return os->private ? 0 : -1;
-
if (!os->private) {
os->private = av_mallocz(sizeof(struct oggvorbis_private));
if (!os->private)
- return -1;
+ return AVERROR(ENOMEM);
}
+ if (!(pkt_type & 1))
+ return 0;
+
if (os->psize < 1 || pkt_type > 5)
- return -1;
+ return AVERROR_INVALIDDATA;
priv = os->private;
- if (priv->packet[pkt_type>>1])
- return -1;
+ if (priv->packet[pkt_type >> 1])
+ return AVERROR_INVALIDDATA;
if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
- return -1;
+ return AVERROR_INVALIDDATA;
- priv->len[pkt_type >> 1] = os->psize;
+ priv->len[pkt_type >> 1] = os->psize;
priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
if (!priv->packet[pkt_type >> 1])
return AVERROR(ENOMEM);
@@ -247,36 +276,36 @@ vorbis_header (AVFormatContext * s, int idx)
int channels;
if (os->psize != 30)
- return -1;
+ return AVERROR_INVALIDDATA;
if (bytestream_get_le32(&p) != 0) /* vorbis_version */
- return -1;
+ return AVERROR_INVALIDDATA;
- channels= bytestream_get_byte(&p);
+ channels = bytestream_get_byte(&p);
if (st->codec->channels && channels != st->codec->channels) {
av_log(s, AV_LOG_ERROR, "Channel change is not supported\n");
return AVERROR_PATCHWELCOME;
}
st->codec->channels = channels;
- srate = bytestream_get_le32(&p);
+ srate = bytestream_get_le32(&p);
p += 4; // skip maximum bitrate
st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
p += 4; // skip minimum bitrate
blocksize = bytestream_get_byte(&p);
- bs0 = blocksize & 15;
- bs1 = blocksize >> 4;
+ bs0 = blocksize & 15;
+ bs1 = blocksize >> 4;
if (bs0 > bs1)
- return -1;
+ return AVERROR_INVALIDDATA;
if (bs0 < 6 || bs1 > 13)
- return -1;
+ return AVERROR_INVALIDDATA;
if (bytestream_get_byte(&p) != 1) /* framing_flag */
- return -1;
+ return AVERROR_INVALIDDATA;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_VORBIS;
+ st->codec->codec_id = AV_CODEC_ID_VORBIS;
if (srate > 0) {
st->codec->sample_rate = srate;
@@ -284,19 +313,23 @@ vorbis_header (AVFormatContext * s, int idx)
}
} 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) {
+ ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7,
+ os->psize - 8) >= 0) {
// 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;
if (new_len >= 16 && new_len < os->psize) {
AV_WL32(priv->packet[1] + new_len - 5, 0);
priv->packet[1][new_len - 1] = 1;
- priv->len[1] = new_len;
+ priv->len[1] = new_len;
}
}
} else {
- int ret;
- st->codec->extradata_size =
- fixup_vorbis_headers(s, priv, &st->codec->extradata);
+ int ret = fixup_vorbis_headers(s, priv, &st->codec->extradata);
+ if (ret < 0) {
+ st->codec->extradata_size = 0;
+ return ret;
+ }
+ st->codec->extradata_size = ret;
if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) {
av_freep(&st->codec->extradata);
st->codec->extradata_size = 0;
@@ -315,13 +348,13 @@ static int vorbis_packet(AVFormatContext *s, int idx)
int duration;
/* 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 */
+ * 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)) {
int seg, d;
- uint8_t *last_pkt = os->buf + os->pstart;
- uint8_t *next_pkt = last_pkt;
+ uint8_t *last_pkt = os->buf + os->pstart;
+ uint8_t *next_pkt = last_pkt;
avpriv_vorbis_parse_reset(&priv->vp);
duration = 0;
@@ -341,17 +374,18 @@ static int vorbis_packet(AVFormatContext *s, int idx)
break;
}
duration += d;
- last_pkt = next_pkt + os->segments[seg];
+ last_pkt = next_pkt + os->segments[seg];
}
next_pkt += os->segments[seg];
}
- os->lastpts = os->lastdts = os->granule - duration;
- if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
+ os->lastpts =
+ os->lastdts = os->granule - duration;
+ if (s->streams[idx]->start_time == AV_NOPTS_VALUE) {
s->streams[idx]->start_time = FFMAX(os->lastpts, 0);
if (s->streams[idx]->duration)
s->streams[idx]->duration -= s->streams[idx]->start_time;
}
- priv->final_pts = AV_NOPTS_VALUE;
+ priv->final_pts = AV_NOPTS_VALUE;
avpriv_vorbis_parse_reset(&priv->vp);
}
@@ -366,12 +400,12 @@ static int vorbis_packet(AVFormatContext *s, int idx)
}
/* final packet handling
- here we save the pts of the first packet in the final page, sum up all
- packet durations in the final page except for the last one, and compare
- to the page granule to find the duration of the final packet */
+ * here we save the pts of the first packet in the final page, sum up all
+ * packet durations in the final page except for the last one, and compare
+ * to the page granule to find the duration of the final packet */
if (os->flags & OGG_FLAG_EOS) {
if (os->lastpts != AV_NOPTS_VALUE) {
- priv->final_pts = os->lastpts;
+ priv->final_pts = os->lastpts;
priv->final_duration = 0;
}
if (os->segp == os->nsegs)
@@ -383,10 +417,10 @@ static int vorbis_packet(AVFormatContext *s, int idx)
}
const struct ogg_codec ff_vorbis_codec = {
- .magic = "\001vorbis",
+ .magic = "\001vorbis",
.magicsize = 7,
- .header = vorbis_header,
- .packet = vorbis_packet,
- .cleanup= vorbis_cleanup,
+ .header = vorbis_header,
+ .packet = vorbis_packet,
+ .cleanup = vorbis_cleanup,
.nb_header = 3,
};
diff --git a/ffmpeg/libavformat/oma.c b/ffmpeg/libavformat/oma.c
index 9e4bfbd..2702867 100644
--- a/ffmpeg/libavformat/oma.c
+++ b/ffmpeg/libavformat/oma.c
@@ -21,8 +21,9 @@
#include "internal.h"
#include "oma.h"
#include "libavcodec/avcodec.h"
+#include "libavutil/channel_layout.h"
-const uint16_t ff_oma_srate_tab[8] = { 320, 441, 480, 882, 960, 0, 0, 0};
+const uint16_t ff_oma_srate_tab[8] = { 320, 441, 480, 882, 960, 0 };
const AVCodecTag ff_oma_codec_tags[] = {
{ AV_CODEC_ID_ATRAC3, OMA_CODECID_ATRAC3 },
@@ -32,3 +33,16 @@ const AVCodecTag ff_oma_codec_tags[] = {
{ 0 },
};
+/** map ATRAC-X channel id to internal channel layout */
+const uint64_t ff_oma_chid_to_native_layout[7] = {
+ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_SURROUND,
+ AV_CH_LAYOUT_4POINT0,
+ AV_CH_LAYOUT_5POINT1_BACK,
+ AV_CH_LAYOUT_6POINT1_BACK,
+ AV_CH_LAYOUT_7POINT1
+};
+
+/** map ATRAC-X channel id to total number of channels */
+const int ff_oma_chid_to_num_channels[7] = {1, 2, 3, 4, 6, 7, 8};
diff --git a/ffmpeg/libavformat/oma.h b/ffmpeg/libavformat/oma.h
index 1f0ddf9..e2a187b 100644
--- a/ffmpeg/libavformat/oma.h
+++ b/ffmpeg/libavformat/oma.h
@@ -1,20 +1,20 @@
/*
* Sony OpenMG (OMA) common data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,4 +41,7 @@ extern const uint16_t ff_oma_srate_tab[8];
extern const AVCodecTag ff_oma_codec_tags[];
+extern const uint64_t ff_oma_chid_to_native_layout[7];
+extern const int ff_oma_chid_to_num_channels[7];
+
#endif /* AVFORMAT_OMA_H */
diff --git a/ffmpeg/libavformat/omadec.c b/ffmpeg/libavformat/omadec.c
index 9f65db0..6a08076 100644
--- a/ffmpeg/libavformat/omadec.c
+++ b/ffmpeg/libavformat/omadec.c
@@ -1,7 +1,7 @@
/*
* Sony OpenMG (OMA) demuxer
*
- * Copyright (c) 2008 Maxim Poliakovski
+ * Copyright (c) 2008, 2013 Maxim Poliakovski
* 2008 Benjamin Larsson
* 2011 David Goldwich
*
@@ -73,18 +73,20 @@ typedef struct OMAContext {
struct AVDES av_des;
} OMAContext;
-static void hex_log(AVFormatContext *s, int level, const char *name, const uint8_t *value, int len)
+static void hex_log(AVFormatContext *s, int level,
+ const char *name, const uint8_t *value, int len)
{
char buf[33];
len = FFMIN(len, 16);
if (av_log_get_level() < level)
return;
ff_data_to_hex(buf, value, len, 1);
- buf[len<<1] = '\0';
+ buf[len << 1] = '\0';
av_log(s, level, "%s: %s\n", name, buf);
}
-static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val, int len)
+static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val,
+ int len)
{
OMAContext *oc = s->priv_data;
@@ -112,13 +114,18 @@ static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val,
return 0;
}
-static int rprobe(AVFormatContext *s, uint8_t *enc_header, const uint8_t *r_val)
+#define OMA_RPROBE_M_VAL 48 + 1
+
+static int rprobe(AVFormatContext *s, uint8_t *enc_header, unsigned size,
+ const uint8_t *r_val)
{
OMAContext *oc = s->priv_data;
unsigned int pos;
struct AVDES av_des;
- if (!enc_header || !r_val)
+ if (!enc_header || !r_val ||
+ size < OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size ||
+ size < OMA_RPROBE_M_VAL)
return -1;
/* m_val */
@@ -139,35 +146,41 @@ static int rprobe(AVFormatContext *s, uint8_t *enc_header, const uint8_t *r_val)
return memcmp(&enc_header[pos], oc->sm_val, 8) ? -1 : 0;
}
-static int nprobe(AVFormatContext *s, uint8_t *enc_header, int size, const uint8_t *n_val)
+static int nprobe(AVFormatContext *s, uint8_t *enc_header, unsigned size,
+ const uint8_t *n_val)
{
OMAContext *oc = s->priv_data;
- uint32_t pos, taglen, datalen;
+ uint64_t pos;
+ uint32_t taglen, datalen;
struct AVDES av_des;
- if (!enc_header || !n_val)
+ if (!enc_header || !n_val ||
+ size < OMA_ENC_HEADER_SIZE + oc->k_size + 4)
return -1;
pos = OMA_ENC_HEADER_SIZE + oc->k_size;
if (!memcmp(&enc_header[pos], "EKB ", 4))
pos += 32;
+ if (size < pos + 44)
+ return -1;
+
if (AV_RB32(&enc_header[pos]) != oc->rid)
av_log(s, AV_LOG_DEBUG, "Mismatching RID\n");
- taglen = AV_RB32(&enc_header[pos+32]);
- datalen = AV_RB32(&enc_header[pos+36]) >> 4;
+ taglen = AV_RB32(&enc_header[pos + 32]);
+ datalen = AV_RB32(&enc_header[pos + 36]) >> 4;
- if(pos + (uint64_t)taglen + (((uint64_t)datalen)<<4) + 44 > size)
- return -1;
+ pos += 44L + taglen;
- pos += 44 + taglen;
+ if (pos + (((uint64_t)datalen) << 4) > size)
+ return -1;
av_des_init(&av_des, n_val, 192, 1);
while (datalen-- > 0) {
av_des_crypt(&av_des, oc->r_val, &enc_header[pos], 2, NULL, 1);
kset(s, oc->r_val, NULL, 16);
- if (!rprobe(s, enc_header, oc->r_val))
+ if (!rprobe(s, enc_header, size, oc->r_val))
return 0;
pos += 16;
}
@@ -196,12 +209,13 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
}
if (!em) {
av_log(s, AV_LOG_ERROR, "No encryption header found\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (geob->datasize < 64) {
- av_log(s, AV_LOG_ERROR, "Invalid GEOB data size: %u\n", geob->datasize);
- return -1;
+ av_log(s, AV_LOG_ERROR,
+ "Invalid GEOB data size: %u\n", geob->datasize);
+ return AVERROR_INVALIDDATA;
}
gdata = geob->data;
@@ -216,11 +230,10 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
if (memcmp(&gdata[OMA_ENC_HEADER_SIZE], "KEYRING ", 12)) {
av_log(s, AV_LOG_ERROR, "Invalid encryption header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- if ( OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size + 8 > geob->datasize
- || OMA_ENC_HEADER_SIZE + 48 > geob->datasize
- ) {
+ if (OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size + 8 > geob->datasize ||
+ OMA_ENC_HEADER_SIZE + 48 > geob->datasize) {
av_log(s, AV_LOG_ERROR, "Too little GEOB data\n");
return AVERROR_INVALIDDATA;
}
@@ -230,32 +243,36 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
memcpy(oc->iv, &header[0x58], 8);
hex_log(s, AV_LOG_DEBUG, "IV", oc->iv, 8);
- hex_log(s, AV_LOG_DEBUG, "CBC-MAC", &gdata[OMA_ENC_HEADER_SIZE+oc->k_size+oc->e_size+oc->i_size], 8);
+ hex_log(s, AV_LOG_DEBUG, "CBC-MAC",
+ &gdata[OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size],
+ 8);
if (s->keylen > 0) {
kset(s, s->key, s->key, s->keylen);
}
if (!memcmp(oc->r_val, (const uint8_t[8]){0}, 8) ||
- rprobe(s, gdata, oc->r_val) < 0 &&
+ rprobe(s, gdata, geob->datasize, oc->r_val) < 0 &&
nprobe(s, gdata, geob->datasize, oc->n_val) < 0) {
int i;
for (i = 0; i < FF_ARRAY_ELEMS(leaf_table); i += 2) {
uint8_t buf[16];
- AV_WL64(buf, leaf_table[i]);
- AV_WL64(&buf[8], leaf_table[i+1]);
+ AV_WL64(buf, leaf_table[i]);
+ AV_WL64(&buf[8], leaf_table[i + 1]);
kset(s, buf, buf, 16);
- if (!rprobe(s, gdata, oc->r_val) || !nprobe(s, gdata, geob->datasize, oc->n_val))
+ if (!rprobe(s, gdata, geob->datasize, oc->r_val) ||
+ !nprobe(s, gdata, geob->datasize, oc->n_val))
break;
}
if (i >= FF_ARRAY_ELEMS(leaf_table)) {
av_log(s, AV_LOG_ERROR, "Invalid key\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
}
/* e_val */
av_des_init(&oc->av_des, oc->m_val, 64, 0);
- av_des_crypt(&oc->av_des, oc->e_val, &gdata[OMA_ENC_HEADER_SIZE + 40], 1, NULL, 0);
+ av_des_crypt(&oc->av_des, oc->e_val,
+ &gdata[OMA_ENC_HEADER_SIZE + 40], 1, NULL, 0);
hex_log(s, AV_LOG_DEBUG, "EK", oc->e_val, 8);
/* init e_val */
@@ -267,7 +284,7 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header)
static int oma_read_header(AVFormatContext *s)
{
int ret, framesize, jsflag, samplerate;
- uint32_t codec_params;
+ uint32_t codec_params, channel_id;
int16_t eid;
uint8_t buf[EA3_HEADER_SIZE];
uint8_t *edata;
@@ -280,9 +297,10 @@ static int oma_read_header(AVFormatContext *s)
if (ret < EA3_HEADER_SIZE)
return -1;
- if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) {
+ if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}), 3) ||
+ buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) {
av_log(s, AV_LOG_ERROR, "Couldn't find the EA3 header !\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
oc->content_start = avio_tell(s->pb);
@@ -303,65 +321,85 @@ static int oma_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->start_time = 0;
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_tag = buf[32];
- st->codec->codec_id = ff_codec_get_id(ff_oma_codec_tags, st->codec->codec_tag);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_tag = buf[32];
+ st->codec->codec_id = ff_codec_get_id(ff_oma_codec_tags,
+ st->codec->codec_tag);
switch (buf[32]) {
- case OMA_CODECID_ATRAC3:
- samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7]*100;
- if (samplerate != 44100)
- avpriv_request_sample(s, "Sample rate %d", samplerate);
-
- framesize = (codec_params & 0x3FF) * 8;
- jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */
- st->codec->channels = 2;
- st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- st->codec->sample_rate = samplerate;
- st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024;
-
- /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */
- st->codec->extradata_size = 14;
- edata = av_mallocz(14 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!edata)
- return AVERROR(ENOMEM);
-
- st->codec->extradata = edata;
- AV_WL16(&edata[0], 1); // always 1
- AV_WL32(&edata[2], samplerate); // samples rate
- AV_WL16(&edata[6], jsflag); // coding mode
- AV_WL16(&edata[8], jsflag); // coding mode
- AV_WL16(&edata[10], 1); // always 1
- // AV_WL16(&edata[12], 0); // always 0
-
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
- break;
- case OMA_CODECID_ATRAC3P:
- st->codec->channels = (codec_params >> 10) & 7;
- framesize = ((codec_params & 0x3FF) * 8) + 8;
- st->codec->sample_rate = ff_oma_srate_tab[(codec_params >> 13) & 7]*100;
- st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024;
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
- av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n");
- break;
- case OMA_CODECID_MP3:
- st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
- framesize = 1024;
- break;
- case OMA_CODECID_LPCM:
- /* PCM 44.1 kHz 16 bit stereo big-endian */
- st->codec->channels = 2;
- st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- st->codec->sample_rate = 44100;
- framesize = 1024;
- /* bit rate = sample rate x PCM block align (= 4) x 8 */
- st->codec->bit_rate = st->codec->sample_rate * 32;
- st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
- break;
- default:
- av_log(s, AV_LOG_ERROR, "Unsupported codec %d!\n",buf[32]);
- return -1;
+ case OMA_CODECID_ATRAC3:
+ samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100;
+ if (!samplerate) {
+ av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (samplerate != 44100)
+ avpriv_request_sample(s, "Sample rate %d", samplerate);
+
+ framesize = (codec_params & 0x3FF) * 8;
+
+ /* get stereo coding mode, 1 for joint-stereo */
+ jsflag = (codec_params >> 17) & 1;
+
+ st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ st->codec->sample_rate = samplerate;
+ st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024;
+
+ /* fake the ATRAC3 extradata
+ * (wav format, makes stream copy to wav work) */
+ if (ff_alloc_extradata(st->codec, 14))
+ return AVERROR(ENOMEM);
+
+ edata = st->codec->extradata;
+ AV_WL16(&edata[0], 1); // always 1
+ AV_WL32(&edata[2], samplerate); // samples rate
+ AV_WL16(&edata[6], jsflag); // coding mode
+ AV_WL16(&edata[8], jsflag); // coding mode
+ AV_WL16(&edata[10], 1); // always 1
+ // AV_WL16(&edata[12], 0); // always 0
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ break;
+ case OMA_CODECID_ATRAC3P:
+ channel_id = (codec_params >> 10) & 7;
+ if (!channel_id) {
+ av_log(s, AV_LOG_ERROR,
+ "Invalid ATRAC-X channel id: %d\n", channel_id);
+ return AVERROR_INVALIDDATA;
+ }
+ st->codec->channel_layout = ff_oma_chid_to_native_layout[channel_id - 1];
+ st->codec->channels = ff_oma_chid_to_num_channels[channel_id - 1];
+ framesize = ((codec_params & 0x3FF) * 8) + 8;
+ samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100;
+ if (!samplerate) {
+ av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n");
+ return AVERROR_INVALIDDATA;
+ }
+ 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;
+ framesize = 1024;
+ break;
+ case OMA_CODECID_LPCM:
+ /* PCM 44.1 kHz 16 bit stereo big-endian */
+ st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ st->codec->sample_rate = 44100;
+ framesize = 1024;
+ /* bit rate = sample rate x PCM block align (= 4) x 8 */
+ st->codec->bit_rate = st->codec->sample_rate * 32;
+ st->codec->bits_per_coded_sample =
+ av_get_bits_per_sample(st->codec->codec_id);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "Unsupported codec %d!\n", buf[32]);
+ return AVERROR(ENOSYS);
}
st->codec->block_align = framesize;
@@ -376,14 +414,24 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt)
int packet_size = s->streams[0]->codec->block_align;
int ret = av_get_packet(s->pb, pkt, packet_size);
- if (ret <= 0)
- return AVERROR(EIO);
+ if (ret < packet_size)
+ pkt->flags |= AV_PKT_FLAG_CORRUPT;
+
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ return AVERROR_EOF;
pkt->stream_index = 0;
if (oc->encrypted) {
- /* previous unencrypted block saved in IV for the next packet (CBC mode) */
- av_des_crypt(&oc->av_des, pkt->data, pkt->data, (ret >> 3), oc->iv, 1);
+ /* previous unencrypted block saved in IV for
+ * the next packet (CBC mode) */
+ if (ret == packet_size)
+ av_des_crypt(&oc->av_des, pkt->data, pkt->data,
+ (packet_size >> 3), oc->iv, 1);
+ else
+ memset(oc->iv, 0, 8);
}
return ret;
@@ -391,23 +439,16 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt)
static int oma_read_probe(AVProbeData *p)
{
- const uint8_t *buf;
+ const uint8_t *buf = p->buf;
unsigned tag_len = 0;
- buf = p->buf;
-
- if (p->buf_size < ID3v2_HEADER_SIZE ||
- !ff_id3v2_match(buf, ID3v2_EA3_MAGIC) ||
- buf[3] != 3 || // version must be 3
- buf[4]) // flags byte zero
- return 0;
-
- tag_len = ff_id3v2_tag_len(buf);
+ if (p->buf_size >= ID3v2_HEADER_SIZE && ff_id3v2_match(buf, ID3v2_EA3_MAGIC))
+ tag_len = ff_id3v2_tag_len(buf);
/* 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 AVPROBE_SCORE_MAX / 2;
+ return tag_len ? AVPROBE_SCORE_EXTENSION : 0;
buf += tag_len;
@@ -417,26 +458,30 @@ static int oma_read_probe(AVProbeData *p)
return 0;
}
-static int oma_read_seek(struct AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+static int oma_read_seek(struct AVFormatContext *s,
+ int stream_index, int64_t timestamp, int flags)
{
OMAContext *oc = s->priv_data;
-
- ff_pcm_read_seek(s, stream_index, timestamp, flags);
-
- if (oc->encrypted) {
- /* readjust IV for CBC */
- int64_t pos = avio_tell(s->pb);
- if (pos < oc->content_start)
- memset(oc->iv, 0, 8);
- else {
- if (avio_seek(s->pb, -8, SEEK_CUR) < 0 || avio_read(s->pb, oc->iv, 8) < 8) {
- memset(oc->iv, 0, 8);
- return -1;
- }
- }
+ int err = ff_pcm_read_seek(s, stream_index, timestamp, flags);
+
+ if (!oc->encrypted)
+ return err;
+
+ /* readjust IV for CBC */
+ if (err || avio_tell(s->pb) < oc->content_start)
+ goto wipe;
+ if ((err = avio_seek(s->pb, -8, SEEK_CUR)) < 0)
+ goto wipe;
+ if ((err = avio_read(s->pb, oc->iv, 8)) < 8) {
+ if (err >= 0)
+ err = AVERROR_EOF;
+ goto wipe;
}
return 0;
+wipe:
+ memset(oc->iv, 0, 8);
+ return err;
}
AVInputFormat ff_oma_demuxer = {
diff --git a/ffmpeg/libavformat/omaenc.c b/ffmpeg/libavformat/omaenc.c
index 5c5aff7..b947987 100644
--- a/ffmpeg/libavformat/omaenc.c
+++ b/ffmpeg/libavformat/omaenc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2011 Michael Karcher
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/options.c b/ffmpeg/libavformat/options.c
index 42307d1..5218e5b 100644
--- a/ffmpeg/libavformat/options.c
+++ b/ffmpeg/libavformat/options.c
@@ -86,7 +86,7 @@ static AVClassCategory get_category(void *ptr)
static const AVClass av_format_context_class = {
.class_name = "AVFormatContext",
.item_name = format_to_name,
- .option = options,
+ .option = avformat_options,
.version = LIBAVUTIL_VERSION_INT,
.child_next = format_child_next,
.child_class_next = format_child_class_next,
diff --git a/ffmpeg/libavformat/options_table.h b/ffmpeg/libavformat/options_table.h
index 6750050..8145325 100644
--- a/ffmpeg/libavformat/options_table.h
+++ b/ffmpeg/libavformat/options_table.h
@@ -32,12 +32,13 @@
#define E AV_OPT_FLAG_ENCODING_PARAM
#define D AV_OPT_FLAG_DECODING_PARAM
-static const AVOption options[]={
+static const AVOption avformat_options[] = {
{"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT, {.i64 = 5000000 }, 32, INT_MAX, D},
{"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E},
-{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "fflags"},
+{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D|E, "fflags"},
+{"flush_packets", "reduce the latency by flushing out packets immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D, "fflags"},
{"ignidx", "ignore index", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNIDX }, INT_MIN, INT_MAX, D, "fflags"},
{"genpts", "generate pts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_GENPTS }, INT_MIN, INT_MAX, D, "fflags"},
{"nofillin", "do not fill in missing values that can be exactly calculated", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOFILLIN }, INT_MIN, INT_MAX, D, "fflags"},
@@ -45,10 +46,10 @@ static const AVOption options[]={
{"igndts", "ignore dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNDTS }, INT_MIN, INT_MAX, D, "fflags"},
{"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"},
{"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"},
-{"keepside", "dont merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"},
+{"keepside", "don't merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"},
{"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", "forces seeking to enable seek to any mode", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D},
+{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D},
{"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},
@@ -68,13 +69,14 @@ static const AVOption 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"},
-{"careful", "consider things that violate the spec 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"},
+{"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 shouldnt do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, 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 positive. 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},
-{"skip_initial_bytes", "skip initial bytes", OFFSET(skip_initial_bytes), 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},
+{"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},
{NULL},
};
diff --git a/ffmpeg/libavformat/os_support.c b/ffmpeg/libavformat/os_support.c
index 0a901f6..e8f063a 100644
--- a/ffmpeg/libavformat/os_support.c
+++ b/ffmpeg/libavformat/os_support.c
@@ -27,55 +27,18 @@
#include "avformat.h"
#include "os_support.h"
-#if defined(_WIN32) && !defined(__MINGW32CE__)
-#undef open
-#undef lseek
-#undef stat
-#undef fstat
-#include <fcntl.h>
-#include <io.h>
-#include <windows.h>
-#include <share.h>
-
-int ff_win32_open(const char *filename_utf8, int oflag, int pmode)
-{
- int fd;
- int num_chars;
- wchar_t *filename_w;
-
- /* convert UTF-8 to wide chars */
- num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0);
- if (num_chars <= 0)
- goto fallback;
- filename_w = av_mallocz(sizeof(wchar_t) * num_chars);
- if (!filename_w)
- return -1;
- MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars);
-
- fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode);
- av_freep(&filename_w);
-
- if (fd != -1 || (oflag & O_CREAT))
- return fd;
-
-fallback:
- /* filename maybe be in CP_ACP */
- return _sopen(filename_utf8, oflag, SH_DENYNO, pmode);
-}
-#endif
-
#if CONFIG_NETWORK
#include <fcntl.h>
#if !HAVE_POLL_H
#if HAVE_SYS_TIME_H
#include <sys/time.h>
-#endif
+#endif /* HAVE_SYS_TIME_H */
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#elif HAVE_SYS_SELECT_H
#include <sys/select.h>
-#endif
-#endif
+#endif /* HAVE_WINSOCK2_H */
+#endif /* !HAVE_POLL_H */
#include "network.h"
@@ -119,7 +82,7 @@ int ff_getaddrinfo(const char *node, const char *service,
win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo");
if (win_getaddrinfo)
return win_getaddrinfo(node, service, hints, res);
-#endif
+#endif /* HAVE_WINSOCK2_H */
*res = NULL;
sin = av_mallocz(sizeof(struct sockaddr_in));
@@ -193,7 +156,7 @@ void ff_freeaddrinfo(struct addrinfo *res)
win_freeaddrinfo(res);
return;
}
-#endif
+#endif /* HAVE_WINSOCK2_H */
av_free(res->ai_canonname);
av_free(res->ai_addr);
@@ -214,7 +177,7 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen,
win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo");
if (win_getnameinfo)
return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
-#endif
+#endif /* HAVE_WINSOCK2_H */
if (sa->sa_family != AF_INET)
return EAI_FAMILY;
@@ -245,7 +208,7 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen,
#if HAVE_GETSERVBYPORT
if (!(flags & NI_NUMERICSERV))
ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp");
-#endif
+#endif /* HAVE_GETSERVBYPORT */
if (ent)
snprintf(serv, servlen, "%s", ent->s_name);
@@ -275,7 +238,7 @@ const char *ff_gai_strerror(int ecode)
#if EAI_NODATA != EAI_NONAME
case EAI_NODATA:
return "No address associated with hostname";
-#endif
+#endif /* EAI_NODATA != EAI_NONAME */
case EAI_NONAME:
return "The name does not resolve for the supplied parameters";
case EAI_SERVICE:
@@ -298,7 +261,7 @@ int ff_socket_nonblock(int socket, int enable)
return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
else
return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK);
-#endif
+#endif /* HAVE_WINSOCK2_H */
}
#if !HAVE_POLL_H
@@ -316,7 +279,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout)
errno = EINVAL;
return -1;
}
-#endif
+#endif /* HAVE_WINSOCK2_H */
FD_ZERO(&read_set);
FD_ZERO(&write_set);
@@ -331,7 +294,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout)
errno = EINVAL;
return -1;
}
-#endif
+#endif /* !HAVE_WINSOCK2_H */
if (fds[i].events & POLLIN)
FD_SET(fds[i].fd, &read_set);
@@ -373,5 +336,6 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout)
return rc;
}
-#endif /* HAVE_POLL_H */
+#endif /* !HAVE_POLL_H */
+
#endif /* CONFIG_NETWORK */
diff --git a/ffmpeg/libavformat/os_support.h b/ffmpeg/libavformat/os_support.h
index e5f31e0..7c7cd1f 100644
--- a/ffmpeg/libavformat/os_support.h
+++ b/ffmpeg/libavformat/os_support.h
@@ -54,8 +54,6 @@
#include <io.h>
#endif
#define mkdir(a, b) _mkdir(a)
-#else
-#include <sys/stat.h>
#endif
static inline int is_dos_path(const char *path)
@@ -86,11 +84,6 @@ static inline int is_dos_path(const char *path)
#endif
#endif
-#if defined(_WIN32) && !defined(__MINGW32CE__)
-int ff_win32_open(const char *filename, int oflag, int pmode);
-#define open ff_win32_open
-#endif
-
#if CONFIG_NETWORK
#if !HAVE_SOCKLEN_T
typedef int socklen_t;
diff --git a/ffmpeg/libavformat/paf.c b/ffmpeg/libavformat/paf.c
index 09786eb..09aefe6 100644
--- a/ffmpeg/libavformat/paf.c
+++ b/ffmpeg/libavformat/paf.c
@@ -233,10 +233,11 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
p->current_frame_block++;
}
- size = p->video_size - p->frames_offset_table[p->current_frame];
- if (size < 1)
+ if (p->frames_offset_table[p->current_frame] >= p->video_size)
return AVERROR_INVALIDDATA;
+ size = p->video_size - p->frames_offset_table[p->current_frame];
+
if (av_new_packet(pkt, size) < 0)
return AVERROR(ENOMEM);
diff --git a/ffmpeg/libavformat/pjsdec.c b/ffmpeg/libavformat/pjsdec.c
index ef2b626..a69a316 100644
--- a/ffmpeg/libavformat/pjsdec.c
+++ b/ffmpeg/libavformat/pjsdec.c
@@ -39,7 +39,7 @@ static int pjs_probe(AVProbeData *p)
int64_t start, end;
const unsigned char *ptr = p->buf;
- if (sscanf(ptr, "%"PRId64",%"PRId64",%c", &start, &end, &c) == 3) {
+ if (sscanf(ptr, "%"SCNd64",%"SCNd64",%c", &start, &end, &c) == 3) {
size_t q1pos = strcspn(ptr, "\"");
size_t q2pos = q1pos + strcspn(ptr + q1pos + 1, "\"") + 1;
if (strcspn(ptr, "\r\n") > q2pos)
@@ -52,7 +52,7 @@ static int64_t read_ts(char **line, int *duration)
{
int64_t start, end;
- if (sscanf(*line, "%"PRId64",%"PRId64, &start, &end) == 2) {
+ if (sscanf(*line, "%"SCNd64",%"SCNd64, &start, &end) == 2) {
*line += strcspn(*line, "\"") + 1;
*duration = end - start;
return start;
diff --git a/ffmpeg/libavformat/pmpdec.c b/ffmpeg/libavformat/pmpdec.c
index 2fe6c46..71f450e 100644
--- a/ffmpeg/libavformat/pmpdec.c
+++ b/ffmpeg/libavformat/pmpdec.c
@@ -174,7 +174,7 @@ static int pmp_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags)
{
PMPContext *pmp = s->priv_data;
pmp->cur_stream = 0;
- // fallback to default seek now
+ // fall back on default seek now
return -1;
}
diff --git a/ffmpeg/libavformat/psxstr.c b/ffmpeg/libavformat/psxstr.c
index 90c933e..5efcadf 100644
--- a/ffmpeg/libavformat/psxstr.c
+++ b/ffmpeg/libavformat/psxstr.c
@@ -30,6 +30,7 @@
*/
#include "libavutil/channel_layout.h"
+#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
@@ -126,7 +127,7 @@ static int str_probe(AVProbeData *p)
}
/* MPEG files (like those ripped from VCDs) can also look like this;
* only return half certainty */
- if(vid+aud > 3) return 50;
+ if(vid+aud > 3) return AVPROBE_SCORE_EXTENSION;
else if(vid+aud) return 1;
else return 0;
}
@@ -220,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 =
@@ -237,7 +239,9 @@ static int str_read_packet(AVFormatContext *s,
pkt->size= -1;
pkt->buf = NULL;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
return 0;
}
diff --git a/ffmpeg/libavformat/pva.c b/ffmpeg/libavformat/pva.c
index ae42c83..18ab1cd 100644
--- a/ffmpeg/libavformat/pva.c
+++ b/ffmpeg/libavformat/pva.c
@@ -49,7 +49,7 @@ static int pva_probe(AVProbeData * pd) {
if (pd->buf_size >= len + 8 &&
pva_check(buf + len) >= 0)
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
return AVPROBE_SCORE_MAX / 4;
}
@@ -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/ffmpeg/libavformat/r3d.c b/ffmpeg/libavformat/r3d.c
index 3b3ecce..0719fb6 100644
--- a/ffmpeg/libavformat/r3d.c
+++ b/ffmpeg/libavformat/r3d.c
@@ -19,8 +19,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-//#define DEBUG
-
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
@@ -87,7 +85,7 @@ static int r3d_read_red1(AVFormatContext *s)
framerate.num = avio_rb16(s->pb);
framerate.den = avio_rb16(s->pb);
- if (framerate.num && framerate.den) {
+ if (framerate.num > 0 && framerate.den > 0) {
#if FF_API_R_FRAME_RATE
st->r_frame_rate =
#endif
@@ -285,8 +283,8 @@ static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom)
dts = avio_rb32(s->pb);
st->codec->sample_rate = avio_rb32(s->pb);
- if (st->codec->sample_rate < 0) {
- av_log(s, AV_LOG_ERROR, "negative sample rate\n");
+ if (st->codec->sample_rate <= 0) {
+ av_log(s, AV_LOG_ERROR, "Bad sample rate\n");
return AVERROR_INVALIDDATA;
}
diff --git a/ffmpeg/libavformat/rawdec.c b/ffmpeg/libavformat/rawdec.c
index 07c2782..a9ff22a 100644
--- a/ffmpeg/libavformat/rawdec.c
+++ b/ffmpeg/libavformat/rawdec.c
@@ -70,7 +70,6 @@ int ff_raw_video_read_header(AVFormatContext *s)
{
AVStream *st;
FFRawVideoDemuxerContext *s1 = s->priv_data;
- AVRational framerate;
int ret = 0;
@@ -84,27 +83,43 @@ int ff_raw_video_read_header(AVFormatContext *s)
st->codec->codec_id = s->iformat->raw_codec_id;
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
- if ((ret = av_parse_video_rate(&framerate, s1->framerate)) < 0) {
- av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s1->framerate);
- goto fail;
- }
-
- st->codec->time_base = av_inv_q(framerate);
+ st->codec->time_base = av_inv_q(s1->framerate);
avpriv_set_pts_info(st, 64, 1, 1200000);
fail:
return ret;
}
+static int ff_raw_data_read_header(AVFormatContext *s)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ st->codec->codec_id = s->iformat->raw_codec_id;
+ st->start_time = 0;
+ return 0;
+}
+
/* Note: Do not forget to add new entries to the Makefile as well. */
#define OFFSET(x) offsetof(FFRawVideoDemuxerContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
const AVOption ff_rawvideo_options[] = {
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC},
+ { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC},
{ NULL },
};
+#if CONFIG_DATA_DEMUXER
+AVInputFormat ff_data_demuxer = {
+ .name = "data",
+ .long_name = NULL_IF_CONFIG_SMALL("raw data"),
+ .read_header = ff_raw_data_read_header,
+ .read_packet = ff_raw_read_partial_packet,
+ .raw_codec_id = AV_CODEC_ID_NONE,
+};
+#endif
+
#if CONFIG_LATM_DEMUXER
AVInputFormat ff_latm_demuxer = {
.name = "latm",
diff --git a/ffmpeg/libavformat/rawdec.h b/ffmpeg/libavformat/rawdec.h
index d978295..5910855 100644
--- a/ffmpeg/libavformat/rawdec.h
+++ b/ffmpeg/libavformat/rawdec.h
@@ -30,7 +30,7 @@ typedef struct FFRawVideoDemuxerContext {
const AVClass *class; /**< Class for private options. */
char *video_size; /**< String describing video size, set by a private option. */
char *pixel_format; /**< Set by a private option. */
- char *framerate; /**< String describing framerate, set by a private option. */
+ AVRational framerate; /**< AVRational describing framerate, set by a private option. */
} FFRawVideoDemuxerContext;
extern const AVOption ff_rawvideo_options[];
diff --git a/ffmpeg/libavformat/rawenc.c b/ffmpeg/libavformat/rawenc.c
index b804c24..5044698 100644
--- a/ffmpeg/libavformat/rawenc.c
+++ b/ffmpeg/libavformat/rawenc.c
@@ -26,7 +26,16 @@
int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
- avio_flush(s->pb);
+ 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;
}
@@ -40,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,
};
@@ -52,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,
};
@@ -64,6 +75,17 @@ 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,
+};
+#endif
+
+#if CONFIG_DATA_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,
};
@@ -76,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,
};
@@ -88,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,
};
@@ -101,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,
};
@@ -114,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,
};
@@ -127,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,
};
@@ -140,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,
};
@@ -153,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,
};
@@ -166,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,
};
@@ -178,6 +208,7 @@ 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,
};
@@ -203,6 +234,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,
};
@@ -215,6 +247,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,
};
@@ -228,6 +261,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,
};
@@ -240,6 +274,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,
};
@@ -264,6 +299,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,
};
@@ -276,6 +312,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/ffmpeg/libavformat/rawvideodec.c b/ffmpeg/libavformat/rawvideodec.c
index 8460781..cbcae43 100644
--- a/ffmpeg/libavformat/rawvideodec.c
+++ b/ffmpeg/libavformat/rawvideodec.c
@@ -27,18 +27,16 @@
typedef struct RawVideoDemuxerContext {
const AVClass *class; /**< Class for private options. */
- char *video_size; /**< String describing video size, set by a private option. */
+ int width, height; /**< Integers describing video size, set by a private option. */
char *pixel_format; /**< Set by a private option. */
- char *framerate; /**< String describing framerate, set by a private option. */
+ AVRational framerate; /**< AVRational describing framerate, set by a private option. */
} RawVideoDemuxerContext;
static int rawvideo_read_header(AVFormatContext *ctx)
{
RawVideoDemuxerContext *s = ctx->priv_data;
- int width = 0, height = 0, ret = 0;
enum AVPixelFormat pix_fmt;
- AVRational framerate;
AVStream *st;
st = avformat_new_stream(ctx, NULL);
@@ -49,30 +47,18 @@ static int rawvideo_read_header(AVFormatContext *ctx)
st->codec->codec_id = ctx->iformat->raw_codec_id;
- if (s->video_size &&
- (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Couldn't parse video size.\n");
- return ret;
- }
-
if ((pix_fmt = av_get_pix_fmt(s->pixel_format)) == AV_PIX_FMT_NONE) {
av_log(ctx, AV_LOG_ERROR, "No such pixel format: %s.\n",
s->pixel_format);
return AVERROR(EINVAL);
}
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n",
- s->framerate);
- return ret;
- }
-
- avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
+ avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num);
- st->codec->width = width;
- st->codec->height = height;
+ st->codec->width = s->width;
+ st->codec->height = s->height;
st->codec->pix_fmt = pix_fmt;
- st->codec->bit_rate = av_rescale_q(avpicture_get_size(st->codec->pix_fmt, width, height),
+ st->codec->bit_rate = av_rescale_q(avpicture_get_size(st->codec->pix_fmt, s->width, s->height),
(AVRational){8,1}, st->time_base);
return 0;
@@ -103,9 +89,9 @@ static int rawvideo_read_packet(AVFormatContext *s, AVPacket *pkt)
#define OFFSET(x) offsetof(RawVideoDemuxerContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption rawvideo_options[] = {
- { "video_size", "set frame size", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
{ "pixel_format", "set pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = "yuv420p"}, 0, 0, DEC },
- { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ NULL },
};
diff --git a/ffmpeg/libavformat/rdt.c b/ffmpeg/libavformat/rdt.c
index 695323a..201a3e0 100644
--- a/ffmpeg/libavformat/rdt.c
+++ b/ffmpeg/libavformat/rdt.c
@@ -98,7 +98,7 @@ ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
unsigned char zres[16],
buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
#define XOR_TABLE_SIZE 37
- const unsigned char xor_table[XOR_TABLE_SIZE] = {
+ static const unsigned char xor_table[XOR_TABLE_SIZE] = {
0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
@@ -419,15 +419,16 @@ rdt_parse_sdp_line (AVFormatContext *s, int st_index,
for (n = 0; n < s->nb_streams; n++)
if (s->streams[n]->id == stream->id) {
- int count = s->streams[n]->index + 1;
+ int count = s->streams[n]->index + 1, err;
if (first == -1) first = n;
if (rdt->nb_rmst < count) {
- RMStream **rmst= av_realloc(rdt->rmst, count*sizeof(*rmst));
- if (!rmst)
- return AVERROR(ENOMEM);
- memset(rmst + rdt->nb_rmst, 0,
- (count - rdt->nb_rmst) * sizeof(*rmst));
- rdt->rmst = rmst;
+ if ((err = av_reallocp(&rdt->rmst,
+ count * sizeof(*rdt->rmst))) < 0) {
+ rdt->nb_rmst = 0;
+ return err;
+ }
+ memset(rdt->rmst + rdt->nb_rmst, 0,
+ (count - rdt->nb_rmst) * sizeof(*rdt->rmst));
rdt->nb_rmst = count;
}
rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream();
@@ -548,7 +549,7 @@ rdt_free_context (PayloadContext *rdt)
}
#define RDT_HANDLER(n, s, t) \
-static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
+static RTPDynamicProtocolHandler rdt_ ## n ## _handler = { \
.enc_name = s, \
.codec_type = t, \
.codec_id = AV_CODEC_ID_NONE, \
@@ -563,10 +564,10 @@ RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO);
RDT_HANDLER(video, "x-pn-realvideo", AVMEDIA_TYPE_VIDEO);
RDT_HANDLER(audio, "x-pn-realaudio", AVMEDIA_TYPE_AUDIO);
-void av_register_rdt_dynamic_payload_handlers(void)
+void ff_register_rdt_dynamic_payload_handlers(void)
{
- ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
- ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
- ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
- ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
+ ff_register_dynamic_payload_handler(&rdt_video_handler);
+ ff_register_dynamic_payload_handler(&rdt_audio_handler);
+ ff_register_dynamic_payload_handler(&rdt_live_video_handler);
+ ff_register_dynamic_payload_handler(&rdt_live_audio_handler);
}
diff --git a/ffmpeg/libavformat/rdt.h b/ffmpeg/libavformat/rdt.h
index c2ec94b..ce6026f 100644
--- a/ffmpeg/libavformat/rdt.h
+++ b/ffmpeg/libavformat/rdt.h
@@ -62,7 +62,7 @@ void ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
/**
* Register RDT-related dynamic payload handlers with our cache.
*/
-void av_register_rdt_dynamic_payload_handlers(void);
+void ff_register_rdt_dynamic_payload_handlers(void);
/**
* Add subscription information to Subscribe parameter string.
diff --git a/ffmpeg/libavformat/realtextdec.c b/ffmpeg/libavformat/realtextdec.c
index 67bc339..5e4981a 100644
--- a/ffmpeg/libavformat/realtextdec.c
+++ b/ffmpeg/libavformat/realtextdec.c
@@ -41,7 +41,7 @@ static int realtext_probe(AVProbeData *p)
if (AV_RB24(ptr) == 0xEFBBBF)
ptr += 3; /* skip UTF-8 BOM */
- return !av_strncasecmp(ptr, "<window", 7) ? AVPROBE_SCORE_MAX/2 : 0;
+ return !av_strncasecmp(ptr, "<window", 7) ? AVPROBE_SCORE_EXTENSION : 0;
}
static int read_ts(const char *s)
diff --git a/ffmpeg/libavformat/riff.c b/ffmpeg/libavformat/riff.c
index ac1a4ff..52640d1 100644
--- a/ffmpeg/libavformat/riff.c
+++ b/ffmpeg/libavformat/riff.c
@@ -19,19 +19,16 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/mathematics.h"
+#include "libavutil/error.h"
#include "libavcodec/avcodec.h"
#include "avformat.h"
-#include "avio_internal.h"
#include "riff.h"
-#include "libavcodec/bytestream.h"
-#include "libavutil/avassert.h"
-/* Note: when encoding, the first matching tag is used, so order is
- important if multiple tags possible for a given codec.
- Note also that this list is used for more than just riff, other
- files use it as well.
-*/
+/* Note: When encoding, the first matching tag is used, so order is
+ * important if multiple tags are possible for a given codec.
+ * Note also that this list is used for more than just riff, other
+ * files use it as well.
+ */
const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('H', '2', '6', '4') },
{ AV_CODEC_ID_H264, MKTAG('h', '2', '6', '4') },
@@ -43,6 +40,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ 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('G', 'A', 'V', 'C') }, /* GeoVision camera */
+ { AV_CODEC_ID_H264, MKTAG('U', 'M', 'S', 'V') },
{ 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') },
@@ -52,7 +51,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H263, MKTAG('M', '2', '6', '3') },
{ AV_CODEC_ID_H263, MKTAG('l', 's', 'v', 'm') },
{ AV_CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
- { AV_CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
+ { AV_CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* Intel H.263 */
{ AV_CODEC_ID_H261, MKTAG('H', '2', '6', '1') },
{ AV_CODEC_ID_H263, MKTAG('U', '2', '6', '3') },
{ AV_CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') },
@@ -61,8 +60,10 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
{ AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
{ AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
- { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 0 ) }, /* some broken avi use this */
- { AV_CODEC_ID_MPEG4, MKTAG('Z', 'M', 'P', '4') }, /* some broken avi use this */
+ /* some broken AVIs use this */
+ { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 0 ) },
+ /* some broken AVIs use this */
+ { AV_CODEC_ID_MPEG4, MKTAG('Z', 'M', 'P', '4') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') },
{ AV_CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') },
{ AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
@@ -71,7 +72,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') },
{ AV_CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') },
{ AV_CODEC_ID_MPEG4, MKTAG('3', 'I', 'V', '2') },
- { AV_CODEC_ID_MPEG4, MKTAG('W', 'A', 'W', 'V') }, /* WaWv MPEG-4 Video Codec */
+ /* WaWv MPEG-4 Video Codec */
+ { AV_CODEC_ID_MPEG4, MKTAG('W', 'A', 'W', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('F', 'F', 'D', 'S') },
{ AV_CODEC_ID_MPEG4, MKTAG('F', 'V', 'F', 'W') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'C', 'O', 'D') },
@@ -82,18 +84,26 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('V', 'I', 'D', 'M') },
{ AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'T', '3') },
{ AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'X') },
- { AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') }, /* flipped video */
+ /* flipped video */
+ { AV_CODEC_ID_MPEG4, MKTAG('G', '2', '6', '4') },
+ /* flipped video */
+ { AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') },
+ { AV_CODEC_ID_MPEG4, MKTAG('D', 'M', '4', 'V') },
{ 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') },
- { AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') }, /* Ephv MPEG-4 */
+ /* Ephv MPEG-4 */
+ { AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('E', 'M', '4', 'A') },
- { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'C', 'C') }, /* Divio MPEG-4 */
+ /* Divio MPEG-4 */
+ { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'C', 'C') },
{ AV_CODEC_ID_MPEG4, MKTAG('S', 'N', '4', '0') },
{ AV_CODEC_ID_MPEG4, MKTAG('V', 'S', 'P', 'X') },
{ AV_CODEC_ID_MPEG4, MKTAG('U', 'L', 'D', 'X') },
{ AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'V') },
- { AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') }, /* Samsung SHR-6040 */
+ /* Samsung SHR-6040 */
+ { AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') },
{ AV_CODEC_ID_MPEG4, MKTAG('S', 'M', '4', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'X') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'r', 'e', 'X') },
@@ -122,9 +132,12 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', '0') },
- { AV_CODEC_ID_DVVIDEO, MKTAG('c', 'd', 'v', 'c') }, /* Canopus DV */
- { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', 'H') }, /* Canopus DV */
- { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', '5') }, /* Canopus DV */
+ /* Canopus DV */
+ { AV_CODEC_ID_DVVIDEO, MKTAG('c', 'd', 'v', 'c') },
+ /* Canopus DV */
+ { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', 'H') },
+ /* Canopus DV */
+ { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', '5') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 's') },
{ AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '1') },
@@ -144,10 +157,12 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 16) },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') },
- { AV_CODEC_ID_MPEG2VIDEO, MKTAG('L', 'M', 'P', '2') }, /* Lead MPEG2 in avi */
+ /* Lead MPEG-2 in AVI */
+ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('L', 'M', 'P', '2') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('s', 'l', 'i', 'f') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('E', 'M', '2', 'V') },
- { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') }, /* Matrox MPEG2 intra-only */
+ /* Matrox MPEG-2 intra-only */
+ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') },
{ AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', 'v') },
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('B', 'W', '1', '0') },
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('X', 'M', 'P', 'G') }, /* Xing MPEG intra only */
@@ -156,23 +171,31 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') },
{ AV_CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') },
{ AV_CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') },
- { AV_CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */
- { AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */
+ /* Pegasus lossless JPEG */
+ { AV_CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') },
+ /* JPEG-LS custom FOURCC for AVI - encoder */
+ { AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'L', 'S') },
{ AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'P', 'G') },
- { AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */
+ /* JPEG-LS custom FOURCC for AVI - decoder */
+ { AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') },
{ AV_CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') },
{ AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') },
{ AV_CODEC_ID_AVRN, MKTAG('A', 'V', 'R', 'n') },
{ AV_CODEC_ID_MJPEG, MKTAG('A', 'C', 'D', 'V') },
{ AV_CODEC_ID_MJPEG, MKTAG('Q', 'I', 'V', 'G') },
- { AV_CODEC_ID_MJPEG, MKTAG('S', 'L', 'M', 'J') }, /* SL M-JPEG */
- { AV_CODEC_ID_MJPEG, MKTAG('C', 'J', 'P', 'G') }, /* Creative Webcam JPEG */
- { AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'L', 'V') }, /* Intel JPEG Library Video Codec */
- { AV_CODEC_ID_MJPEG, MKTAG('M', 'V', 'J', 'P') }, /* Midvid JPEG Video Codec */
+ /* SL M-JPEG */
+ { AV_CODEC_ID_MJPEG, MKTAG('S', 'L', 'M', 'J') },
+ /* Creative Webcam JPEG */
+ { AV_CODEC_ID_MJPEG, MKTAG('C', 'J', 'P', 'G') },
+ /* Intel JPEG Library Video Codec */
+ { AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'L', 'V') },
+ /* Midvid JPEG Video Codec */
+ { AV_CODEC_ID_MJPEG, MKTAG('M', 'V', 'J', 'P') },
{ AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'I', '1') },
{ AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'I', '2') },
{ AV_CODEC_ID_MJPEG, MKTAG('M', 'T', 'S', 'J') },
- { AV_CODEC_ID_MJPEG, MKTAG('Z', 'J', 'P', 'G') }, /* Paradigm Matrix M-JPEG Codec */
+ /* Paradigm Matrix M-JPEG Codec */
+ { AV_CODEC_ID_MJPEG, MKTAG('Z', 'J', 'P', 'G') },
{ AV_CODEC_ID_MJPEG, MKTAG('M', 'M', 'J', 'P') },
{ AV_CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') },
{ AV_CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') },
@@ -202,7 +225,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '8', ' ', ' ') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', 'U', '9') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */
+ /* SoftLab-NSK VideoTizer */
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('V', 'D', 'T', 'Z') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '1', '1') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'V', '1', '2') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'V', '2', '1') },
@@ -231,9 +255,11 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
+ { 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_VP8, MKTAG('V', 'P', '8', '0') },
+ { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') },
{ AV_CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') },
{ AV_CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') },
{ AV_CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') },
@@ -304,21 +330,20 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_DPX, MKTAG('d', 'p', 'x', ' ') },
{ AV_CODEC_ID_KGV1, MKTAG('K', 'G', 'V', '1') },
{ AV_CODEC_ID_LAGARITH, MKTAG('L', 'A', 'G', 'S') },
- { 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_AMV, MKTAG('A', 'M', 'V', 'F') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'A') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'G') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '0') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') },
+ /* Ut Video version 13.0.1 BT.709 codecs */
+ { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') },
+ { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') },
{ AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') },
{ AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') },
{ AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') },
{ AV_CODEC_ID_ZEROCODEC, MKTAG('Z', 'E', 'C', 'O') },
{ AV_CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') },
{ AV_CODEC_ID_FLIC, MKTAG('A', 'F', 'L', 'C') },
- { AV_CODEC_ID_EXR, MKTAG('e', 'x', 'r', ' ') },
{ AV_CODEC_ID_MSS1, MKTAG('M', 'S', 'S', '1') },
{ AV_CODEC_ID_MSA1, MKTAG('M', 'S', 'A', '1') },
{ AV_CODEC_ID_TSCC2, MKTAG('T', 'S', 'C', '2') },
@@ -328,27 +353,34 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
{ AV_CODEC_ID_012V, MKTAG('0', '1', '2', 'v') },
{ AV_CODEC_ID_012V, MKTAG('a', '1', '2', 'v') },
+ { 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_NONE, 0 }
};
const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_PCM_S16LE, 0x0001 },
- { AV_CODEC_ID_PCM_U8, 0x0001 }, /* must come after s16le in this list */
+ /* must come after s16le in this list */
+ { AV_CODEC_ID_PCM_U8, 0x0001 },
{ AV_CODEC_ID_PCM_S24LE, 0x0001 },
{ AV_CODEC_ID_PCM_S32LE, 0x0001 },
{ AV_CODEC_ID_ADPCM_MS, 0x0002 },
{ AV_CODEC_ID_PCM_F32LE, 0x0003 },
- { AV_CODEC_ID_PCM_F64LE, 0x0003 }, /* must come after f32le in this list */
+ /* must come after f32le in this list */
+ { AV_CODEC_ID_PCM_F64LE, 0x0003 },
{ AV_CODEC_ID_PCM_ALAW, 0x0006 },
{ AV_CODEC_ID_PCM_MULAW, 0x0007 },
{ AV_CODEC_ID_WMAVOICE, 0x000A },
{ AV_CODEC_ID_ADPCM_IMA_OKI, 0x0010 },
{ AV_CODEC_ID_ADPCM_IMA_WAV, 0x0011 },
- { AV_CODEC_ID_PCM_ZORK, 0x0011 }, /* must come after adpcm_ima_wav in this list */
+ /* must come after adpcm_ima_wav in this list */
+ { AV_CODEC_ID_PCM_ZORK, 0x0011 },
{ AV_CODEC_ID_ADPCM_IMA_OKI, 0x0017 },
{ AV_CODEC_ID_ADPCM_YAMAHA, 0x0020 },
{ AV_CODEC_ID_TRUESPEECH, 0x0022 },
{ AV_CODEC_ID_GSM_MS, 0x0031 },
+ { AV_CODEC_ID_GSM_MS, 0x0032 }, /* msn audio */
{ AV_CODEC_ID_AMR_NB, 0x0038 }, /* rogue format number */
{ AV_CODEC_ID_G723_1, 0x0042 },
{ AV_CODEC_ID_ADPCM_G726, 0x0045 },
@@ -356,11 +388,15 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_MP3, 0x0055 },
{ AV_CODEC_ID_AMR_NB, 0x0057 },
{ AV_CODEC_ID_AMR_WB, 0x0058 },
- { AV_CODEC_ID_ADPCM_IMA_DK4, 0x0061 }, /* rogue format number */
- { AV_CODEC_ID_ADPCM_IMA_DK3, 0x0062 }, /* rogue format number */
+ /* rogue format number */
+ { AV_CODEC_ID_ADPCM_IMA_DK4, 0x0061 },
+ /* rogue format number */
+ { AV_CODEC_ID_ADPCM_IMA_DK3, 0x0062 },
+ { AV_CODEC_ID_ADPCM_G726, 0x0064 },
{ AV_CODEC_ID_ADPCM_IMA_WAV, 0x0069 },
- { AV_CODEC_ID_VOXWARE, 0x0075 },
+ { AV_CODEC_ID_METASOUND, 0x0075 },
{ AV_CODEC_ID_AAC, 0x00ff },
+ { AV_CODEC_ID_G723_1, 0x0111 },
{ AV_CODEC_ID_SIPR, 0x0130 },
{ AV_CODEC_ID_WMAV1, 0x0160 },
{ AV_CODEC_ID_WMAV2, 0x0161 },
@@ -373,7 +409,8 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_IAC, 0x0402 },
{ AV_CODEC_ID_GSM_MS, 0x1500 },
{ AV_CODEC_ID_TRUESPEECH, 0x1501 },
- { AV_CODEC_ID_AAC, 0x1600 }, /* ADTS AAC */
+ /* ADTS AAC */
+ { AV_CODEC_ID_AAC, 0x1600 },
{ AV_CODEC_ID_AAC_LATM, 0x1602 },
{ AV_CODEC_ID_AC3, 0x2000 },
{ AV_CODEC_ID_DTS, 0x2001 },
@@ -382,486 +419,40 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_PCM_MULAW, 0x6c75 },
{ 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_AAC, 0xA106 },
{ AV_CODEC_ID_SPEEX, 0xA109 },
{ AV_CODEC_ID_FLAC, 0xF1AC },
- { AV_CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' },
- { AV_CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id?
+ { AV_CODEC_ID_ADPCM_SWF, ('S' << 8) + 'F' },
+ /* HACK/FIXME: Does Vorbis in WAV/AVI have an (in)official ID? */
+ { AV_CODEC_ID_VORBIS, ('V' << 8) + 'o' },
{ AV_CODEC_ID_NONE, 0 },
};
-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}
-};
-
const AVMetadataConv ff_riff_info_conv[] = {
- { "IART", "artist" },
- { "ICMT", "comment" },
- { "ICOP", "copyright" },
- { "ICRD", "date" },
- { "IGNR", "genre" },
- { "ILNG", "language" },
- { "INAM", "title" },
- { "IPRD", "album" },
- { "IPRT", "track" },
- { "ISFT", "encoder" },
- { "ISMP", "timecode" },
- { "ITCH", "encoded_by"},
+ { "IART", "artist" },
+ { "ICMT", "comment" },
+ { "ICOP", "copyright" },
+ { "ICRD", "date" },
+ { "IGNR", "genre" },
+ { "ILNG", "language" },
+ { "INAM", "title" },
+ { "IPRD", "album" },
+ { "IPRT", "track" },
+ { "ITRK", "track" },
+ { "ISFT", "encoder" },
+ { "ISMP", "timecode" },
+ { "ITCH", "encoded_by" },
{ 0 },
};
-#if CONFIG_MUXERS
-int64_t ff_start_tag(AVIOContext *pb, const char *tag)
-{
- ffio_wfourcc(pb, tag);
- avio_wl32(pb, 0);
- return avio_tell(pb);
-}
-
-void ff_end_tag(AVIOContext *pb, int64_t start)
-{
- int64_t pos;
-
- av_assert0((start&1) == 0);
-
- pos = avio_tell(pb);
- if (pos & 1)
- avio_w8(pb, 0);
- avio_seek(pb, start - 4, SEEK_SET);
- avio_wl32(pb, (uint32_t)(pos - start));
- avio_seek(pb, FFALIGN(pos, 2), SEEK_SET);
-}
-
-/* WAVEFORMATEX header */
-/* returns the size or -1 on error */
-int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
-{
- int bps, blkalign, bytespersec, frame_size;
- int hdrsize = 18;
- int waveformatextensible;
- uint8_t temp[256];
- uint8_t *riff_extradata= temp;
- uint8_t *riff_extradata_start= temp;
-
- if(!enc->codec_tag || enc->codec_tag > 0xffff)
- return -1;
-
- /* We use the known constant frame size for the codec if known, otherwise
- fallback to using AVCodecContext.frame_size, which is not as reliable
- for indicating packet duration */
- frame_size = av_get_audio_frame_duration(enc, 0);
- if (!frame_size)
- frame_size = enc->frame_size;
-
- waveformatextensible = (enc->channels > 2 && enc->channel_layout)
- || enc->sample_rate > 48000
- || av_get_bits_per_sample(enc->codec_id) > 16;
-
- if (waveformatextensible) {
- avio_wl16(pb, 0xfffe);
- } else {
- avio_wl16(pb, enc->codec_tag);
- }
- avio_wl16(pb, enc->channels);
- avio_wl32(pb, enc->sample_rate);
- if (enc->codec_id == AV_CODEC_ID_ATRAC3 ||
- enc->codec_id == AV_CODEC_ID_G723_1 ||
- enc->codec_id == AV_CODEC_ID_GSM_MS ||
- enc->codec_id == AV_CODEC_ID_MP2 ||
- enc->codec_id == AV_CODEC_ID_MP3) {
- bps = 0;
- } else {
- if (!(bps = av_get_bits_per_sample(enc->codec_id))) {
- if (enc->bits_per_coded_sample)
- bps = enc->bits_per_coded_sample;
- else
- bps = 16; // default to 16
- }
- }
- if(bps != enc->bits_per_coded_sample && enc->bits_per_coded_sample){
- av_log(enc, AV_LOG_WARNING, "requested bits_per_coded_sample (%d) and actually stored (%d) differ\n", enc->bits_per_coded_sample, bps);
- }
-
- if (enc->codec_id == AV_CODEC_ID_MP2 || enc->codec_id == AV_CODEC_ID_MP3) {
- /* this is wrong, but it seems many demuxers do not work if this is set
- correctly */
- blkalign = frame_size;
- //blkalign = 144 * enc->bit_rate/enc->sample_rate;
- } else if (enc->codec_id == AV_CODEC_ID_AC3) {
- blkalign = 3840; //maximum bytes per frame
- } else if (enc->codec_id == AV_CODEC_ID_AAC) {
- blkalign = 768 * enc->channels; //maximum bytes per frame
- } else if (enc->codec_id == AV_CODEC_ID_G723_1) {
- blkalign = 24;
- } else if (enc->block_align != 0) { /* specified by the codec */
- blkalign = enc->block_align;
- } else
- blkalign = bps * enc->channels / av_gcd(8, bps);
- if (enc->codec_id == AV_CODEC_ID_PCM_U8 ||
- enc->codec_id == AV_CODEC_ID_PCM_S24LE ||
- enc->codec_id == AV_CODEC_ID_PCM_S32LE ||
- enc->codec_id == AV_CODEC_ID_PCM_F32LE ||
- enc->codec_id == AV_CODEC_ID_PCM_F64LE ||
- enc->codec_id == AV_CODEC_ID_PCM_S16LE) {
- bytespersec = enc->sample_rate * blkalign;
- } else if (enc->codec_id == AV_CODEC_ID_G723_1) {
- bytespersec = 800;
- } else {
- bytespersec = enc->bit_rate / 8;
- }
- avio_wl32(pb, bytespersec); /* bytes per second */
- 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;
- bytestream_put_le16(&riff_extradata, 2); /* fwHeadLayer */
- bytestream_put_le32(&riff_extradata, enc->bit_rate); /* dwHeadBitrate */
- bytestream_put_le16(&riff_extradata, enc->channels == 2 ? 1 : 8); /* fwHeadMode */
- bytestream_put_le16(&riff_extradata, 0); /* fwHeadModeExt */
- bytestream_put_le16(&riff_extradata, 1); /* wHeadEmphasis */
- bytestream_put_le16(&riff_extradata, 16); /* fwHeadFlags */
- bytestream_put_le32(&riff_extradata, 0); /* dwPTSLow */
- bytestream_put_le32(&riff_extradata, 0); /* dwPTSHigh */
- } 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;
- bytestream_put_le16(&riff_extradata, frame_size); /* wSamplesPerBlock */
- } else if(enc->extradata_size){
- riff_extradata_start= enc->extradata;
- riff_extradata= enc->extradata + enc->extradata_size;
- hdrsize += enc->extradata_size;
- }
- if(waveformatextensible) { /* write WAVEFORMATEXTENSIBLE extensions */
- hdrsize += 22;
- avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* 22 is WAVEFORMATEXTENSIBLE size */
- avio_wl16(pb, bps); /* ValidBitsPerSample || SamplesPerBlock || Reserved */
- avio_wl32(pb, enc->channel_layout); /* dwChannelMask */
- avio_wl32(pb, enc->codec_tag); /* GUID + next 3 */
- avio_wl32(pb, 0x00100000);
- avio_wl32(pb, 0xAA000080);
- avio_wl32(pb, 0x719B3800);
- } else {
- avio_wl16(pb, riff_extradata - riff_extradata_start); /* cbSize */
- }
- avio_write(pb, riff_extradata_start, riff_extradata - riff_extradata_start);
- if(hdrsize&1){
- hdrsize++;
- avio_w8(pb, 0);
- }
-
- return hdrsize;
-}
-
-/* BITMAPINFOHEADER header */
-void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf)
-{
- avio_wl32(pb, 40 + enc->extradata_size); /* size */
- avio_wl32(pb, enc->width);
- //We always store RGB TopDown
- avio_wl32(pb, enc->codec_tag ? enc->height : -enc->height);
- avio_wl16(pb, 1); /* planes */
-
- avio_wl16(pb, enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24); /* depth */
- /* compression type */
- avio_wl32(pb, enc->codec_tag);
- avio_wl32(pb, (enc->width * enc->height * (enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24)+7) / 8);
- avio_wl32(pb, 0);
- avio_wl32(pb, 0);
- avio_wl32(pb, 0);
- avio_wl32(pb, 0);
-
- avio_write(pb, enc->extradata, enc->extradata_size);
-
- if (!for_asf && enc->extradata_size & 1)
- avio_w8(pb, 0);
-}
-
-void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale)
-{
- int gcd;
- int audio_frame_size;
-
- /* We use the known constant frame size for the codec if known, otherwise
- fallback to using AVCodecContext.frame_size, which is not as reliable
- for indicating packet duration */
- audio_frame_size = av_get_audio_frame_duration(stream, 0);
- if (!audio_frame_size)
- audio_frame_size = stream->frame_size;
-
- *au_ssize= stream->block_align;
- if (audio_frame_size && stream->sample_rate) {
- *au_scale = audio_frame_size;
- *au_rate= stream->sample_rate;
- }else if(stream->codec_type == AVMEDIA_TYPE_VIDEO ||
- stream->codec_type == AVMEDIA_TYPE_DATA ||
- stream->codec_type == AVMEDIA_TYPE_SUBTITLE){
- *au_scale= stream->time_base.num;
- *au_rate = stream->time_base.den;
- }else{
- *au_scale= stream->block_align ? stream->block_align*8 : 8;
- *au_rate = stream->bit_rate ? stream->bit_rate : 8*stream->sample_rate;
- }
- gcd= av_gcd(*au_scale, *au_rate);
- *au_scale /= gcd;
- *au_rate /= gcd;
-}
-
-void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str)
-{
- int len = strlen(str);
- if (len > 0) {
- len++;
- ffio_wfourcc(pb, tag);
- avio_wl32(pb, len);
- avio_put_str(pb, str);
- if (len & 1)
- avio_w8(pb, 0);
- }
-}
-
-static const char riff_tags[][5] = {
- "IARL", "IART", "ICMS", "ICMT", "ICOP", "ICRD", "ICRP", "IDIM", "IDPI",
- "IENG", "IGNR", "IKEY", "ILGT", "ILNG", "IMED", "INAM", "IPLT", "IPRD",
- "IPRT", "ISBJ", "ISFT", "ISHP", "ISMP", "ISRC", "ISRF", "ITCH",
- {0}
-};
-
-static int riff_has_valid_tags(AVFormatContext *s)
+const struct AVCodecTag *avformat_get_riff_video_tags(void)
{
- int i;
-
- for (i = 0; *riff_tags[i]; i++) {
- if (av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE))
- return 1;
- }
-
- return 0;
+ return ff_codec_bmp_tags;
}
-void ff_riff_write_info(AVFormatContext *s)
+const struct AVCodecTag *avformat_get_riff_audio_tags(void)
{
- AVIOContext *pb = s->pb;
- int i;
- int64_t list_pos;
- AVDictionaryEntry *t = NULL;
-
- ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL);
-
- /* writing empty LIST is not nice and may cause problems */
- if (!riff_has_valid_tags(s))
- return;
-
- list_pos = ff_start_tag(pb, "LIST");
- ffio_wfourcc(pb, "INFO");
- for (i = 0; *riff_tags[i]; i++) {
- if ((t = av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE)))
- ff_riff_write_info_tag(s->pb, t->key, t->value);
- }
- ff_end_tag(pb, list_pos);
-}
-#endif //CONFIG_MUXERS
-
-#if CONFIG_DEMUXERS
-/* We could be given one of the three possible structures here:
- * WAVEFORMAT, PCMWAVEFORMAT or WAVEFORMATEX. Each structure
- * is an expansion of the previous one with the fields added
- * at the bottom. PCMWAVEFORMAT adds 'WORD wBitsPerSample' and
- * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself
- * an openended structure.
- */
-int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
-{
- int id;
-
- id = avio_rl16(pb);
- codec->codec_type = AVMEDIA_TYPE_AUDIO;
- codec->channels = avio_rl16(pb);
- codec->sample_rate = avio_rl32(pb);
- codec->bit_rate = avio_rl32(pb) * 8;
- codec->block_align = avio_rl16(pb);
- if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */
- codec->bits_per_coded_sample = 8;
- }else
- codec->bits_per_coded_sample = avio_rl16(pb);
- if (id == 0xFFFE) {
- codec->codec_tag = 0;
- } else {
- codec->codec_tag = id;
- codec->codec_id = ff_wav_codec_get_id(id, codec->bits_per_coded_sample);
- }
- if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */
- int cbSize = avio_rl16(pb); /* cbSize */
- size -= 18;
- cbSize = FFMIN(size, cbSize);
- if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */
- ff_asf_guid subformat;
- int bps = avio_rl16(pb);
- if (bps)
- codec->bits_per_coded_sample = bps;
- codec->channel_layout = avio_rl32(pb); /* dwChannelMask */
- ff_get_guid(pb, &subformat);
- if (!memcmp(subformat + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
- codec->codec_tag = AV_RL32(subformat);
- codec->codec_id = ff_wav_codec_get_id(codec->codec_tag, codec->bits_per_coded_sample);
- } else {
- codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subformat);
- if (!codec->codec_id)
- av_log(codec, AV_LOG_WARNING, "unknown subformat:"FF_PRI_GUID"\n", FF_ARG_GUID(subformat));
- }
- cbSize -= 22;
- size -= 22;
- }
- codec->extradata_size = cbSize;
- if (cbSize > 0) {
- av_free(codec->extradata);
- codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!codec->extradata)
- return AVERROR(ENOMEM);
- avio_read(pb, codec->extradata, codec->extradata_size);
- size -= cbSize;
- }
-
- /* It is possible for the chunk to contain garbage at the end */
- if (size > 0)
- avio_skip(pb, size);
- }
- if (codec->codec_id == AV_CODEC_ID_AAC_LATM) {
- /* channels and sample_rate values are those prior to applying SBR and/or PS */
- codec->channels = 0;
- codec->sample_rate = 0;
- }
- /* override bits_per_coded_sample for G.726 */
- if (codec->codec_id == AV_CODEC_ID_ADPCM_G726 && codec->sample_rate)
- codec->bits_per_coded_sample = codec->bit_rate / codec->sample_rate;
-
- return 0;
-}
-
-
-enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps)
-{
- enum AVCodecID id;
- id = ff_codec_get_id(ff_codec_wav_tags, tag);
- if (id <= 0)
- return id;
-
- if (id == AV_CODEC_ID_PCM_S16LE)
- id = ff_get_pcm_codec_id(bps, 0, 0, ~1);
- else if (id == AV_CODEC_ID_PCM_F32LE)
- id = ff_get_pcm_codec_id(bps, 1, 0, 0);
-
- if (id == AV_CODEC_ID_ADPCM_IMA_WAV && bps == 8)
- id = AV_CODEC_ID_PCM_ZORK;
- return id;
-}
-
-int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize)
-{
- int tag1;
- if(esize) *esize = avio_rl32(pb);
- else avio_rl32(pb);
- st->codec->width = avio_rl32(pb);
- st->codec->height = (int32_t)avio_rl32(pb);
- avio_rl16(pb); /* planes */
- st->codec->bits_per_coded_sample= avio_rl16(pb); /* depth */
- tag1 = avio_rl32(pb);
- avio_rl32(pb); /* ImageSize */
- avio_rl32(pb); /* XPelsPerMeter */
- avio_rl32(pb); /* YPelsPerMeter */
- avio_rl32(pb); /* ClrUsed */
- avio_rl32(pb); /* ClrImportant */
- return tag1;
-}
-
-void 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))
- memset(*g, 0, sizeof(*g));
-}
-
-enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid)
-{
- int i;
- for (i = 0; guids[i].id != AV_CODEC_ID_NONE; i++) {
- if (!ff_guidcmp(guids[i].guid, guid))
- return guids[i].id;
- }
- return AV_CODEC_ID_NONE;
-}
-
-int ff_read_riff_info(AVFormatContext *s, int64_t size)
-{
- int64_t start, end, cur;
- AVIOContext *pb = s->pb;
-
- start = avio_tell(pb);
- end = start + size;
-
- while ((cur = avio_tell(pb)) >= 0 && cur <= end - 8 /* = tag + size */) {
- uint32_t chunk_code;
- int64_t chunk_size;
- char key[5] = {0};
- char *value;
-
- chunk_code = avio_rl32(pb);
- chunk_size = avio_rl32(pb);
- if (url_feof(pb)) {
- if (chunk_code || chunk_size) {
- av_log(s, AV_LOG_WARNING, "INFO subchunk truncated\n");
- return AVERROR_INVALIDDATA;
- }
- break;
- }
- if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) {
- avio_seek(pb, -9, SEEK_CUR);
- chunk_code = avio_rl32(pb);
- chunk_size = avio_rl32(pb);
- if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) {
- av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n");
- return AVERROR_INVALIDDATA;
- }
- }
-
- chunk_size += (chunk_size & 1);
-
- if (!chunk_code) {
- if (chunk_size)
- avio_skip(pb, chunk_size);
- continue;
- }
-
- value = av_mallocz(chunk_size + 1);
- if (!value) {
- av_log(s, AV_LOG_ERROR, "out of memory, unable to read INFO tag\n");
- return AVERROR(ENOMEM);
- }
-
- AV_WL32(key, chunk_code);
-
- if (avio_read(pb, value, chunk_size) != chunk_size) {
- av_log(s, AV_LOG_WARNING, "premature end of file while reading INFO tag\n");
- }
-
- av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
- }
-
- return 0;
+ return ff_codec_wav_tags;
}
-#endif // CONFIG_DEMUXERS
diff --git a/ffmpeg/libavformat/riff.h b/ffmpeg/libavformat/riff.h
index 70b2f76..ce07869 100644
--- a/ffmpeg/libavformat/riff.h
+++ b/ffmpeg/libavformat/riff.h
@@ -34,7 +34,6 @@
#include "metadata.h"
extern const AVMetadataConv ff_riff_info_conv[];
-extern const char ff_riff_tags[][5];
int64_t ff_start_tag(AVIOContext *pb, const char *tag);
void ff_end_tag(AVIOContext *pb, int64_t start);
@@ -46,7 +45,7 @@ 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);
+void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf, int ignore_extradata);
int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc);
enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps);
int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size);
@@ -56,14 +55,36 @@ extern const AVCodecTag ff_codec_wav_tags[];
void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale);
+int ff_read_riff_info(AVFormatContext *s, int64_t size);
+
+/**
+ * Write all recognized RIFF tags from s->metadata
+ */
+void ff_riff_write_info(AVFormatContext *s);
+
+/**
+ * Write a single RIFF info tag
+ */
+void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str);
+
typedef uint8_t ff_asf_guid[16];
-int ff_read_riff_info(AVFormatContext *s, int64_t size);
+typedef struct AVCodecGuid {
+ enum AVCodecID id;
+ ff_asf_guid guid;
+} AVCodecGuid;
+
+extern const AVCodecGuid ff_codec_wav_guids[];
#define FF_PRI_GUID \
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+
#define FF_ARG_GUID(g) \
- g[0],g[1],g[2],g[3],g[4],g[5],g[6],g[7],g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
+ g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], \
+ g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]
+
+#define FF_MEDIASUBTYPE_BASE_GUID \
+ 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
static av_always_inline int ff_guidcmp(const void *g1, const void *g2)
{
@@ -72,26 +93,6 @@ static av_always_inline int ff_guidcmp(const void *g1, const void *g2)
void ff_get_guid(AVIOContext *s, ff_asf_guid *g);
-typedef struct {
- enum AVCodecID id;
- ff_asf_guid guid;
-} AVCodecGuid;
-
enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid);
-extern const AVCodecGuid ff_codec_wav_guids[];
-
-#define FF_MEDIASUBTYPE_BASE_GUID \
- 0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
-
-/**
- * Write all recognized RIFF tags from s->metadata
- */
-void ff_riff_write_info(AVFormatContext *s);
-
-/**
- * Write a single RIFF info tag
- */
-void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str);
-
#endif /* AVFORMAT_RIFF_H */
diff --git a/ffmpeg/libavformat/rl2.c b/ffmpeg/libavformat/rl2.c
index 800e12e..d354339 100644
--- a/ffmpeg/libavformat/rl2.c
+++ b/ffmpeg/libavformat/rl2.c
@@ -32,6 +32,8 @@
* optional background_frame
*/
+#include <stdint.h>
+
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "avformat.h"
@@ -125,19 +127,15 @@ static av_cold int rl2_read_header(AVFormatContext *s)
if(signature == RLV3_TAG && back_size > 0)
st->codec->extradata_size += back_size;
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if(!st->codec->extradata)
+ 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 <= 0)
+ if (!channels || channels > 42) {
+ av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels);
return AVERROR_INVALIDDATA;
+ }
pts_num = def_sound_size;
pts_den = rate;
diff --git a/ffmpeg/libavformat/rmdec.c b/ffmpeg/libavformat/rmdec.c
index 478b35b..8feef54 100644
--- a/ffmpeg/libavformat/rmdec.c
+++ b/ffmpeg/libavformat/rmdec.c
@@ -22,6 +22,7 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
@@ -30,7 +31,7 @@
#include "rmsipr.h"
#include "rm.h"
-#define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/Atrac
+#define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/ATRAC
#define DEINT_ID_INT0 MKTAG('I', 'n', 't', '0') ///< no interleaving needed
#define DEINT_ID_INT4 MKTAG('I', 'n', 't', '4') ///< interleaving for 28.8
#define DEINT_ID_SIPR MKTAG('s', 'i', 'p', 'r') ///< interleaving for Sipro
@@ -85,23 +86,19 @@ static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned si
{
if (size >= 1<<24)
return -1;
- avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ if (ff_get_extradata(avctx, pb, size) < 0)
return AVERROR(ENOMEM);
- avctx->extradata_size = avio_read(pb, avctx->extradata, size);
- memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- if (avctx->extradata_size != size)
- return AVERROR(EIO);
return 0;
}
-static void rm_read_metadata(AVFormatContext *s, int wide)
+static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide)
{
char buf[1024];
int i;
+
for (i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
- int len = wide ? avio_rb16(s->pb) : avio_r8(s->pb);
- get_strl(s->pb, buf, sizeof(buf), len);
+ int len = wide ? avio_rb16(pb) : avio_r8(pb);
+ get_strl(pb, buf, sizeof(buf), len);
av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0);
}
}
@@ -134,7 +131,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
avio_skip(pb, 8);
bytes_per_minute = avio_rb16(pb);
avio_skip(pb, 4);
- rm_read_metadata(s, 0);
+ rm_read_metadata(s, pb, 0);
if ((startpos + header_size) >= avio_tell(pb) + 2) {
// fourcc (should always be "lpcJ")
avio_r8(pb);
@@ -185,6 +182,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 */
@@ -257,22 +255,16 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
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:
if (ast->coded_framesize > ast->audio_framesize ||
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 ||
@@ -288,12 +280,22 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\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);
avio_r8(pb);
avio_r8(pb);
- rm_read_metadata(s, 0);
+ rm_read_metadata(s, pb, 0);
}
}
return 0;
@@ -375,11 +377,16 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0)
return ret;
- av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num,
- 0x10000, fps, (1 << 30) - 1);
+ if (fps > 0) {
+ av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num,
+ 0x10000, fps, (1 << 30) - 1);
#if FF_API_R_FRAME_RATE
- st->r_frame_rate = st->avg_frame_rate;
+ st->r_frame_rate = st->avg_frame_rate;
#endif
+ } else if (s->error_recognition & AV_EF_EXPLODE) {
+ av_log(s, AV_LOG_ERROR, "Invalid framerate\n");
+ return AVERROR_INVALIDDATA;
+ }
}
skip:
@@ -516,7 +523,7 @@ static int rm_read_header(AVFormatContext *s)
flags = avio_rb16(pb); /* flags */
break;
case MKTAG('C', 'O', 'N', 'T'):
- rm_read_metadata(s, 1);
+ rm_read_metadata(s, pb, 1);
break;
case MKTAG('M', 'D', 'P', 'R'):
st = avformat_new_stream(s, NULL);
@@ -662,6 +669,7 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
int hdr;
int seq = 0, pic_num = 0, len2 = 0, pos = 0; //init to silcense compiler warning
int type;
+ int ret;
hdr = avio_r8(pb); len--;
type = hdr >> 6;
@@ -674,23 +682,31 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
pos = get_num(pb, &len);
pic_num = avio_r8(pb); len--;
}
- if(len<0)
+ if(len<0) {
+ av_log(s, AV_LOG_ERROR, "Insufficient data\n");
return -1;
+ }
rm->remaining_len = len;
if(type&1){ // frame, not slice
if(type == 3){ // frame as a part of packet
len= len2;
*timestamp = pos;
}
- if(rm->remaining_len < len)
+ if(rm->remaining_len < len) {
+ av_log(s, AV_LOG_ERROR, "Insufficient remaining len\n");
return -1;
+ }
rm->remaining_len -= len;
if(av_new_packet(pkt, len + 9) < 0)
return AVERROR(EIO);
pkt->data[0] = 0;
AV_WL32(pkt->data + 1, 1);
AV_WL32(pkt->data + 5, 0);
- avio_read(pb, pkt->data + 9, len);
+ if ((ret = avio_read(pb, pkt->data + 9, len)) != len) {
+ av_free_packet(pkt);
+ av_log(s, AV_LOG_ERROR, "Failed to read %d bytes\n", len);
+ return ret < 0 ? ret : AVERROR(EIO);
+ }
return 0;
}
//now we have to deal with single slice
@@ -706,6 +722,7 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
av_free_packet(&vst->pkt); //FIXME this should be output.
if(av_new_packet(&vst->pkt, vst->videobufsize) < 0)
return AVERROR(ENOMEM);
+ memset(vst->pkt.data, 0, vst->pkt.size);
vst->videobufpos = 8*vst->slices + 1;
vst->cur_slice = 0;
vst->curpic_num = pic_num;
@@ -714,12 +731,18 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
if(type == 2)
len = FFMIN(len, pos);
- if(++vst->cur_slice > vst->slices)
+ if(++vst->cur_slice > vst->slices) {
+ av_log(s, AV_LOG_ERROR, "cur slice %d, too large\n", vst->cur_slice);
return 1;
+ }
+ if(!vst->pkt.data)
+ return AVERROR(ENOMEM);
AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1);
AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1);
- if(vst->videobufpos + len > vst->videobufsize)
+ if(vst->videobufpos + len > vst->videobufsize) {
+ av_log(s, AV_LOG_ERROR, "outside videobufsize\n");
return 1;
+ }
if (avio_read(pb, vst->pkt.data + vst->videobufpos, len) != len)
return AVERROR(EIO);
vst->videobufpos += len;
@@ -732,7 +755,9 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
vst->pkt.size= 0;
vst->pkt.buf = NULL;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
vst->pkt.destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin
memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices,
@@ -768,11 +793,13 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
int *seq, int flags, int64_t timestamp)
{
RMDemuxContext *rm = s->priv_data;
+ int ret;
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
rm->current_stream= st->id;
- if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, &timestamp))
- return -1; //got partial frame
+ ret = rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, &timestamp);
+ if(ret)
+ return ret < 0 ? ret : -1; //got partial frame or error
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if ((ast->deint_id == DEINT_ID_GENR) ||
(ast->deint_id == DEINT_ID_INT4) ||
@@ -919,6 +946,8 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt,
&seq, flags, timestamp);
+ if (res < -1)
+ return res;
if((flags&2) && (seq&0x7F) == 1)
av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME);
if (res)
diff --git a/ffmpeg/libavformat/rmenc.c b/ffmpeg/libavformat/rmenc.c
index a96c429..17192ff 100644
--- a/ffmpeg/libavformat/rmenc.c
+++ b/ffmpeg/libavformat/rmenc.c
@@ -374,7 +374,6 @@ static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int
} else {
avio_write(pb, buf, size);
}
- avio_flush(pb);
stream->nb_frames++;
av_free(buf1);
return 0;
@@ -419,7 +418,6 @@ static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int
avio_w8(pb, stream->nb_frames & 0xff);
avio_write(pb, buf, size);
- avio_flush(pb);
stream->nb_frames++;
return 0;
diff --git a/ffmpeg/libavformat/rpl.c b/ffmpeg/libavformat/rpl.c
index dcc7950..fb60379 100644
--- a/ffmpeg/libavformat/rpl.c
+++ b/ffmpeg/libavformat/rpl.c
@@ -19,11 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+#include <stdlib.h>
+
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "avformat.h"
#include "internal.h"
-#include <stdlib.h>
#define RPL_SIGNATURE "ARMovie\x0A"
#define RPL_SIGNATURE_SIZE 8
@@ -168,9 +170,8 @@ static int rpl_read_header(AVFormatContext *s)
vst->codec->codec_id = AV_CODEC_ID_ESCAPE130;
break;
default:
- av_log(s, AV_LOG_WARNING,
- "RPL video format %i not supported yet!\n",
- vst->codec->codec_tag);
+ avpriv_report_missing_feature(s, "Video format %i",
+ vst->codec->codec_tag);
vst->codec->codec_id = AV_CODEC_ID_NONE;
}
@@ -220,11 +221,8 @@ static int rpl_read_header(AVFormatContext *s)
}
break;
}
- if (ast->codec->codec_id == AV_CODEC_ID_NONE) {
- av_log(s, AV_LOG_WARNING,
- "RPL audio format %i not supported yet!\n",
- audio_format);
- }
+ if (ast->codec->codec_id == AV_CODEC_ID_NONE)
+ avpriv_request_sample(s, "Audio format %i", audio_format);
avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
} else {
for (i = 0; i < 3; i++)
@@ -255,9 +253,11 @@ static int rpl_read_header(AVFormatContext *s)
for (i = 0; !error && i < number_of_chunks; i++) {
int64_t offset, video_size, audio_size;
error |= read_line(pb, line, sizeof(line));
- if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64,
- &offset, &video_size, &audio_size))
+ if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64,
+ &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/ffmpeg/libavformat/rtmp.h b/ffmpeg/libavformat/rtmp.h
index 7c9bb6d..8fc8040 100644
--- a/ffmpeg/libavformat/rtmp.h
+++ b/ffmpeg/libavformat/rtmp.h
@@ -1,6 +1,6 @@
/*
* RTMP definitions
- * Copyright (c) 2009 Kostya Shishkov
+ * Copyright (c) 2009 Konstantin Shishkov
*
* This file is part of FFmpeg.
*
diff --git a/ffmpeg/libavformat/rtmphttp.c b/ffmpeg/libavformat/rtmphttp.c
index 3a51f7c..0334ba5 100644
--- a/ffmpeg/libavformat/rtmphttp.c
+++ b/ffmpeg/libavformat/rtmphttp.c
@@ -85,14 +85,15 @@ static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size)
{
RTMP_HTTPContext *rt = h->priv_data;
- void *ptr;
if (rt->out_size + size > rt->out_capacity) {
+ int err;
rt->out_capacity = (rt->out_size + size) * 2;
- ptr = av_realloc(rt->out_data, rt->out_capacity);
- if (!ptr)
- return AVERROR(ENOMEM);
- rt->out_data = ptr;
+ if ((err = av_reallocp(&rt->out_data, rt->out_capacity)) < 0) {
+ rt->out_size = 0;
+ rt->out_capacity = 0;
+ return err;
+ }
}
memcpy(rt->out_data + rt->out_size, buf, size);
@@ -112,7 +113,7 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
if (ret < 0 && ret != AVERROR_EOF)
return ret;
- if (ret == AVERROR_EOF) {
+ if (!ret || ret == AVERROR_EOF) {
if (rt->finishing) {
/* Do not send new requests when the client wants to
* close the connection. */
@@ -226,7 +227,7 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags)
/* read the server reply which contains a unique ID */
for (;;) {
ret = ffurl_read(rt->stream, rt->client_id + off, sizeof(rt->client_id) - off);
- if (ret == AVERROR_EOF)
+ if (!ret || ret == AVERROR_EOF)
break;
if (ret < 0)
goto fail;
diff --git a/ffmpeg/libavformat/rtmppkt.c b/ffmpeg/libavformat/rtmppkt.c
index 3bd28eb..375ae2f 100644
--- a/ffmpeg/libavformat/rtmppkt.c
+++ b/ffmpeg/libavformat/rtmppkt.c
@@ -1,6 +1,6 @@
/*
* RTMP input format
- * Copyright (c) 2009 Kostya Shishkov
+ * Copyright (c) 2009 Konstantin Shishkov
*
* This file is part of FFmpeg.
*
@@ -129,41 +129,69 @@ int ff_amf_read_null(GetByteContext *bc)
return 0;
}
+int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt,
+ int channel)
+{
+ int nb_alloc;
+ RTMPPacket *ptr;
+ if (channel < *nb_prev_pkt)
+ return 0;
+
+ nb_alloc = channel + 16;
+ // This can't use the av_reallocp family of functions, since we
+ // would need to free each element in the array before the array
+ // itself is freed.
+ ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt));
+ if (!ptr)
+ return AVERROR(ENOMEM);
+ memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr));
+ *prev_pkt = ptr;
+ *nb_prev_pkt = nb_alloc;
+ return 0;
+}
+
int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
- int chunk_size, RTMPPacket *prev_pkt)
+ int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
{
uint8_t hdr;
if (ffurl_read(h, &hdr, 1) != 1)
return AVERROR(EIO);
- return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt, hdr);
+ return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt,
+ nb_prev_pkt, hdr);
}
-int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
- RTMPPacket *prev_pkt, uint8_t hdr)
+static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p,
+ int chunk_size, RTMPPacket **prev_pkt_ptr,
+ int *nb_prev_pkt, uint8_t hdr)
{
- uint8_t t, buf[16];
- int channel_id, timestamp, data_size, offset = 0;
+ uint8_t buf[16];
+ int channel_id, timestamp, size;
uint32_t extra = 0;
enum RTMPPacketType type;
- int size = 0;
- int ret;
+ int written = 0;
+ int ret, toread;
+ RTMPPacket *prev_pkt;
- size++;
+ written++;
channel_id = hdr & 0x3F;
if (channel_id < 2) { //special case for channel number >= 64
buf[1] = 0;
if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1)
return AVERROR(EIO);
- size += channel_id + 1;
+ written += channel_id + 1;
channel_id = AV_RL16(buf) + 64;
}
- data_size = prev_pkt[channel_id].data_size;
- type = prev_pkt[channel_id].type;
- extra = prev_pkt[channel_id].extra;
+ if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
+ channel_id)) < 0)
+ return ret;
+ prev_pkt = *prev_pkt_ptr;
+ size = prev_pkt[channel_id].size;
+ type = prev_pkt[channel_id].type;
+ extra = prev_pkt[channel_id].extra;
hdr >>= 6;
if (hdr == RTMP_PS_ONEBYTE) {
@@ -171,21 +199,21 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
} else {
if (ffurl_read_complete(h, buf, 3) != 3)
return AVERROR(EIO);
- size += 3;
+ written += 3;
timestamp = AV_RB24(buf);
if (hdr != RTMP_PS_FOURBYTES) {
if (ffurl_read_complete(h, buf, 3) != 3)
return AVERROR(EIO);
- size += 3;
- data_size = AV_RB24(buf);
+ written += 3;
+ size = AV_RB24(buf);
if (ffurl_read_complete(h, buf, 1) != 1)
return AVERROR(EIO);
- size++;
+ written++;
type = buf[0];
if (hdr == RTMP_PS_TWELVEBYTES) {
if (ffurl_read_complete(h, buf, 4) != 4)
return AVERROR(EIO);
- size += 4;
+ written += 4;
extra = AV_RL32(buf);
}
}
@@ -198,47 +226,88 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
if (hdr != RTMP_PS_TWELVEBYTES)
timestamp += prev_pkt[channel_id].timestamp;
- if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
- data_size)) < 0)
- return ret;
+ if (!prev_pkt[channel_id].read) {
+ if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
+ size)) < 0)
+ return ret;
+ p->read = written;
+ p->offset = 0;
+ prev_pkt[channel_id].ts_delta = timestamp -
+ prev_pkt[channel_id].timestamp;
+ prev_pkt[channel_id].timestamp = timestamp;
+ } else {
+ // previous packet in this channel hasn't completed reading
+ RTMPPacket *prev = &prev_pkt[channel_id];
+ p->data = prev->data;
+ p->size = prev->size;
+ p->channel_id = prev->channel_id;
+ p->type = prev->type;
+ p->ts_delta = prev->ts_delta;
+ p->extra = prev->extra;
+ p->offset = prev->offset;
+ p->read = prev->read + written;
+ p->timestamp = prev->timestamp;
+ prev->data = NULL;
+ }
p->extra = extra;
// save history
prev_pkt[channel_id].channel_id = channel_id;
prev_pkt[channel_id].type = type;
- prev_pkt[channel_id].data_size = data_size;
- prev_pkt[channel_id].ts_delta = timestamp - prev_pkt[channel_id].timestamp;
- prev_pkt[channel_id].timestamp = timestamp;
+ prev_pkt[channel_id].size = size;
prev_pkt[channel_id].extra = extra;
- while (data_size > 0) {
- int toread = FFMIN(data_size, chunk_size);
- if (ffurl_read_complete(h, p->data + offset, toread) != toread) {
- ff_rtmp_packet_destroy(p);
+ size = size - p->offset;
+
+ toread = FFMIN(size, chunk_size);
+ if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
+ ff_rtmp_packet_destroy(p);
+ return AVERROR(EIO);
+ }
+ size -= toread;
+ p->read += toread;
+ p->offset += toread;
+
+ if (size > 0) {
+ RTMPPacket *prev = &prev_pkt[channel_id];
+ prev->data = p->data;
+ prev->read = p->read;
+ prev->offset = p->offset;
+ return AVERROR(EAGAIN);
+ }
+
+ prev_pkt[channel_id].read = 0; // read complete; reset if needed
+ return p->read;
+}
+
+int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
+ RTMPPacket **prev_pkt, int *nb_prev_pkt,
+ uint8_t hdr)
+{
+ while (1) {
+ int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt,
+ nb_prev_pkt, hdr);
+ if (ret > 0 || ret != AVERROR(EAGAIN))
+ return ret;
+
+ if (ffurl_read(h, &hdr, 1) != 1)
return AVERROR(EIO);
- }
- data_size -= chunk_size;
- offset += chunk_size;
- size += chunk_size;
- if (data_size > 0) {
- if ((ret = ffurl_read_complete(h, &t, 1)) < 0) { // marker
- ff_rtmp_packet_destroy(p);
- return ret;
- }
- size++;
- if (t != (0xC0 + channel_id))
- return -1;
- }
}
- return size;
}
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
- int chunk_size, RTMPPacket *prev_pkt)
+ int chunk_size, RTMPPacket **prev_pkt_ptr,
+ int *nb_prev_pkt)
{
uint8_t pkt_hdr[16], *p = pkt_hdr;
int mode = RTMP_PS_TWELVEBYTES;
int off = 0;
- int size = 0;
+ int written = 0;
int ret;
+ RTMPPacket *prev_pkt;
+
+ 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;
@@ -246,7 +315,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
if (prev_pkt[pkt->channel_id].channel_id &&
pkt->extra == prev_pkt[pkt->channel_id].extra) {
if (pkt->type == prev_pkt[pkt->channel_id].type &&
- pkt->data_size == prev_pkt[pkt->channel_id].data_size) {
+ pkt->size == prev_pkt[pkt->channel_id].size) {
mode = RTMP_PS_FOURBYTES;
if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta)
mode = RTMP_PS_ONEBYTE;
@@ -270,7 +339,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
timestamp = pkt->ts_delta;
bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp);
if (mode != RTMP_PS_FOURBYTES) {
- bytestream_put_be24(&p, pkt->data_size);
+ bytestream_put_be24(&p, pkt->size);
bytestream_put_byte(&p, pkt->type);
if (mode == RTMP_PS_TWELVEBYTES)
bytestream_put_le32(&p, pkt->extra);
@@ -281,7 +350,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
// 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].data_size = pkt->data_size;
+ 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;
@@ -292,20 +361,20 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0)
return ret;
- size = p - pkt_hdr + pkt->data_size;
- while (off < pkt->data_size) {
- int towrite = FFMIN(chunk_size, pkt->data_size - off);
+ written = p - pkt_hdr + pkt->size;
+ while (off < pkt->size) {
+ int towrite = FFMIN(chunk_size, pkt->size - off);
if ((ret = ffurl_write(h, pkt->data + off, towrite)) < 0)
return ret;
off += towrite;
- if (off < pkt->data_size) {
+ if (off < pkt->size) {
uint8_t marker = 0xC0 | pkt->channel_id;
if ((ret = ffurl_write(h, &marker, 1)) < 0)
return ret;
- size++;
+ written++;
}
}
- return size;
+ return written;
}
int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type,
@@ -316,7 +385,7 @@ int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type,
if (!pkt->data)
return AVERROR(ENOMEM);
}
- pkt->data_size = size;
+ pkt->size = size;
pkt->channel_id = channel_id;
pkt->type = type;
pkt->timestamp = timestamp;
@@ -331,34 +400,41 @@ void ff_rtmp_packet_destroy(RTMPPacket *pkt)
if (!pkt)
return;
av_freep(&pkt->data);
- pkt->data_size = 0;
+ pkt->size = 0;
}
int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
{
const uint8_t *base = data;
+ AMFDataType type;
+ unsigned nb = -1;
+ int parse_key = 1;
if (data >= data_end)
return -1;
- switch (*data++) {
+ switch ((type = *data++)) {
case AMF_DATA_TYPE_NUMBER: return 9;
case AMF_DATA_TYPE_BOOL: return 2;
case AMF_DATA_TYPE_STRING: return 3 + AV_RB16(data);
case AMF_DATA_TYPE_LONG_STRING: return 5 + AV_RB32(data);
case AMF_DATA_TYPE_NULL: return 1;
case AMF_DATA_TYPE_ARRAY:
- data += 4;
+ parse_key = 0;
+ case AMF_DATA_TYPE_MIXEDARRAY:
+ nb = bytestream_get_be32(&data);
case AMF_DATA_TYPE_OBJECT:
- for (;;) {
- int size = bytestream_get_be16(&data);
+ while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
int t;
- if (!size) {
- data++;
- break;
+ if (parse_key) {
+ int size = bytestream_get_be16(&data);
+ if (!size) {
+ data++;
+ break;
+ }
+ if (size < 0 || size >= data_end - data)
+ return -1;
+ data += size;
}
- if (size < 0 || size >= data_end - data)
- return -1;
- data += size;
t = ff_amf_tag_size(data, data_end);
if (t < 0 || t >= data_end - data)
return -1;
@@ -438,14 +514,17 @@ static const char* rtmp_packet_type(int type)
}
}
-static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *data_end)
+static void amf_tag_contents(void *ctx, const uint8_t *data,
+ const uint8_t *data_end)
{
- unsigned int size;
+ unsigned int size, nb = -1;
char buf[1024];
+ AMFDataType type;
+ int parse_key = 1;
if (data >= data_end)
return;
- switch (*data++) {
+ switch ((type = *data++)) {
case AMF_DATA_TYPE_NUMBER:
av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2double(AV_RB64(data)));
return;
@@ -454,7 +533,7 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d
return;
case AMF_DATA_TYPE_STRING:
case AMF_DATA_TYPE_LONG_STRING:
- if (data[-1] == AMF_DATA_TYPE_STRING) {
+ if (type == AMF_DATA_TYPE_STRING) {
size = bytestream_get_be16(&data);
} else {
size = bytestream_get_be32(&data);
@@ -468,23 +547,29 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d
av_log(ctx, AV_LOG_DEBUG, " NULL\n");
return;
case AMF_DATA_TYPE_ARRAY:
- data += 4;
+ parse_key = 0;
+ case AMF_DATA_TYPE_MIXEDARRAY:
+ nb = bytestream_get_be32(&data);
case AMF_DATA_TYPE_OBJECT:
av_log(ctx, AV_LOG_DEBUG, " {\n");
- for (;;) {
+ while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
int t;
- size = bytestream_get_be16(&data);
- av_strlcpy(buf, data, FFMIN(sizeof(buf), size + 1));
- if (!size) {
- av_log(ctx, AV_LOG_DEBUG, " }\n");
- data++;
- break;
+ if (parse_key) {
+ size = bytestream_get_be16(&data);
+ size = FFMIN(size, sizeof(buf) - 1);
+ if (!size) {
+ av_log(ctx, AV_LOG_DEBUG, " }\n");
+ data++;
+ break;
+ }
+ memcpy(buf, data, size);
+ buf[size] = 0;
+ if (size >= data_end - data)
+ return;
+ data += size;
+ av_log(ctx, AV_LOG_DEBUG, " %s: ", buf);
}
- if (size >= data_end - data)
- return;
- data += size;
- av_log(ctx, AV_LOG_DEBUG, " %s: ", buf);
- ff_amf_tag_contents(ctx, data, data_end);
+ amf_tag_contents(ctx, data, data_end);
t = ff_amf_tag_size(data, data_end);
if (t < 0 || t >= data_end - data)
return;
@@ -502,12 +587,12 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d
void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
{
av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n",
- rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->data_size);
+ rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->size);
if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) {
- uint8_t *src = p->data, *src_end = p->data + p->data_size;
+ uint8_t *src = p->data, *src_end = p->data + p->size;
while (src < src_end) {
int sz;
- ff_amf_tag_contents(ctx, src, src_end);
+ amf_tag_contents(ctx, src, src_end);
sz = ff_amf_tag_size(src, src_end);
if (sz < 0)
break;
@@ -519,8 +604,41 @@ void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
av_log(ctx, AV_LOG_DEBUG, "Client BW = %d\n", AV_RB32(p->data));
} else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) {
int i;
- for (i = 0; i < p->data_size; i++)
+ for (i = 0; i < p->size; i++)
av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]);
av_log(ctx, AV_LOG_DEBUG, "\n");
}
}
+
+int ff_amf_match_string(const uint8_t *data, int size, const char *str)
+{
+ int len = strlen(str);
+ int amf_len, type;
+
+ if (size < 1)
+ return 0;
+
+ type = *data++;
+
+ if (type != AMF_DATA_TYPE_LONG_STRING &&
+ type != AMF_DATA_TYPE_STRING)
+ return 0;
+
+ if (type == AMF_DATA_TYPE_LONG_STRING) {
+ if ((size -= 4 + 1) < 0)
+ return 0;
+ amf_len = bytestream_get_be32(&data);
+ } else {
+ if ((size -= 2 + 1) < 0)
+ return 0;
+ amf_len = bytestream_get_be16(&data);
+ }
+
+ if (amf_len > size)
+ return 0;
+
+ if (amf_len != len)
+ return 0;
+
+ return !memcmp(data, str, len);
+}
diff --git a/ffmpeg/libavformat/rtmppkt.h b/ffmpeg/libavformat/rtmppkt.h
index a942295..fb79fed 100644
--- a/ffmpeg/libavformat/rtmppkt.h
+++ b/ffmpeg/libavformat/rtmppkt.h
@@ -1,6 +1,6 @@
/*
* RTMP packet utilities
- * Copyright (c) 2009 Kostya Shishkov
+ * Copyright (c) 2009 Konstantin Shishkov
*
* This file is part of FFmpeg.
*
@@ -36,9 +36,9 @@
enum RTMPChannel {
RTMP_NETWORK_CHANNEL = 2, ///< channel for network-related messages (bandwidth report, ping, etc)
RTMP_SYSTEM_CHANNEL, ///< channel for sending server control messages
- RTMP_SOURCE_CHANNEL, ///< channel for sending a/v to server
- RTMP_VIDEO_CHANNEL = 8, ///< channel for video data
RTMP_AUDIO_CHANNEL, ///< channel for audio data
+ RTMP_VIDEO_CHANNEL = 6, ///< channel for video data
+ RTMP_SOURCE_CHANNEL = 8, ///< channel for a/v invokes
};
/**
@@ -81,7 +81,9 @@ typedef struct RTMPPacket {
uint32_t ts_delta; ///< timestamp increment to the previous one in milliseconds (latter only for media packets)
uint32_t extra; ///< probably an additional channel ID used during streaming data
uint8_t *data; ///< packet payload
- int data_size; ///< packet payload size
+ int size; ///< packet payload size
+ int offset; ///< amount of data read so far
+ int read; ///< amount read, including headers
} RTMPPacket;
/**
@@ -112,10 +114,12 @@ void ff_rtmp_packet_destroy(RTMPPacket *pkt);
* @param chunk_size current chunk size
* @param prev_pkt previously read packet headers for all channels
* (may be needed for restoring incomplete packet header)
+ * @param nb_prev_pkt number of allocated elements in prev_pkt
* @return number of bytes read on success, negative value otherwise
*/
int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
- int chunk_size, RTMPPacket *prev_pkt);
+ int chunk_size, RTMPPacket **prev_pkt,
+ int *nb_prev_pkt);
/**
* Read internal RTMP packet sent by the server.
*
@@ -124,11 +128,13 @@ int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
* @param chunk_size current chunk size
* @param prev_pkt previously read packet headers for all channels
* (may be needed for restoring incomplete packet header)
+ * @param nb_prev_pkt number of allocated elements in prev_pkt
* @param c the first byte already read
* @return number of bytes read on success, negative value otherwise
*/
int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
- RTMPPacket *prev_pkt, uint8_t c);
+ RTMPPacket **prev_pkt, int *nb_prev_pkt,
+ uint8_t c);
/**
* Send RTMP packet to the server.
@@ -138,10 +144,12 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
* @param chunk_size current chunk size
* @param prev_pkt previously sent packet headers for all channels
* (may be used for packet header compressing)
+ * @param nb_prev_pkt number of allocated elements in prev_pkt
* @return number of bytes written on success, negative value otherwise
*/
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p,
- int chunk_size, RTMPPacket *prev_pkt);
+ int chunk_size, RTMPPacket **prev_pkt,
+ int *nb_prev_pkt);
/**
* Print information and contents of RTMP packet.
@@ -152,6 +160,16 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p,
void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p);
/**
+ * Enlarge the prev_pkt array to fit the given channel
+ *
+ * @param prev_pkt array with previously sent packet headers
+ * @param nb_prev_pkt number of allocated elements in prev_pkt
+ * @param channel the channel number that needs to be allocated
+ */
+int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt,
+ int channel);
+
+/**
* @name Functions used to work with the AMF format (which is also used in .flv)
* @see amf_* funcs in libavformat/flvdec.c
* @{
@@ -282,6 +300,13 @@ int ff_amf_read_string(GetByteContext *gbc, uint8_t *str,
*/
int ff_amf_read_null(GetByteContext *gbc);
+/**
+ * Match AMF string with a NULL-terminated string.
+ *
+ * @return 0 if the strings do not match.
+ */
+
+int ff_amf_match_string(const uint8_t *data, int size, const char *str);
/** @} */ // AMF funcs
diff --git a/ffmpeg/libavformat/rtmpproto.c b/ffmpeg/libavformat/rtmpproto.c
index d73e015..a4d7f0e 100644
--- a/ffmpeg/libavformat/rtmpproto.c
+++ b/ffmpeg/libavformat/rtmpproto.c
@@ -1,6 +1,6 @@
/*
* RTMP network protocol
- * Copyright (c) 2009 Kostya Shishkov
+ * Copyright (c) 2009 Konstantin Shishkov
*
* This file is part of FFmpeg.
*
@@ -48,13 +48,12 @@
#include <zlib.h>
#endif
-//#define DEBUG
-
#define APP_MAX_LENGTH 1024
#define PLAYPATH_MAX_LENGTH 256
#define TCURL_MAX_LENGTH 512
#define FLASHVER_MAX_LENGTH 64
#define RTMP_PKTDATA_DEFAULT_SIZE 4096
+#define RTMP_HEADER 11
/** RTMP protocol handler state */
typedef enum {
@@ -62,8 +61,10 @@ typedef enum {
STATE_HANDSHAKED, ///< client has performed handshake
STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
STATE_PLAYING, ///< client has started receiving multimedia data from server
+ STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
STATE_RECEIVING, ///< received a publish command (for input)
+ STATE_SENDING, ///< received a play command (for output)
STATE_STOPPED, ///< the broadcast has been stopped
} ClientState;
@@ -76,7 +77,8 @@ typedef struct TrackedMethod {
typedef struct RTMPContext {
const AVClass *class;
URLContext* stream; ///< TCP stream used in interactions with RTMP server
- RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
+ RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
+ int nb_prev_pkt[2]; ///< number of elements in prev_pkt
int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
int is_input; ///< input/output flag
@@ -85,7 +87,7 @@ typedef struct RTMPContext {
char *app; ///< name of application
char *conn; ///< append arbitrary AMF data to the Connect message
ClientState state; ///< current state
- int main_channel_id; ///< an additional channel ID which is used for some invocations
+ int stream_id; ///< ID assigned by the server for the stream
uint8_t* flv_data; ///< buffer with data for demuxer
int flv_size; ///< current buffer size
int flv_off; ///< number of bytes read from current buffer
@@ -95,7 +97,7 @@ typedef struct RTMPContext {
uint32_t bytes_read; ///< number of bytes read from server
uint32_t last_bytes_read; ///< number of bytes read last reported to server
int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
- uint8_t flv_header[11]; ///< partial incoming flv packet header
+ uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
int flv_header_bytes; ///< number of initialized bytes in flv_header
int nb_invokes; ///< keeps track of invoke messages
char* tcurl; ///< url of the target stream
@@ -150,15 +152,16 @@ static const uint8_t rtmp_server_key[] = {
static int add_tracked_method(RTMPContext *rt, const char *name, int id)
{
- void *ptr;
+ int err;
if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
- ptr = av_realloc(rt->tracked_methods,
- rt->tracked_methods_size * sizeof(*rt->tracked_methods));
- if (!ptr)
- return AVERROR(ENOMEM);
- rt->tracked_methods = ptr;
+ if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
+ sizeof(*rt->tracked_methods))) < 0) {
+ rt->nb_tracked_methods = 0;
+ rt->tracked_methods_size = 0;
+ return err;
+ }
}
rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
@@ -186,7 +189,7 @@ static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
int ret;
int i;
- bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset);
+ bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
return ret;
@@ -224,7 +227,7 @@ static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
double pkt_id;
int len;
- bytestream2_init(&gbc, pkt->data, pkt->data_size);
+ bytestream2_init(&gbc, pkt->data, pkt->size);
if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
goto fail;
@@ -236,7 +239,7 @@ static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
}
ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
fail:
ff_rtmp_packet_destroy(pkt);
return ret;
@@ -385,7 +388,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
}
}
- pkt.data_size = p - pkt.data;
+ pkt.size = p - pkt.data;
return rtmp_send_packet(rt, &pkt, 1);
}
@@ -403,10 +406,10 @@ static int read_connect(URLContext *s, RTMPContext *rt)
GetByteContext gbc;
if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
- rt->prev_pkt[1])) < 0)
+ &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
return ret;
cp = pkt.data;
- bytestream2_init(&gbc, cp, pkt.data_size);
+ bytestream2_init(&gbc, cp, pkt.size);
if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
ff_rtmp_packet_destroy(&pkt);
@@ -437,9 +440,9 @@ static int read_connect(URLContext *s, RTMPContext *rt)
return ret;
p = pkt.data;
bytestream_put_be32(&p, rt->server_bw);
- pkt.data_size = p - pkt.data;
+ pkt.size = p - pkt.data;
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
if (ret < 0)
return ret;
@@ -450,9 +453,9 @@ static int read_connect(URLContext *s, RTMPContext *rt)
p = pkt.data;
bytestream_put_be32(&p, rt->server_bw);
bytestream_put_byte(&p, 2); // dynamic
- pkt.data_size = p - pkt.data;
+ pkt.size = p - pkt.data;
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
if (ret < 0)
return ret;
@@ -466,7 +469,7 @@ static int read_connect(URLContext *s, RTMPContext *rt)
bytestream_put_be16(&p, 0); // 0 -> Stream Begin
bytestream_put_be32(&p, 0);
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
if (ret < 0)
return ret;
@@ -479,7 +482,7 @@ static int read_connect(URLContext *s, RTMPContext *rt)
p = pkt.data;
bytestream_put_be32(&p, rt->out_chunk_size);
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
if (ret < 0)
return ret;
@@ -512,9 +515,9 @@ static int read_connect(URLContext *s, RTMPContext *rt)
ff_amf_write_number(&p, 0);
ff_amf_write_object_end(&p);
- pkt.data_size = p - pkt.data;
+ pkt.size = p - pkt.data;
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
if (ret < 0)
return ret;
@@ -527,9 +530,9 @@ static int read_connect(URLContext *s, RTMPContext *rt)
ff_amf_write_number(&p, 0);
ff_amf_write_null(&p);
ff_amf_write_number(&p, 8192);
- pkt.data_size = p - pkt.data;
+ pkt.size = p - pkt.data;
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&pkt);
return ret;
@@ -652,7 +655,7 @@ static int gen_delete_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_string(&p, "deleteStream");
ff_amf_write_number(&p, ++rt->nb_invokes);
ff_amf_write_null(&p);
- ff_amf_write_number(&p, rt->main_channel_id);
+ ff_amf_write_number(&p, rt->stream_id);
return rtmp_send_packet(rt, &pkt, 0);
}
@@ -672,7 +675,7 @@ static int gen_buffer_time(URLContext *s, RTMPContext *rt)
p = pkt.data;
bytestream_put_be16(&p, 3);
- bytestream_put_be32(&p, rt->main_channel_id);
+ bytestream_put_be32(&p, rt->stream_id);
bytestream_put_be32(&p, rt->client_buffer_time);
return rtmp_send_packet(rt, &pkt, 0);
@@ -690,18 +693,41 @@ static int gen_play(URLContext *s, RTMPContext *rt)
av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
- if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
+ if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
0, 29 + strlen(rt->playpath))) < 0)
return ret;
- pkt.extra = rt->main_channel_id;
+ pkt.extra = rt->stream_id;
p = pkt.data;
ff_amf_write_string(&p, "play");
ff_amf_write_number(&p, ++rt->nb_invokes);
ff_amf_write_null(&p);
ff_amf_write_string(&p, rt->playpath);
- ff_amf_write_number(&p, rt->live);
+ ff_amf_write_number(&p, rt->live * 1000);
+
+ return rtmp_send_packet(rt, &pkt, 1);
+}
+
+static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
+{
+ RTMPPacket pkt;
+ uint8_t *p;
+ int ret;
+
+ av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
+ timestamp);
+
+ if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
+ return ret;
+
+ pkt.extra = rt->stream_id;
+
+ p = pkt.data;
+ ff_amf_write_string(&p, "seek");
+ ff_amf_write_number(&p, 0); //no tracking back responses
+ ff_amf_write_null(&p); //as usual, the first null param
+ ff_amf_write_number(&p, timestamp); //where we want to jump
return rtmp_send_packet(rt, &pkt, 1);
}
@@ -721,7 +747,7 @@ static int gen_publish(URLContext *s, RTMPContext *rt)
0, 30 + strlen(rt->playpath))) < 0)
return ret;
- pkt.extra = rt->main_channel_id;
+ pkt.extra = rt->stream_id;
p = pkt.data;
ff_amf_write_string(&p, "publish");
@@ -742,9 +768,9 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
uint8_t *p;
int ret;
- if (ppkt->data_size < 6) {
+ if (ppkt->size < 6) {
av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
- ppkt->data_size);
+ ppkt->size);
return AVERROR_INVALIDDATA;
}
@@ -1323,7 +1349,7 @@ static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
int inoutsize;
AV_WB32(arraydata, first_int);
- AV_WB32(arraydata + 4, first_int);
+ AV_WB32(arraydata + 4, second_int);
inoutsize = ffurl_write(rt->stream, arraydata,
RTMP_HANDSHAKE_PACKET_SIZE);
if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
@@ -1372,8 +1398,6 @@ static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
return ret;
}
- if (zeroes)
- av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n");
/* Send S1 */
/* By now same epoch will be sent */
hs_my_epoch = hs_epoch;
@@ -1418,10 +1442,10 @@ static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
RTMPContext *rt = s->priv_data;
int ret;
- if (pkt->data_size < 4) {
+ if (pkt->size < 4) {
av_log(s, AV_LOG_ERROR,
"Too short chunk size change packet (%d)\n",
- pkt->data_size);
+ pkt->size);
return AVERROR_INVALIDDATA;
}
@@ -1429,7 +1453,7 @@ static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
/* Send the same chunk size change packet back to the server,
* setting the outgoing chunk size to the same as the incoming one. */
if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
- rt->prev_pkt[1])) < 0)
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
return ret;
rt->out_chunk_size = AV_RB32(pkt->data);
}
@@ -1451,9 +1475,9 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt)
RTMPContext *rt = s->priv_data;
int t, ret;
- if (pkt->data_size < 2) {
+ if (pkt->size < 2) {
av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
- pkt->data_size);
+ pkt->size);
return AVERROR_INVALIDDATA;
}
@@ -1477,10 +1501,10 @@ static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
{
RTMPContext *rt = s->priv_data;
- if (pkt->data_size < 4) {
+ if (pkt->size < 4) {
av_log(s, AV_LOG_ERROR,
"Client bandwidth report packet is less than 4 bytes long (%d)\n",
- pkt->data_size);
+ pkt->size);
return AVERROR_INVALIDDATA;
}
@@ -1501,10 +1525,10 @@ static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
{
RTMPContext *rt = s->priv_data;
- if (pkt->data_size < 4) {
+ if (pkt->size < 4) {
av_log(s, AV_LOG_ERROR,
"Too short server bandwidth report packet (%d)\n",
- pkt->data_size);
+ pkt->size);
return AVERROR_INVALIDDATA;
}
@@ -1587,6 +1611,8 @@ static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
av_md5_update(md5, method, strlen(method));
av_md5_update(md5, ":/", 2);
av_md5_update(md5, rt->app, strlen(rt->app));
+ if (!strchr(rt->app, '/'))
+ av_md5_update(md5, "/_definst_", strlen("/_definst_"));
av_md5_final(md5, hash);
ff_data_to_hex(hashstr2, hash, 16, 1);
hashstr2[32] = '\0';
@@ -1704,7 +1730,7 @@ static int handle_connect_error(URLContext *s, const char *desc)
static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
{
RTMPContext *rt = s->priv_data;
- const uint8_t *data_end = pkt->data + pkt->data_size;
+ const uint8_t *data_end = pkt->data + pkt->size;
char *tracked_method = NULL;
int level = AV_LOG_ERROR;
uint8_t tmpstr[256];
@@ -1737,13 +1763,84 @@ static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
return ret;
}
+static int write_begin(URLContext *s)
+{
+ RTMPContext *rt = s->priv_data;
+ PutByteContext pbc;
+ RTMPPacket spkt = { 0 };
+ int ret;
+
+ // Send Stream Begin 1
+ if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
+ RTMP_PT_PING, 0, 6)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
+ return ret;
+ }
+
+ bytestream2_init_writer(&pbc, spkt.data, spkt.size);
+ bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
+ bytestream2_put_be32(&pbc, rt->nb_streamid);
+
+ ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
+
+ ff_rtmp_packet_destroy(&spkt);
+
+ return ret;
+}
+
+static int write_status(URLContext *s, RTMPPacket *pkt,
+ const char *status, const char *filename)
+{
+ RTMPContext *rt = s->priv_data;
+ RTMPPacket spkt = { 0 };
+ char statusmsg[128];
+ uint8_t *pp;
+ int ret;
+
+ if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
+ RTMP_PT_INVOKE, 0,
+ RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
+ return ret;
+ }
+
+ pp = spkt.data;
+ spkt.extra = pkt->extra;
+ ff_amf_write_string(&pp, "onStatus");
+ ff_amf_write_number(&pp, 0);
+ ff_amf_write_null(&pp);
+
+ ff_amf_write_object_start(&pp);
+ ff_amf_write_field_name(&pp, "level");
+ ff_amf_write_string(&pp, "status");
+ ff_amf_write_field_name(&pp, "code");
+ ff_amf_write_string(&pp, status);
+ ff_amf_write_field_name(&pp, "description");
+ snprintf(statusmsg, sizeof(statusmsg),
+ "%s is now published", filename);
+ ff_amf_write_string(&pp, statusmsg);
+ ff_amf_write_field_name(&pp, "details");
+ ff_amf_write_string(&pp, filename);
+ ff_amf_write_field_name(&pp, "clientid");
+ snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
+ ff_amf_write_string(&pp, statusmsg);
+ ff_amf_write_object_end(&pp);
+
+ spkt.size = pp - spkt.data;
+ ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
+ ff_rtmp_packet_destroy(&spkt);
+
+ return ret;
+}
+
static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
{
RTMPContext *rt = s->priv_data;
double seqnum;
char filename[64];
char command[64];
- char statusmsg[128];
int stringlen;
char *pchar;
const uint8_t *p = pkt->data;
@@ -1752,7 +1849,7 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
GetByteContext gbc;
int ret;
- bytestream2_init(&gbc, p, pkt->data_size);
+ bytestream2_init(&gbc, p, pkt->size);
if (ff_amf_read_string(&gbc, command, sizeof(command),
&stringlen)) {
av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
@@ -1796,52 +1893,20 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
pp = spkt.data;
ff_amf_write_string(&pp, "onFCPublish");
} else if (!strcmp(command, "publish")) {
- PutByteContext pbc;
- // Send Stream Begin 1
- if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
- RTMP_PT_PING, 0, 6)) < 0) {
- av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
- return ret;
- }
- pp = spkt.data;
- bytestream2_init_writer(&pbc, pp, spkt.data_size);
- bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
- bytestream2_put_be32(&pbc, rt->nb_streamid);
- ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&spkt);
+ ret = write_begin(s);
if (ret < 0)
return ret;
// Send onStatus(NetStream.Publish.Start)
- if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
- RTMP_PT_INVOKE, 0,
- RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
- av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
+ return write_status(s, pkt, "NetStream.Publish.Start",
+ filename);
+ } else if (!strcmp(command, "play")) {
+ ret = write_begin(s);
+ if (ret < 0)
return ret;
- }
- spkt.extra = pkt->extra;
- pp = spkt.data;
- ff_amf_write_string(&pp, "onStatus");
- ff_amf_write_number(&pp, 0);
- ff_amf_write_null(&pp);
-
- ff_amf_write_object_start(&pp);
- ff_amf_write_field_name(&pp, "level");
- ff_amf_write_string(&pp, "status");
- ff_amf_write_field_name(&pp, "code");
- ff_amf_write_string(&pp, "NetStream.Publish.Start");
- ff_amf_write_field_name(&pp, "description");
- snprintf(statusmsg, sizeof(statusmsg),
- "%s is now published", filename);
- ff_amf_write_string(&pp, statusmsg);
- ff_amf_write_field_name(&pp, "details");
- ff_amf_write_string(&pp, filename);
- ff_amf_write_field_name(&pp, "clientid");
- snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
- ff_amf_write_string(&pp, statusmsg);
- ff_amf_write_object_end(&pp);
-
+ rt->state = STATE_SENDING;
+ return write_status(s, pkt, "NetStream.Play.Start",
+ filename);
} else {
if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
RTMP_PT_INVOKE, 0,
@@ -1863,9 +1928,9 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
* if a client creates more than 2^32 - 2 streams. */
}
}
- spkt.data_size = pp - spkt.data;
+ spkt.size = pp - spkt.data;
ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
- rt->prev_pkt[1]);
+ &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
ff_rtmp_packet_destroy(&spkt);
return ret;
}
@@ -1884,7 +1949,7 @@ static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
return ret;
}
- if (!memcmp(tracked_method, "connect", 7)) {
+ if (!strcmp(tracked_method, "connect")) {
if (!rt->is_input) {
if ((ret = gen_release_stream(s, rt)) < 0)
goto fail;
@@ -1910,12 +1975,12 @@ static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
goto fail;
}
}
- } else if (!memcmp(tracked_method, "createStream", 12)) {
+ } else if (!strcmp(tracked_method, "createStream")) {
//extract a number from the result
if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
} else {
- rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
+ rt->stream_id = av_int2double(AV_RB64(pkt->data + 21));
}
if (!rt->is_input) {
@@ -1937,8 +2002,8 @@ fail:
static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
{
RTMPContext *rt = s->priv_data;
- const uint8_t *data_end = pkt->data + pkt->data_size;
- const uint8_t *ptr = pkt->data + 11;
+ const uint8_t *data_end = pkt->data + pkt->size;
+ const uint8_t *ptr = pkt->data + RTMP_HEADER;
uint8_t tmpstr[256];
int i, t;
@@ -1951,8 +2016,12 @@ static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
if (!t && !strcmp(tmpstr, "error")) {
- if (!ff_amf_get_field_value(ptr, data_end,
- "description", tmpstr, sizeof(tmpstr)))
+ t = ff_amf_get_field_value(ptr, data_end,
+ "description", tmpstr, sizeof(tmpstr));
+ if (t || !tmpstr[0])
+ t = ff_amf_get_field_value(ptr, data_end, "code",
+ tmpstr, sizeof(tmpstr));
+ if (!t)
av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
return -1;
}
@@ -1962,6 +2031,7 @@ static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
+ if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
return 0;
}
@@ -1972,23 +2042,24 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt)
int ret = 0;
//TODO: check for the messages sent for wrong state?
- if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
+ if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
if ((ret = handle_invoke_error(s, pkt)) < 0)
return ret;
- } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
+ } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
if ((ret = handle_invoke_result(s, pkt)) < 0)
return ret;
- } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
+ } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
if ((ret = handle_invoke_status(s, pkt)) < 0)
return ret;
- } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
+ } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
if ((ret = gen_check_bw(s, rt)) < 0)
return ret;
- } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) ||
- !memcmp(pkt->data, "\002\000\011FCPublish", 12) ||
- !memcmp(pkt->data, "\002\000\007publish", 10) ||
- !memcmp(pkt->data, "\002\000\010_checkbw", 11) ||
- !memcmp(pkt->data, "\002\000\014createStream", 15)) {
+ } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
+ ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
+ ff_amf_match_string(pkt->data, pkt->size, "publish") ||
+ ff_amf_match_string(pkt->data, pkt->size, "play") ||
+ ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
+ ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
if ((ret = send_invoke_response(s, pkt)) < 0)
return ret;
}
@@ -1996,65 +2067,75 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt)
return ret;
}
-static int handle_notify(URLContext *s, RTMPPacket *pkt) {
+static int update_offset(RTMPContext *rt, int size)
+{
+ int old_flv_size;
+
+ // generate packet header and put data into buffer for FLV demuxer
+ if (rt->flv_off < rt->flv_size) {
+ // There is old unread data in the buffer, thus append at the end
+ old_flv_size = rt->flv_size;
+ rt->flv_size += size;
+ } else {
+ // All data has been read, write the new data at the start of the buffer
+ old_flv_size = 0;
+ rt->flv_size = size;
+ rt->flv_off = 0;
+ }
+
+ return old_flv_size;
+}
+
+static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
+{
+ int old_flv_size, ret;
+ PutByteContext pbc;
+ const uint8_t *data = pkt->data + skip;
+ const int size = pkt->size - skip;
+ uint32_t ts = pkt->timestamp;
+
+ old_flv_size = update_offset(rt, size + 15);
+
+ if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
+ rt->flv_size = rt->flv_off = 0;
+ return ret;
+ }
+ bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
+ bytestream2_skip_p(&pbc, old_flv_size);
+ bytestream2_put_byte(&pbc, pkt->type);
+ bytestream2_put_be24(&pbc, size);
+ bytestream2_put_be24(&pbc, ts);
+ bytestream2_put_byte(&pbc, ts >> 24);
+ bytestream2_put_be24(&pbc, 0);
+ bytestream2_put_buffer(&pbc, data, size);
+ bytestream2_put_be32(&pbc, 0);
+
+ return 0;
+}
+
+static int handle_notify(URLContext *s, RTMPPacket *pkt)
+{
RTMPContext *rt = s->priv_data;
- const uint8_t *p = NULL;
- uint8_t *cp = NULL;
uint8_t commandbuffer[64];
char statusmsg[128];
- int stringlen;
+ int stringlen, ret, skip = 0;
GetByteContext gbc;
- PutByteContext pbc;
- uint32_t ts;
- int old_flv_size;
- const uint8_t *datatowrite;
- unsigned datatowritelength;
- p = pkt->data;
- bytestream2_init(&gbc, p, pkt->data_size);
+ bytestream2_init(&gbc, pkt->data, pkt->size);
if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
&stringlen))
return AVERROR_INVALIDDATA;
+
+ // Skip the @setDataFrame string and validate it is a notification
if (!strcmp(commandbuffer, "@setDataFrame")) {
- datatowrite = gbc.buffer;
- datatowritelength = bytestream2_get_bytes_left(&gbc);
- if (ff_amf_read_string(&gbc, statusmsg,
- sizeof(statusmsg), &stringlen))
+ skip = gbc.buffer - pkt->data;
+ ret = ff_amf_read_string(&gbc, statusmsg,
+ sizeof(statusmsg), &stringlen);
+ if (ret < 0)
return AVERROR_INVALIDDATA;
- if (strcmp(statusmsg, "onMetaData")) {
- av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n",
- statusmsg);
- return 0;
- }
-
- /* Provide ECMAArray to flv */
- ts = pkt->timestamp;
-
- // generate packet header and put data into buffer for FLV demuxer
- if (rt->flv_off < rt->flv_size) {
- old_flv_size = rt->flv_size;
- rt->flv_size += datatowritelength + 15;
- } else {
- old_flv_size = 0;
- rt->flv_size = datatowritelength + 15;
- rt->flv_off = 0;
- }
-
- cp = av_realloc(rt->flv_data, rt->flv_size);
- if (!cp)
- return AVERROR(ENOMEM);
- rt->flv_data = cp;
- bytestream2_init_writer(&pbc, cp, rt->flv_size);
- bytestream2_skip_p(&pbc, old_flv_size);
- bytestream2_put_byte(&pbc, pkt->type);
- bytestream2_put_be24(&pbc, datatowritelength);
- bytestream2_put_be24(&pbc, ts);
- bytestream2_put_byte(&pbc, ts >> 24);
- bytestream2_put_be24(&pbc, 0);
- bytestream2_put_buffer(&pbc, datatowrite, datatowritelength);
- bytestream2_put_be32(&pbc, 0);
}
- return 0;
+
+ return append_flv_data(rt, pkt, skip);
}
/**
@@ -2108,6 +2189,55 @@ static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
return 0;
}
+static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
+{
+ int ret, old_flv_size, type;
+ const uint8_t *next;
+ uint8_t *p;
+ uint32_t size;
+ uint32_t ts, cts, pts = 0;
+
+ old_flv_size = update_offset(rt, pkt->size);
+
+ if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
+ rt->flv_size = rt->flv_off = 0;
+ return ret;
+ }
+
+ next = pkt->data;
+ p = rt->flv_data + old_flv_size;
+
+ /* copy data while rewriting timestamps */
+ ts = pkt->timestamp;
+
+ while (next - pkt->data < pkt->size - RTMP_HEADER) {
+ type = bytestream_get_byte(&next);
+ size = bytestream_get_be24(&next);
+ cts = bytestream_get_be24(&next);
+ cts |= bytestream_get_byte(&next) << 24;
+ if (!pts)
+ pts = cts;
+ ts += cts - pts;
+ pts = cts;
+ if (size + 3 + 4 > pkt->data + pkt->size - next)
+ break;
+ bytestream_put_byte(&p, type);
+ bytestream_put_be24(&p, size);
+ bytestream_put_be24(&p, ts);
+ bytestream_put_byte(&p, ts >> 24);
+ memcpy(p, next, size + 3 + 4);
+ next += size + 3 + 4;
+ p += size + 3 + 4;
+ }
+ if (p != rt->flv_data + rt->flv_size) {
+ av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
+ "RTMP_PT_METADATA packet\n");
+ rt->flv_size = p - rt->flv_data;
+ }
+
+ return 0;
+}
+
/**
* Interact with the server by receiving and sending RTMP packets until
* there is some significant data (media data or expected status notification).
@@ -2123,10 +2253,6 @@ static int get_packet(URLContext *s, int for_header)
{
RTMPContext *rt = s->priv_data;
int ret;
- uint8_t *p;
- const uint8_t *next;
- uint32_t data_size;
- uint32_t ts, cts, pts=0;
if (rt->state == STATE_STOPPED)
return AVERROR_EOF;
@@ -2134,7 +2260,8 @@ static int get_packet(URLContext *s, int for_header)
for (;;) {
RTMPPacket rpkt = { 0 };
if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
- rt->in_chunk_size, rt->prev_pkt[0])) <= 0) {
+ rt->in_chunk_size, &rt->prev_pkt[0],
+ &rt->nb_prev_pkt[0])) <= 0) {
if (ret == 0) {
return AVERROR(EAGAIN);
} else {
@@ -2150,6 +2277,17 @@ static int get_packet(URLContext *s, int for_header)
}
ret = rtmp_parse_result(s, rt, &rpkt);
+
+ // At this point we must check if we are in the seek state and continue
+ // with the next packet. handle_invoke will get us out of this state
+ // when the right message is encountered
+ if (rt->state == STATE_SEEKING) {
+ ff_rtmp_packet_destroy(&rpkt);
+ // We continue, let the natural flow of things happen:
+ // AVERROR(EAGAIN) or handle_invoke gets us out of here
+ continue;
+ }
+
if (ret < 0) {//serious error in current packet
ff_rtmp_packet_destroy(&rpkt);
return ret;
@@ -2164,62 +2302,25 @@ static int get_packet(URLContext *s, int for_header)
}
if (for_header && (rt->state == STATE_PLAYING ||
rt->state == STATE_PUBLISHING ||
+ rt->state == STATE_SENDING ||
rt->state == STATE_RECEIVING)) {
ff_rtmp_packet_destroy(&rpkt);
return 0;
}
- if (!rpkt.data_size || !rt->is_input) {
+ if (!rpkt.size || !rt->is_input) {
ff_rtmp_packet_destroy(&rpkt);
continue;
}
- if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
- (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
- ts = rpkt.timestamp;
-
- // generate packet header and put data into buffer for FLV demuxer
- rt->flv_off = 0;
- rt->flv_size = rpkt.data_size + 15;
- rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
- bytestream_put_byte(&p, rpkt.type);
- bytestream_put_be24(&p, rpkt.data_size);
- bytestream_put_be24(&p, ts);
- bytestream_put_byte(&p, ts >> 24);
- bytestream_put_be24(&p, 0);
- bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
- bytestream_put_be32(&p, 0);
+ if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
+ ret = append_flv_data(rt, &rpkt, 0);
ff_rtmp_packet_destroy(&rpkt);
- return 0;
+ return ret;
} else if (rpkt.type == RTMP_PT_NOTIFY) {
ret = handle_notify(s, &rpkt);
ff_rtmp_packet_destroy(&rpkt);
- if (ret) {
- av_log(s, AV_LOG_ERROR, "Handle notify error\n");
- return ret;
- }
- return 0;
+ return ret;
} else if (rpkt.type == RTMP_PT_METADATA) {
- // we got raw FLV data, make it available for FLV demuxer
- rt->flv_off = 0;
- rt->flv_size = rpkt.data_size;
- rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
- /* rewrite timestamps */
- next = rpkt.data;
- ts = rpkt.timestamp;
- while (next - rpkt.data < rpkt.data_size - 11) {
- next++;
- data_size = bytestream_get_be24(&next);
- p=next;
- cts = bytestream_get_be24(&next);
- cts |= bytestream_get_byte(&next) << 24;
- if (pts==0)
- pts=cts;
- ts += cts - pts;
- pts = cts;
- bytestream_put_be24(&p, ts);
- bytestream_put_byte(&p, ts >> 24);
- next += data_size + 3 + 4;
- }
- memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
+ ret = handle_metadata(rt, &rpkt);
ff_rtmp_packet_destroy(&rpkt);
return 0;
}
@@ -2230,17 +2331,22 @@ static int get_packet(URLContext *s, int for_header)
static int rtmp_close(URLContext *h)
{
RTMPContext *rt = h->priv_data;
- int ret = 0;
+ int ret = 0, i, j;
if (!rt->is_input) {
rt->flv_data = NULL;
- if (rt->out_pkt.data_size)
+ if (rt->out_pkt.size)
ff_rtmp_packet_destroy(&rt->out_pkt);
if (rt->state > STATE_FCPUBLISH)
ret = gen_fcunpublish_stream(h, rt);
}
if (rt->state > STATE_HANDSHAKED)
ret = gen_delete_stream(h, rt);
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < rt->nb_prev_pkt[i]; j++)
+ ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
+ av_freep(&rt->prev_pkt[i]);
+ }
free_tracked_methods(rt);
av_freep(&rt->flv_data);
@@ -2276,6 +2382,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
hostname, sizeof(hostname), &port,
path, sizeof(path), s->filename);
+ if (strchr(path, ' ')) {
+ av_log(s, AV_LOG_WARNING,
+ "Detected librtmp style URL parameters, these aren't supported "
+ "by the libavformat internal RTMP handler currently enabled. "
+ "See the documentation for the correct way to pass parameters.\n");
+ }
+
if (auth[0]) {
char *ptr = strchr(auth, ':');
if (ptr) {
@@ -2445,29 +2558,33 @@ reconnect:
} else {
if (read_connect(s, s->priv_data) < 0)
goto fail;
- rt->is_input = 1;
}
do {
ret = get_packet(s, 1);
- } while (ret == EAGAIN);
+ } while (ret == AVERROR(EAGAIN));
if (ret < 0)
goto fail;
if (rt->do_reconnect) {
+ int i;
ffurl_close(rt->stream);
rt->stream = NULL;
rt->do_reconnect = 0;
rt->nb_invokes = 0;
- memset(rt->prev_pkt, 0, sizeof(rt->prev_pkt));
+ for (i = 0; i < 2; i++)
+ memset(rt->prev_pkt[i], 0,
+ sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
free_tracked_methods(rt);
goto reconnect;
}
if (rt->is_input) {
+ int err;
// generate FLV header for demuxer
rt->flv_size = 13;
- rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
+ if ((err = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
+ return err;
rt->flv_off = 0;
memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
} else {
@@ -2514,6 +2631,26 @@ static int rtmp_read(URLContext *s, uint8_t *buf, int size)
return orig_size;
}
+static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
+ int flags)
+{
+ RTMPContext *rt = s->priv_data;
+ int ret;
+ av_log(s, AV_LOG_DEBUG,
+ "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
+ stream_index, timestamp, flags);
+ if ((ret = gen_seek(s, rt, timestamp)) < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "Unable to send seek command on stream index %d at timestamp "
+ "%"PRId64" with flags %08x\n",
+ stream_index, timestamp, flags);
+ return ret;
+ }
+ rt->flv_off = rt->flv_size;
+ rt->state = STATE_SEEKING;
+ return timestamp;
+}
+
static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
{
RTMPContext *rt = s->priv_data;
@@ -2533,13 +2670,14 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
continue;
}
- if (rt->flv_header_bytes < 11) {
+ if (rt->flv_header_bytes < RTMP_HEADER) {
const uint8_t *header = rt->flv_header;
- int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
+ int copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
+ int channel = RTMP_AUDIO_CHANNEL;
bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
rt->flv_header_bytes += copy;
size_temp -= copy;
- if (rt->flv_header_bytes < 11)
+ if (rt->flv_header_bytes < RTMP_HEADER)
break;
pkttype = bytestream_get_byte(&header);
@@ -2549,20 +2687,27 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
bytestream_get_be24(&header);
rt->flv_size = pktsize;
+ if (pkttype == RTMP_PT_VIDEO)
+ channel = RTMP_VIDEO_CHANNEL;
+
//force 12bytes header
if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
pkttype == RTMP_PT_NOTIFY) {
if (pkttype == RTMP_PT_NOTIFY)
pktsize += 16;
- rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
+ if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
+ &rt->nb_prev_pkt[1],
+ channel)) < 0)
+ return ret;
+ rt->prev_pkt[1][channel].channel_id = 0;
}
//this can be a big packet, it's better to send it right here
- if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
+ if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
pkttype, ts, pktsize)) < 0)
return ret;
- rt->out_pkt.extra = rt->main_channel_id;
+ rt->out_pkt.extra = rt->stream_id;
rt->flv_data = rt->out_pkt.data;
if (pkttype == RTMP_PT_NOTIFY)
@@ -2614,7 +2759,8 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
rt->in_chunk_size,
- rt->prev_pkt[0], c)) <= 0)
+ &rt->prev_pkt[0],
+ &rt->nb_prev_pkt[0], c)) <= 0)
return ret;
if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
@@ -2649,6 +2795,7 @@ static const AVOption rtmp_options[] = {
{"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", 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},
{"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
+ {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
{"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
{ NULL },
};
@@ -2665,6 +2812,7 @@ URLProtocol ff_##flavor##_protocol = { \
.name = #flavor, \
.url_open = rtmp_open, \
.url_read = rtmp_read, \
+ .url_read_seek = rtmp_seek, \
.url_write = rtmp_write, \
.url_close = rtmp_close, \
.priv_data_size = sizeof(RTMPContext), \
diff --git a/ffmpeg/libavformat/rtp.c b/ffmpeg/libavformat/rtp.c
index c4dcf6a..4d41350 100644
--- a/ffmpeg/libavformat/rtp.c
+++ b/ffmpeg/libavformat/rtp.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "avformat.h"
@@ -144,7 +145,7 @@ enum AVCodecID ff_rtp_codec_id(const char *buf, enum AVMediaType codec_type)
int i;
for (i = 0; rtp_payload_types[i].pt >= 0; i++)
- if (!strcmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type))
+ if (!av_strcasecmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type))
return rtp_payload_types[i].codec_id;
return AV_CODEC_ID_NONE;
diff --git a/ffmpeg/libavformat/rtp.h b/ffmpeg/libavformat/rtp.h
index 1732af8..66a4f3a 100644
--- a/ffmpeg/libavformat/rtp.h
+++ b/ffmpeg/libavformat/rtp.h
@@ -23,6 +23,7 @@
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
+#include "libavutil/mathematics.h"
/**
* Return the payload type for a given stream used in the given format context.
@@ -109,4 +110,6 @@ enum RTCPType {
#define RTP_PT_IS_RTCP(x) (((x) >= RTCP_FIR && (x) <= RTCP_IJ) || \
((x) >= RTCP_SR && (x) <= RTCP_TOKEN))
+#define NTP_TO_RTP_FORMAT(x) av_rescale((x), INT64_C(1) << 32, 1000000)
+
#endif /* AVFORMAT_RTP_H */
diff --git a/ffmpeg/libavformat/rtpdec.c b/ffmpeg/libavformat/rtpdec.c
index b512b89..ed118b0 100644
--- a/ffmpeg/libavformat/rtpdec.c
+++ b/ffmpeg/libavformat/rtpdec.c
@@ -32,6 +32,12 @@
#define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */
+static RTPDynamicProtocolHandler gsm_dynamic_handler = {
+ .enc_name = "GSM",
+ .codec_type = AVMEDIA_TYPE_AUDIO,
+ .codec_id = AV_CODEC_ID_GSM,
+};
+
static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = {
.enc_name = "X-MP3-draft-00",
.codec_type = AVMEDIA_TYPE_AUDIO,
@@ -58,7 +64,7 @@ void ff_register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler)
rtp_first_dynamic_payload_handler = handler;
}
-void av_register_rtp_dynamic_payload_handlers(void)
+void ff_register_rtp_dynamic_payload_handlers(void)
{
ff_register_dynamic_payload_handler(&ff_amr_nb_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_amr_wb_dynamic_handler);
@@ -78,8 +84,8 @@ void av_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_mpeg_video_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler);
- ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler);
ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler);
+ ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler);
ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_qt_rtp_aud_handler);
@@ -90,6 +96,7 @@ void av_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler);
+ ff_register_dynamic_payload_handler(&gsm_dynamic_handler);
ff_register_dynamic_payload_handler(&opus_dynamic_handler);
ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler);
ff_register_dynamic_payload_handler(&speex_dynamic_handler);
diff --git a/ffmpeg/libavformat/rtpdec.h b/ffmpeg/libavformat/rtpdec.h
index e469c0f..9321066 100644
--- a/ffmpeg/libavformat/rtpdec.h
+++ b/ffmpeg/libavformat/rtpdec.h
@@ -33,7 +33,7 @@ typedef struct PayloadContext PayloadContext;
typedef struct RTPDynamicProtocolHandler RTPDynamicProtocolHandler;
#define RTP_MIN_PACKET_LENGTH 12
-#define RTP_MAX_PACKET_LENGTH 1500
+#define RTP_MAX_PACKET_LENGTH 8192
#define RTP_REORDER_QUEUE_DEFAULT_SIZE 10
@@ -51,10 +51,6 @@ int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
void ff_rtp_parse_close(RTPDemuxContext *s);
int64_t ff_rtp_queued_packet_time(RTPDemuxContext *s);
void ff_rtp_reset_packet_queue(RTPDemuxContext *s);
-int ff_rtp_get_local_rtp_port(URLContext *h);
-int ff_rtp_get_local_rtcp_port(URLContext *h);
-
-int ff_rtp_set_remote_url(URLContext *h, const char *uri);
/**
* Send a dummy packet on both port pairs to set up the connection
@@ -209,7 +205,7 @@ int ff_parse_fmtp(AVStream *stream, PayloadContext *data, const char *p,
PayloadContext *data,
char *attr, char *value));
-void av_register_rtp_dynamic_payload_handlers(void);
+void ff_register_rtp_dynamic_payload_handlers(void);
/**
* Close the dynamic buffer and make a packet from it.
diff --git a/ffmpeg/libavformat/rtpdec_asf.c b/ffmpeg/libavformat/rtpdec_asf.c
index 35603f2..123894f 100644
--- a/ffmpeg/libavformat/rtpdec_asf.c
+++ b/ffmpeg/libavformat/rtpdec_asf.c
@@ -239,14 +239,11 @@ static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf,
int cur_len = start_off + len_off - off;
int prev_len = out_len;
- void *newmem;
out_len += cur_len;
if (FFMIN(cur_len, len - off) < 0)
return -1;
- newmem = av_realloc(asf->buf, out_len);
- if (!newmem)
- return -1;
- asf->buf = newmem;
+ if ((res = av_reallocp(&asf->buf, out_len)) < 0)
+ return res;
memcpy(asf->buf + prev_len, buf + off,
FFMIN(cur_len, len - off));
avio_skip(pb, cur_len);
diff --git a/ffmpeg/libavformat/rtpdec_g726.c b/ffmpeg/libavformat/rtpdec_g726.c
index ec37f09..7e9ef56 100644
--- a/ffmpeg/libavformat/rtpdec_g726.c
+++ b/ffmpeg/libavformat/rtpdec_g726.c
@@ -18,11 +18,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/attributes.h"
#include "avformat.h"
#include "rtpdec_formats.h"
#define RTP_G726_HANDLER(bitrate) \
-static int g726_ ## bitrate ##_init(AVFormatContext *s, int st_index, PayloadContext *data) \
+static av_cold int g726_ ## bitrate ##_init(AVFormatContext *s, int st_index, \
+ PayloadContext *data) \
{ \
AVStream *stream = s->streams[st_index]; \
AVCodecContext *codec = stream->codec; \
diff --git a/ffmpeg/libavformat/rtpdec_h263.c b/ffmpeg/libavformat/rtpdec_h263.c
index dd7aa60..ae4cc27 100644
--- a/ffmpeg/libavformat/rtpdec_h263.c
+++ b/ffmpeg/libavformat/rtpdec_h263.c
@@ -21,9 +21,11 @@
#include "avformat.h"
#include "rtpdec_formats.h"
+#include "libavutil/attributes.h"
#include "libavutil/intreadwrite.h"
-static int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
+static av_cold int h263_init(AVFormatContext *ctx, int st_index,
+ PayloadContext *data)
{
if (st_index < 0)
return 0;
diff --git a/ffmpeg/libavformat/rtpdec_h263_rfc2190.c b/ffmpeg/libavformat/rtpdec_h263_rfc2190.c
index 4b6e996..a227901 100644
--- a/ffmpeg/libavformat/rtpdec_h263_rfc2190.c
+++ b/ffmpeg/libavformat/rtpdec_h263_rfc2190.c
@@ -8,25 +8,26 @@
* Copyright 2007 Collabora Ltd, Philippe Kalaf
* Copyright 2010 Mark Nauwelaerts
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "rtpdec_formats.h"
+#include "libavutil/attributes.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/get_bits.h"
@@ -55,7 +56,7 @@ static void h263_free_context(PayloadContext *data)
av_free(data);
}
-static int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
+static av_cold int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
{
if (st_index < 0)
return 0;
diff --git a/ffmpeg/libavformat/rtpdec_h264.c b/ffmpeg/libavformat/rtpdec_h264.c
index d1133b7..1ca78bc 100644
--- a/ffmpeg/libavformat/rtpdec_h264.c
+++ b/ffmpeg/libavformat/rtpdec_h264.c
@@ -33,6 +33,7 @@
* FU-B packet types)
*/
+#include "libavutil/attributes.h"
#include "libavutil/base64.h"
#include "libavutil/avstring.h"
#include "libavcodec/get_bits.h"
@@ -189,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);
@@ -246,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);
@@ -291,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 {
@@ -338,7 +343,8 @@ static void h264_free_context(PayloadContext *data)
av_free(data);
}
-static int h264_init(AVFormatContext *s, int st_index, PayloadContext *data)
+static av_cold int h264_init(AVFormatContext *s, int st_index,
+ PayloadContext *data)
{
if (st_index < 0)
return 0;
diff --git a/ffmpeg/libavformat/rtpdec_latm.c b/ffmpeg/libavformat/rtpdec_latm.c
index a2ad071..fdeff3a 100644
--- a/ffmpeg/libavformat/rtpdec_latm.c
+++ b/ffmpeg/libavformat/rtpdec_latm.c
@@ -130,10 +130,7 @@ static int parse_fmtp_config(AVStream *st, char *value)
goto end;
}
av_freep(&st->codec->extradata);
- st->codec->extradata_size = (get_bits_left(&gb) + 7)/8;
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
+ if (ff_alloc_extradata(st->codec, (get_bits_left(&gb) + 7)/8)) {
ret = AVERROR(ENOMEM);
goto end;
}
diff --git a/ffmpeg/libavformat/rtpdec_mpeg12.c b/ffmpeg/libavformat/rtpdec_mpeg12.c
index 82e58a0..d73ff1e 100644
--- a/ffmpeg/libavformat/rtpdec_mpeg12.c
+++ b/ffmpeg/libavformat/rtpdec_mpeg12.c
@@ -19,10 +19,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "rtpdec_formats.h"
+#include "libavutil/attributes.h"
#include "libavutil/intreadwrite.h"
+#include "rtpdec_formats.h"
-static int mpeg_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
+static av_cold int mpeg_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
{
if (st_index < 0)
return 0;
diff --git a/ffmpeg/libavformat/rtpdec_mpeg4.c b/ffmpeg/libavformat/rtpdec_mpeg4.c
index 3f1f244..0ea5594 100644
--- a/ffmpeg/libavformat/rtpdec_mpeg4.c
+++ b/ffmpeg/libavformat/rtpdec_mpeg4.c
@@ -29,6 +29,7 @@
#include "rtpdec_formats.h"
#include "internal.h"
+#include "libavutil/attributes.h"
#include "libavutil/avstring.h"
#include "libavcodec/get_bits.h"
@@ -104,10 +105,8 @@ static int parse_fmtp_config(AVCodecContext *codec, char *value)
/* decode the hexa encoded parameter */
int len = ff_hex_to_data(NULL, value);
av_free(codec->extradata);
- codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!codec->extradata)
+ if (ff_alloc_extradata(codec, len))
return AVERROR(ENOMEM);
- codec->extradata_size = len;
ff_hex_to_data(codec->extradata, value);
return 0;
}
@@ -252,7 +251,8 @@ static int parse_sdp_line(AVFormatContext *s, int st_index,
return 0;
}
-static int init_video(AVFormatContext *s, int st_index, PayloadContext *data)
+static av_cold int init_video(AVFormatContext *s, int st_index,
+ PayloadContext *data)
{
if (st_index < 0)
return 0;
diff --git a/ffmpeg/libavformat/rtpdec_mpegts.c b/ffmpeg/libavformat/rtpdec_mpegts.c
index cbb8eb4..5b851c4 100644
--- a/ffmpeg/libavformat/rtpdec_mpegts.c
+++ b/ffmpeg/libavformat/rtpdec_mpegts.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/attributes.h"
#include "mpegts.h"
#include "rtpdec_formats.h"
@@ -43,7 +44,8 @@ static void mpegts_free_context(PayloadContext *data)
av_free(data);
}
-static int mpegts_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
+static av_cold int mpegts_init(AVFormatContext *ctx, int st_index,
+ PayloadContext *data)
{
data->ts = ff_mpegts_parse_open(ctx);
if (!data->ts)
diff --git a/ffmpeg/libavformat/rtpdec_qdm2.c b/ffmpeg/libavformat/rtpdec_qdm2.c
index 6ce776d..e1dd62f 100644
--- a/ffmpeg/libavformat/rtpdec_qdm2.c
+++ b/ffmpeg/libavformat/rtpdec_qdm2.c
@@ -29,6 +29,7 @@
#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/avcodec.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -104,9 +105,7 @@ static int qdm2_parse_config(PayloadContext *qdm, AVStream *st,
if (item_len < 30)
return AVERROR_INVALIDDATA;
av_freep(&st->codec->extradata);
- st->codec->extradata_size = 26 + item_len;
- if (!(st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE))) {
- st->codec->extradata_size = 0;
+ if (ff_alloc_extradata(st->codec, 26 + item_len)) {
return AVERROR(ENOMEM);
}
AV_WB32(st->codec->extradata, 12);
diff --git a/ffmpeg/libavformat/rtpdec_qt.c b/ffmpeg/libavformat/rtpdec_qt.c
index 8e887a5..ee8a48a 100644
--- a/ffmpeg/libavformat/rtpdec_qt.c
+++ b/ffmpeg/libavformat/rtpdec_qt.c
@@ -172,17 +172,21 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
switch (packing_scheme) {
case 3: /* one data packet spread over 1 or multiple RTP packets */
if (qt->pkt.size > 0 && qt->timestamp == *timestamp) {
- qt->pkt.data = av_realloc(qt->pkt.data, qt->pkt.size + alen +
- FF_INPUT_BUFFER_PADDING_SIZE);
+ int err;
+ if ((err = av_reallocp(&qt->pkt.data, qt->pkt.size + alen +
+ FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
+ qt->pkt.size = 0;
+ return err;
+ }
} else {
av_freep(&qt->pkt.data);
av_init_packet(&qt->pkt);
- qt->pkt.data = av_malloc(alen + FF_INPUT_BUFFER_PADDING_SIZE);
+ qt->pkt.data = av_realloc(NULL, alen + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!qt->pkt.data)
+ return AVERROR(ENOMEM);
qt->pkt.size = 0;
qt->timestamp = *timestamp;
}
- if (!qt->pkt.data)
- return AVERROR(ENOMEM);
memcpy(qt->pkt.data + qt->pkt.size, buf + avio_tell(&pb), alen);
qt->pkt.size += alen;
if (has_marker_bit) {
@@ -211,7 +215,7 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
pkt->stream_index = st->index;
if (qt->remaining > 0) {
av_freep(&qt->pkt.data);
- qt->pkt.data = av_malloc(qt->remaining * qt->bytes_per_frame);
+ qt->pkt.data = av_realloc(NULL, qt->remaining * qt->bytes_per_frame);
if (!qt->pkt.data) {
av_free_packet(pkt);
return AVERROR(ENOMEM);
diff --git a/ffmpeg/libavformat/rtpdec_svq3.c b/ffmpeg/libavformat/rtpdec_svq3.c
index 106b785..98e8b58 100644
--- a/ffmpeg/libavformat/rtpdec_svq3.c
+++ b/ffmpeg/libavformat/rtpdec_svq3.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "libavutil/intreadwrite.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -60,11 +61,9 @@ static int svq3_parse_packet (AVFormatContext *s, PayloadContext *sv,
av_freep(&st->codec->extradata);
st->codec->extradata_size = 0;
- if (len < 2 || !(st->codec->extradata =
- av_malloc(len + 8 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ if (len < 2 || ff_alloc_extradata(st->codec, len + 8))
return AVERROR_INVALIDDATA;
- st->codec->extradata_size = len + 8;
memcpy(st->codec->extradata, "SEQH", 4);
AV_WB32(st->codec->extradata + 4, len);
memcpy(st->codec->extradata + 8, buf, len);
diff --git a/ffmpeg/libavformat/rtpdec_xiph.c b/ffmpeg/libavformat/rtpdec_xiph.c
index eddb781..887a65e 100644
--- a/ffmpeg/libavformat/rtpdec_xiph.c
+++ b/ffmpeg/libavformat/rtpdec_xiph.c
@@ -27,11 +27,13 @@
* @author Josh Allmann <joshua.allmann@gmail.com>
*/
+#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/base64.h"
#include "libavcodec/bytestream.h"
+#include "internal.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -69,8 +71,8 @@ static void xiph_free_context(PayloadContext * data)
av_free(data);
}
-static int xiph_vorbis_init(AVFormatContext *ctx, int st_index,
- PayloadContext *data)
+static av_cold int xiph_vorbis_init(AVFormatContext *ctx, int st_index,
+ PayloadContext *data)
{
if (st_index < 0)
return 0;
@@ -287,11 +289,11 @@ parse_packed_headers(const uint8_t * packed_headers,
* -- FF_INPUT_BUFFER_PADDING_SIZE required */
extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
- ptr = codec->extradata = av_malloc(extradata_alloc);
- if (!ptr) {
+ if (ff_alloc_extradata(codec, extradata_alloc)) {
av_log(codec, AV_LOG_ERROR, "Out of memory\n");
return AVERROR(ENOMEM);
}
+ ptr = codec->extradata;
*ptr++ = 2;
ptr += av_xiphlacing(ptr, length1);
ptr += av_xiphlacing(ptr, length2);
diff --git a/ffmpeg/libavformat/rtpenc.c b/ffmpeg/libavformat/rtpenc.c
index 7adf687..f010008 100644
--- a/ffmpeg/libavformat/rtpenc.c
+++ b/ffmpeg/libavformat/rtpenc.c
@@ -28,8 +28,6 @@
#include "rtpenc.h"
-//#define DEBUG
-
static const AVOption options[] = {
FF_RTP_FLAG_OPTS(RTPMuxContext, flags),
{ "payload_type", "Specify RTP payload type", offsetof(RTPMuxContext, payload_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 127, AV_OPT_FLAG_ENCODING_PARAM },
@@ -264,7 +262,7 @@ fail:
}
/* send an rtcp sender report packet */
-static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
+static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time, int bye)
{
RTPMuxContext *s = s1->priv_data;
uint32_t rtp_ts;
@@ -274,12 +272,11 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
s->last_rtcp_ntp_time = ntp_time;
rtp_ts = av_rescale_q(ntp_time - s->first_rtcp_ntp_time, (AVRational){1, 1000000},
s1->streams[0]->time_base) + s->base_timestamp;
- avio_w8(s1->pb, (RTP_VERSION << 6));
+ avio_w8(s1->pb, RTP_VERSION << 6);
avio_w8(s1->pb, RTCP_SR);
avio_wb16(s1->pb, 6); /* length in words - 1 */
avio_wb32(s1->pb, s->ssrc);
- avio_wb32(s1->pb, ntp_time / 1000000);
- avio_wb32(s1->pb, ((ntp_time % 1000000) << 32) / 1000000);
+ avio_wb64(s1->pb, NTP_TO_RTP_FORMAT(ntp_time));
avio_wb32(s1->pb, rtp_ts);
avio_wb32(s1->pb, s->packet_count);
avio_wb32(s1->pb, s->octet_count);
@@ -299,6 +296,13 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
avio_w8(s1->pb, 0);
}
+ if (bye) {
+ avio_w8(s1->pb, (RTP_VERSION << 6) | 1);
+ avio_w8(s1->pb, RTCP_BYE);
+ avio_wb16(s1->pb, 1); /* length in words - 1 */
+ avio_wb32(s1->pb, s->ssrc);
+ }
+
avio_flush(s1->pb);
}
@@ -311,7 +315,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
av_dlog(s1, "rtp_send_data size=%d\n", len);
/* build the RTP header */
- avio_w8(s1->pb, (RTP_VERSION << 6));
+ avio_w8(s1->pb, RTP_VERSION << 6);
avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7));
avio_wb16(s1->pb, s->seq);
avio_wb32(s1->pb, s->timestamp);
@@ -497,7 +501,7 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
if ((s->first_packet || ((rtcp_bytes >= RTCP_SR_SIZE) &&
(ff_ntp_time() - s->last_rtcp_ntp_time > 5000000))) &&
!(s->flags & FF_RTP_FLAG_SKIP_RTCP)) {
- rtcp_send_sr(s1, ff_ntp_time());
+ rtcp_send_sr(s1, ff_ntp_time(), 0);
s->last_octet_count = s->octet_count;
s->first_packet = 0;
}
@@ -553,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;
}
@@ -593,6 +601,10 @@ static int rtp_write_trailer(AVFormatContext *s1)
{
RTPMuxContext *s = s1->priv_data;
+ /* If the caller closes and recreates ->pb, this might actually
+ * be NULL here even if it was successfully allocated at the start. */
+ if (s1->pb && (s->flags & FF_RTP_FLAG_SEND_BYE))
+ rtcp_send_sr(s1, ff_ntp_time(), 1);
av_freep(&s->buf);
return 0;
diff --git a/ffmpeg/libavformat/rtpenc.h b/ffmpeg/libavformat/rtpenc.h
index 72a5fa4..913d05a 100644
--- a/ffmpeg/libavformat/rtpenc.h
+++ b/ffmpeg/libavformat/rtpenc.h
@@ -38,11 +38,9 @@ struct RTPMuxContext {
int max_payload_size;
int num_frames;
- /* rtcp sender statistics receive */
+ /* rtcp sender statistics */
int64_t last_rtcp_ntp_time;
int64_t first_rtcp_ntp_time;
-
- /* rtcp sender statistics */
unsigned int packet_count;
unsigned int octet_count;
unsigned int last_octet_count;
@@ -70,13 +68,15 @@ typedef struct RTPMuxContext RTPMuxContext;
#define FF_RTP_FLAG_RFC2190 2
#define FF_RTP_FLAG_SKIP_RTCP 4
#define FF_RTP_FLAG_H264_MODE0 8
+#define FF_RTP_FLAG_SEND_BYE 16
#define FF_RTP_FLAG_OPTS(ctx, fieldname) \
{ "rtpflags", "RTP muxer flags", offsetof(ctx, fieldname), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \
{ "latm", "Use MP4A-LATM packetization instead of MPEG4-GENERIC for AAC", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_MP4A_LATM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \
{ "rfc2190", "Use RFC 2190 packetization instead of RFC 4629 for H.263", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_RFC2190}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \
{ "skip_rtcp", "Don't send RTCP sender reports", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_SKIP_RTCP}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \
- { "h264_mode0", "Use mode 0 for H264 in RTP", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_H264_MODE0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" } \
+ { "h264_mode0", "Use mode 0 for H264 in RTP", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_H264_MODE0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \
+ { "send_bye", "Send RTCP BYE packets when finishing", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_SEND_BYE}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" } \
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m);
diff --git a/ffmpeg/libavformat/rtpenc_chain.c b/ffmpeg/libavformat/rtpenc_chain.c
index 70d68ce..dea1f70 100644
--- a/ffmpeg/libavformat/rtpenc_chain.c
+++ b/ffmpeg/libavformat/rtpenc_chain.c
@@ -22,7 +22,6 @@
#include "avformat.h"
#include "avio_internal.h"
#include "rtpenc_chain.h"
-#include "avio_internal.h"
#include "rtp.h"
#include "libavutil/opt.h"
@@ -78,16 +77,19 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s,
avcodec_copy_context(rtpctx->streams[0]->codec, st->codec);
if (handle) {
- ffio_fdopen(&rtpctx->pb, handle);
+ ret = ffio_fdopen(&rtpctx->pb, handle);
+ if (ret < 0)
+ ffurl_close(handle);
} else
- ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size);
- ret = avformat_write_header(rtpctx, &opts);
+ ret = ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size);
+ if (!ret)
+ ret = avformat_write_header(rtpctx, &opts);
av_dict_free(&opts);
if (ret) {
- if (handle) {
+ if (handle && rtpctx->pb) {
avio_close(rtpctx->pb);
- } else {
+ } else if (rtpctx->pb) {
uint8_t *ptr;
avio_close_dyn_buf(rtpctx->pb, &ptr);
av_free(ptr);
diff --git a/ffmpeg/libavformat/rtpenc_h263_rfc2190.c b/ffmpeg/libavformat/rtpenc_h263_rfc2190.c
index f714d01..0493008 100644
--- a/ffmpeg/libavformat/rtpenc_h263_rfc2190.c
+++ b/ffmpeg/libavformat/rtpenc_h263_rfc2190.c
@@ -2,20 +2,20 @@
* RTP packetization for H.263 video
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/rtpenc_latm.c b/ffmpeg/libavformat/rtpenc_latm.c
index 7535a0f..4430c44 100644
--- a/ffmpeg/libavformat/rtpenc_latm.c
+++ b/ffmpeg/libavformat/rtpenc_latm.c
@@ -9,13 +9,13 @@
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/ffmpeg/libavformat/rtpenc_mpv.c b/ffmpeg/libavformat/rtpenc_mpv.c
index 2708dd1..4b45f51 100644
--- a/ffmpeg/libavformat/rtpenc_mpv.c
+++ b/ffmpeg/libavformat/rtpenc_mpv.c
@@ -20,7 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavcodec/mpegvideo.h"
+#include "libavcodec/internal.h"
#include "avformat.h"
#include "rtpenc.h"
@@ -56,7 +56,7 @@ void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size)
r1 = buf1;
while (1) {
start_code = -1;
- r = avpriv_mpv_find_start_code(r1, end, &start_code);
+ r = avpriv_find_start_code(r1, end, &start_code);
if((start_code & 0xFFFFFF00) == 0x100) {
/* New start code found */
if (start_code == 0x100) {
diff --git a/ffmpeg/libavformat/rtpproto.c b/ffmpeg/libavformat/rtpproto.c
index 62ec4c9..a8cbd97 100644
--- a/ffmpeg/libavformat/rtpproto.c
+++ b/ffmpeg/libavformat/rtpproto.c
@@ -28,7 +28,8 @@
#include "libavutil/avstring.h"
#include "avformat.h"
#include "avio_internal.h"
-#include "rtpdec.h"
+#include "rtp.h"
+#include "rtpproto.h"
#include "url.h"
#include <stdarg.h>
@@ -42,7 +43,11 @@
typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
- int rtp_fd, rtcp_fd;
+ int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
+ struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
+ int write_to_source;
+ struct sockaddr_storage last_rtp_source, last_rtcp_source;
+ socklen_t last_rtp_source_len, last_rtcp_source_len;
} RTPContext;
/**
@@ -59,22 +64,109 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri)
{
RTPContext *s = h->priv_data;
char hostname[256];
- int port;
+ int port, rtcp_port;
+ const char *p;
char buf[1024];
char path[1024];
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
path, sizeof(path), uri);
+ rtcp_port = port + 1;
+
+ p = strchr(uri, '?');
+ if (p) {
+ if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
+ rtcp_port = strtol(buf, NULL, 10);
+ }
+ }
ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
ff_udp_set_remote_url(s->rtp_hd, buf);
- ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
+ ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path);
ff_udp_set_remote_url(s->rtcp_hd, buf);
return 0;
}
+static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
+ int type, int family, int flags)
+{
+ struct addrinfo hints = { 0 }, *res = 0;
+ int error;
+ char service[16];
+
+ snprintf(service, sizeof(service), "%d", port);
+ hints.ai_socktype = type;
+ hints.ai_family = family;
+ hints.ai_flags = flags;
+ if ((error = getaddrinfo(hostname, service, &hints, &res))) {
+ res = NULL;
+ av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
+ }
+
+ return res;
+}
+
+static int compare_addr(const struct sockaddr_storage *a,
+ const struct sockaddr_storage *b)
+{
+ if (a->ss_family != b->ss_family)
+ return 1;
+ if (a->ss_family == AF_INET) {
+ return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
+ ((const struct sockaddr_in *)b)->sin_addr.s_addr);
+ }
+
+#if HAVE_STRUCT_SOCKADDR_IN6
+ if (a->ss_family == AF_INET6) {
+ const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
+ const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
+ return memcmp(s6_addr_a, s6_addr_b, 16);
+ }
+#endif
+ return 1;
+}
+
+static int get_port(const struct sockaddr_storage *ss)
+{
+ if (ss->ss_family == AF_INET)
+ return ntohs(((const struct sockaddr_in *)ss)->sin_port);
+#if HAVE_STRUCT_SOCKADDR_IN6
+ if (ss->ss_family == AF_INET6)
+ return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port);
+#endif
+ return 0;
+}
+
+static void set_port(struct sockaddr_storage *ss, int port)
+{
+ if (ss->ss_family == AF_INET)
+ ((struct sockaddr_in *)ss)->sin_port = htons(port);
+#if HAVE_STRUCT_SOCKADDR_IN6
+ else if (ss->ss_family == AF_INET6)
+ ((struct sockaddr_in6 *)ss)->sin6_port = htons(port);
+#endif
+}
+
+static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr)
+{
+ int i;
+ if (s->nb_ssm_exclude_addrs) {
+ for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
+ if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i]))
+ return 1;
+ }
+ }
+ if (s->nb_ssm_include_addrs) {
+ for (i = 0; i < s->nb_ssm_include_addrs; i++) {
+ if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i]))
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
/**
* add option to url of the form:
@@ -99,7 +191,9 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const
static void build_udp_url(char *buf, int buf_size,
const char *hostname, int port,
int local_port, int ttl,
- int max_packet_size, int connect)
+ int max_packet_size, int connect,
+ const char *include_sources,
+ const char *exclude_sources)
{
ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
if (local_port >= 0)
@@ -111,6 +205,50 @@ static void build_udp_url(char *buf, int buf_size,
if (connect)
url_add_option(buf, buf_size, "connect=1");
url_add_option(buf, buf_size, "fifo_size=0");
+ if (include_sources && include_sources[0])
+ url_add_option(buf, buf_size, "sources=%s", include_sources);
+ if (exclude_sources && exclude_sources[0])
+ url_add_option(buf, buf_size, "block=%s", exclude_sources);
+}
+
+static void rtp_parse_addr_list(URLContext *h, char *buf,
+ struct sockaddr_storage ***address_list_ptr,
+ int *address_list_size_ptr)
+{
+ struct addrinfo *ai = NULL;
+ struct sockaddr_storage *source_addr;
+ char tmp = '\0', *p = buf, *next;
+
+ /* Resolve all of the IPs */
+
+ while (p && p[0]) {
+ next = strchr(p, ',');
+
+ if (next) {
+ tmp = *next;
+ *next = '\0';
+ }
+
+ ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0);
+ if (ai) {
+ source_addr = av_mallocz(sizeof(struct sockaddr_storage));
+ if (!source_addr)
+ break;
+
+ memcpy(source_addr, ai->ai_addr, ai->ai_addrlen);
+ freeaddrinfo(ai);
+ dynarray_add(address_list_ptr, address_list_size_ptr, source_addr);
+ } else {
+ av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p);
+ }
+
+ if (next) {
+ *next = tmp;
+ p = next + 1;
+ } else {
+ p = NULL;
+ }
+ }
}
/**
@@ -121,6 +259,9 @@ static void build_udp_url(char *buf, int buf_size,
* 'localrtcpport=n' : set the local rtcp port to n
* 'pkt_size=n' : set max packet size
* 'connect=0/1' : do a connect() on the UDP socket
+ * 'sources=ip[,ip]' : list allowed source IP addresses
+ * 'block=ip[,ip]' : list disallowed source IP addresses
+ * 'write_to_source=0/1' : send packets to the source address of the latest received packet
* deprecated option:
* 'localport=n' : set the local port to n
*
@@ -136,10 +277,11 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
int rtp_port, rtcp_port,
ttl, connect,
local_rtp_port, local_rtcp_port, max_packet_size;
- char hostname[256];
+ char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
char buf[1024];
char path[1024];
const char *p;
+ int i, max_retry_count = 3;
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
path, sizeof(path), uri);
@@ -174,21 +316,48 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
connect = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
+ s->write_to_source = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
+ av_strlcpy(include_sources, buf, sizeof(include_sources));
+ rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
+ av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
+ rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
+ }
}
- build_udp_url(buf, sizeof(buf),
- hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
- connect);
- if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
- goto fail;
- if (local_rtp_port>=0 && local_rtcp_port<0)
- local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
-
- build_udp_url(buf, sizeof(buf),
- hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
- connect);
- if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
- goto fail;
+ for (i = 0;i < max_retry_count;i++) {
+ build_udp_url(buf, sizeof(buf),
+ hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
+ goto fail;
+ local_rtp_port = ff_udp_get_local_port(s->rtp_hd);
+ if(local_rtp_port == 65535) {
+ local_rtp_port = -1;
+ continue;
+ }
+ if (local_rtcp_port<0) {
+ local_rtcp_port = local_rtp_port + 1;
+ build_udp_url(buf, sizeof(buf),
+ hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) {
+ local_rtp_port = local_rtcp_port = -1;
+ continue;
+ }
+ break;
+ }
+ build_udp_url(buf, sizeof(buf),
+ hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
+ connect, include_sources, exclude_sources);
+ if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
+ goto fail;
+ break;
+ }
/* just to ease handle access. XXX: need to suppress direct handle
access */
@@ -210,48 +379,41 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
static int rtp_read(URLContext *h, uint8_t *buf, int size)
{
RTPContext *s = h->priv_data;
- struct sockaddr_storage from;
- socklen_t from_len;
- int len, n;
+ int len, n, i;
struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
+ int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100;
+ struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source };
+ socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len };
for(;;) {
if (ff_check_interrupt(&h->interrupt_callback))
return AVERROR_EXIT;
- /* build fdset to listen to RTP and RTCP packets */
- n = poll(p, 2, 100);
+ n = poll(p, 2, poll_delay);
if (n > 0) {
- /* first try RTCP */
- if (p[1].revents & POLLIN) {
- from_len = sizeof(from);
- len = recvfrom (s->rtcp_fd, buf, size, 0,
- (struct sockaddr *)&from, &from_len);
+ /* first try RTCP, then RTP */
+ for (i = 1; i >= 0; i--) {
+ if (!(p[i].revents & POLLIN))
+ continue;
+ *addr_lens[i] = sizeof(*addrs[i]);
+ len = recvfrom(p[i].fd, buf, size, 0,
+ (struct sockaddr *)addrs[i], addr_lens[i]);
if (len < 0) {
if (ff_neterrno() == AVERROR(EAGAIN) ||
ff_neterrno() == AVERROR(EINTR))
continue;
return AVERROR(EIO);
}
- break;
- }
- /* then RTP */
- if (p[0].revents & POLLIN) {
- from_len = sizeof(from);
- len = recvfrom (s->rtp_fd, buf, size, 0,
- (struct sockaddr *)&from, &from_len);
- if (len < 0) {
- if (ff_neterrno() == AVERROR(EAGAIN) ||
- ff_neterrno() == AVERROR(EINTR))
- continue;
- return AVERROR(EIO);
- }
- break;
+ if (rtp_check_source_lists(s, addrs[i]))
+ continue;
+ return len;
}
} else if (n < 0) {
if (ff_neterrno() == AVERROR(EINTR))
continue;
return AVERROR(EIO);
}
+ if (h->flags & AVIO_FLAG_NONBLOCK)
+ return AVERROR(EAGAIN);
}
return len;
}
@@ -262,6 +424,60 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
int ret;
URLContext *hd;
+ if (size < 2)
+ return AVERROR(EINVAL);
+
+ if (s->write_to_source) {
+ int fd;
+ struct sockaddr_storage *source, temp_source;
+ socklen_t *source_len, temp_len;
+ if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) {
+ av_log(h, AV_LOG_ERROR,
+ "Unable to send packet to source, no packets received yet\n");
+ // Intentionally not returning an error here
+ return size;
+ }
+
+ if (RTP_PT_IS_RTCP(buf[1])) {
+ fd = s->rtcp_fd;
+ source = &s->last_rtcp_source;
+ source_len = &s->last_rtcp_source_len;
+ } else {
+ fd = s->rtp_fd;
+ source = &s->last_rtp_source;
+ source_len = &s->last_rtp_source_len;
+ }
+ if (!source->ss_family) {
+ source = &temp_source;
+ source_len = &temp_len;
+ if (RTP_PT_IS_RTCP(buf[1])) {
+ temp_source = s->last_rtp_source;
+ temp_len = s->last_rtp_source_len;
+ set_port(source, get_port(source) + 1);
+ av_log(h, AV_LOG_INFO,
+ "Not received any RTCP packets yet, inferring peer port "
+ "from the RTP port\n");
+ } else {
+ temp_source = s->last_rtcp_source;
+ temp_len = s->last_rtcp_source_len;
+ set_port(source, get_port(source) - 1);
+ av_log(h, AV_LOG_INFO,
+ "Not received any RTP packets yet, inferring peer port "
+ "from the RTCP port\n");
+ }
+ }
+
+ if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
+ ret = ff_network_wait_fd(fd, 1);
+ if (ret < 0)
+ return ret;
+ }
+ ret = sendto(fd, buf, size, 0, (struct sockaddr *) source,
+ *source_len);
+
+ return ret < 0 ? ff_neterrno() : ret;
+ }
+
if (RTP_PT_IS_RTCP(buf[1])) {
/* RTCP payload type */
hd = s->rtcp_hd;
@@ -277,6 +493,14 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
static int rtp_close(URLContext *h)
{
RTPContext *s = h->priv_data;
+ int i;
+
+ for (i = 0; i < s->nb_ssm_include_addrs; i++)
+ av_free(s->ssm_include_addrs[i]);
+ av_freep(&s->ssm_include_addrs);
+ for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
+ av_free(s->ssm_exclude_addrs[i]);
+ av_freep(&s->ssm_exclude_addrs);
ffurl_close(s->rtp_hd);
ffurl_close(s->rtcp_hd);
diff --git a/ffmpeg/libavformat/rtsp.c b/ffmpeg/libavformat/rtsp.c
index 317893c..9ee016c 100644
--- a/ffmpeg/libavformat/rtsp.c
+++ b/ffmpeg/libavformat/rtsp.c
@@ -42,6 +42,7 @@
#include "rtsp.h"
#include "rtpdec.h"
+#include "rtpproto.h"
#include "rdt.h"
#include "rtpdec_formats.h"
#include "rtpenc_chain.h"
@@ -49,8 +50,6 @@
#include "rtpenc.h"
#include "mpegts.h"
-//#define DEBUG
-
/* Timeout values for socket poll, in ms,
* and read_packet(), in seconds */
#define POLL_TIMEOUT_MS 100
@@ -66,8 +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" }, \
- { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 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" }, \
@@ -87,17 +85,21 @@ const AVOption ff_rtsp_options[] = {
{ "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_REORDERING_OPTS(),
+ { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
{ NULL },
};
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"),
RTSP_REORDERING_OPTS(),
{ NULL },
@@ -289,8 +291,27 @@ typedef struct SDPParseState {
struct sockaddr_storage default_ip;
int default_ttl;
int skip_media; ///< set if an unknown m= line occurs
+ int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
+ struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
+ int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
+ struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
} SDPParseState;
+static void copy_default_source_addrs(struct RTSPSource **addrs, int count,
+ struct RTSPSource ***dest, int *dest_count)
+{
+ RTSPSource *rtsp_src, *rtsp_src2;
+ int i;
+ for (i = 0; i < count; i++) {
+ rtsp_src = addrs[i];
+ rtsp_src2 = av_malloc(sizeof(*rtsp_src2));
+ if (!rtsp_src2)
+ continue;
+ memcpy(rtsp_src2, rtsp_src, sizeof(*rtsp_src));
+ dynarray_add(dest, dest_count, rtsp_src2);
+ }
+}
+
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int letter, const char *buf)
{
@@ -301,6 +322,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int payload_type, i;
AVStream *st;
RTSPStream *rtsp_st;
+ RTSPSource *rtsp_src;
struct sockaddr_storage sdp_ip;
int ttl;
@@ -369,6 +391,15 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
rtsp_st->sdp_ip = s1->default_ip;
rtsp_st->sdp_ttl = s1->default_ttl;
+ copy_default_source_addrs(s1->default_include_source_addrs,
+ s1->nb_default_include_source_addrs,
+ &rtsp_st->include_source_addrs,
+ &rtsp_st->nb_include_source_addrs);
+ copy_default_source_addrs(s1->default_exclude_source_addrs,
+ s1->nb_default_exclude_source_addrs,
+ &rtsp_st->exclude_source_addrs,
+ &rtsp_st->nb_exclude_source_addrs);
+
get_word(buf1, sizeof(buf1), &p); /* port */
rtsp_st->sdp_port = atoi(buf1);
@@ -498,6 +529,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
p += strspn(p, SPACE_CHARS);
if (av_strstart(p, "inline:", &p))
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
+ } else if (av_strstart(p, "source-filter:", &p)) {
+ int exclude = 0;
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "incl") && strcmp(buf1, "excl"))
+ return;
+ exclude = !strcmp(buf1, "excl");
+
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "IN") != 0)
+ return;
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
+ return;
+ // not checking that the destination address actually matches or is wildcard
+ get_word(buf1, sizeof(buf1), &p);
+
+ while (*p != '\0') {
+ rtsp_src = av_mallocz(sizeof(*rtsp_src));
+ if (!rtsp_src)
+ return;
+ get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p);
+ if (exclude) {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src);
+ }
+ } else {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src);
+ }
+ }
+ }
} else {
if (rt->server_type == RTSP_SERVER_WMS)
ff_wms_parse_sdp_a_line(s, p);
@@ -522,7 +590,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
{
RTSPState *rt = s->priv_data;
const char *p;
- int letter;
+ int letter, i;
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
* contain long SDP lines containing complete ASF Headers (several
* kB) or arrays of MDPR (RM stream descriptor) headers plus
@@ -559,13 +627,21 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
if (*p == '\n')
p++;
}
+
+ for (i = 0; i < s1->nb_default_include_source_addrs; i++)
+ av_free(s1->default_include_source_addrs[i]);
+ av_freep(&s1->default_include_source_addrs);
+ for (i = 0; i < s1->nb_default_exclude_source_addrs; i++)
+ av_free(s1->default_exclude_source_addrs[i]);
+ av_freep(&s1->default_exclude_source_addrs);
+
rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
if (!rt->p) return AVERROR(ENOMEM);
return 0;
}
#endif /* CONFIG_RTPDEC */
-void ff_rtsp_undo_setup(AVFormatContext *s)
+void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets)
{
RTSPState *rt = s->priv_data;
int i;
@@ -580,6 +656,8 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
av_write_trailer(rtpctx);
if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
uint8_t *ptr;
+ if (CONFIG_RTSP_MUXER && rtpctx->pb && send_packets)
+ ff_rtsp_tcp_write_packet(s, rtsp_st);
avio_close_dyn_buf(rtpctx->pb, &ptr);
av_free(ptr);
} else {
@@ -602,16 +680,23 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
void ff_rtsp_close_streams(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- int i;
+ int i, j;
RTSPStream *rtsp_st;
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
for (i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
rtsp_st->dynamic_handler->free(
rtsp_st->dynamic_protocol_context);
+ for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
+ av_free(rtsp_st->include_source_addrs[j]);
+ av_freep(&rtsp_st->include_source_addrs);
+ for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++)
+ av_free(rtsp_st->exclude_source_addrs[j]);
+ av_freep(&rtsp_st->exclude_source_addrs);
+
av_free(rtsp_st);
}
}
@@ -644,8 +729,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 */
@@ -1119,11 +1204,11 @@ start:
*
* @return zero if success, nonzero otherwise
*/
-static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
- const char *method, const char *url,
- const char *headers,
- const unsigned char *send_content,
- int send_content_length)
+static int rtsp_send_cmd_with_content_async(AVFormatContext *s,
+ const char *method, const char *url,
+ const char *headers,
+ const unsigned char *send_content,
+ int send_content_length)
{
RTSPState *rt = s->priv_data;
char buf[4096], *out_buf;
@@ -1136,6 +1221,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
if (headers)
av_strlcat(buf, headers, sizeof(buf));
av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq);
+ av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", rt->user_agent);
if (rt->session_id[0] != '\0' && (!headers ||
!strstr(headers, "\nIf-Match:"))) {
av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id);
@@ -1176,7 +1262,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
const char *url, const char *headers)
{
- return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
+ return rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
}
int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url,
@@ -1201,9 +1287,9 @@ int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
retry:
cur_auth_type = rt->auth_state.auth_type;
- if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header,
- send_content,
- send_content_length)))
+ if ((ret = rtsp_send_cmd_with_content_async(s, method, url, header,
+ send_content,
+ send_content_length)))
return ret;
if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0)
@@ -1398,18 +1484,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
case RTSP_LOWER_TRANSPORT_UDP: {
char url[1024], options[30] = "";
+ const char *peer = host;
if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC)
av_strlcpy(options, "?connect=1", sizeof(options));
/* Use source address if specified */
- if (reply->transports[0].source[0]) {
- ff_url_join(url, sizeof(url), "rtp", NULL,
- reply->transports[0].source,
- reply->transports[0].server_port_min, "%s", options);
- } else {
- ff_url_join(url, sizeof(url), "rtp", NULL, host,
- reply->transports[0].server_port_min, "%s", options);
- }
+ if (reply->transports[0].source[0])
+ peer = reply->transports[0].source;
+ ff_url_join(url, sizeof(url), "rtp", NULL, peer,
+ reply->transports[0].server_port_min, "%s", options);
if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) &&
ff_rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
err = AVERROR_INVALIDDATA;
@@ -1466,7 +1549,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
return 0;
fail:
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
return err;
}
@@ -1618,7 +1701,8 @@ redirect:
}
} else {
/* open the tcp connection */
- ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
+ ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
+ "?timeout=%d", rt->stimeout);
if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR(EIO);
@@ -2028,7 +2112,7 @@ static int sdp_probe(AVProbeData *p1)
while (p < p_end && *p != '\0') {
if (p + sizeof("c=IN IP") - 1 < p_end &&
av_strstart(p, "c=IN IP", NULL))
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
while (p < p_end - 1 && *p != '\n') p++;
if (++p >= p_end)
@@ -2039,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1)
return 0;
}
+static void append_source_addrs(char *buf, int size, const char *name,
+ int count, struct RTSPSource **addrs)
+{
+ int i;
+ if (!count)
+ return;
+ av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr);
+ for (i = 1; i < count; i++)
+ av_strlcatf(buf, size, ",%s", addrs[i]->addr);
+}
+
static int sdp_read_header(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
@@ -2079,9 +2174,17 @@ static int sdp_read_header(AVFormatContext *s)
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
ff_url_join(url, sizeof(url), "rtp", NULL,
namebuf, rtsp_st->sdp_port,
- "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
- rtsp_st->sdp_ttl,
- rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
+ "?localport=%d&ttl=%d&connect=%d&write_to_source=%d",
+ rtsp_st->sdp_port, rtsp_st->sdp_ttl,
+ rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0,
+ rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0);
+
+ append_source_addrs(url, sizeof(url), "sources",
+ rtsp_st->nb_include_source_addrs,
+ rtsp_st->include_source_addrs);
+ append_source_addrs(url, sizeof(url), "block",
+ rtsp_st->nb_exclude_source_addrs,
+ rtsp_st->exclude_source_addrs);
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR_INVALIDDATA;
@@ -2134,7 +2237,7 @@ static int rtp_probe(AVProbeData *p)
static int rtp_read_header(AVFormatContext *s)
{
- uint8_t recvbuf[1500];
+ uint8_t recvbuf[RTP_MAX_PACKET_LENGTH];
char host[500], sdp[500];
int ret, port;
URLContext* in = NULL;
diff --git a/ffmpeg/libavformat/rtsp.h b/ffmpeg/libavformat/rtsp.h
index 321cd7a..76c7f18 100644
--- a/ffmpeg/libavformat/rtsp.h
+++ b/ffmpeg/libavformat/rtsp.h
@@ -391,9 +391,19 @@ typedef struct RTSPState {
int initial_timeout;
/**
+ * timeout of socket i/o operations.
+ */
+ int stimeout;
+
+ /**
* Size of RTP packet reordering queue.
*/
int reordering_queue_size;
+
+ /**
+ * User-Agent string
+ */
+ char *user_agent;
} RTSPState;
#define RTSP_FLAG_FILTER_SRC 0x1 /**< Filter incoming UDP packets -
@@ -401,6 +411,12 @@ typedef struct RTSPState {
source address and port. */
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
#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. */
+
+typedef struct RTSPSource {
+ char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
+} RTSPSource;
/**
* Describe a single stream, as identified by a single m= line block in the
@@ -425,6 +441,10 @@ typedef struct RTSPStream {
//@{
int sdp_port; /**< port (from SDP content) */
struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */
+ int nb_include_source_addrs; /**< Number of source-specific multicast include source IP addresses (from SDP content) */
+ struct RTSPSource **include_source_addrs; /**< Source-specific multicast include source IP addresses (from SDP content) */
+ int nb_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP addresses (from SDP content) */
+ struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast exclude source IP addresses (from SDP content) */
int sdp_ttl; /**< IP Time-To-Live (from SDP content) */
int sdp_payload_type; /**< payload type */
//@}
@@ -578,6 +598,11 @@ int ff_rtsp_tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
uint8_t *buf, int buf_size);
/**
+ * Send buffered packets over TCP.
+ */
+int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st);
+
+/**
* Receive one packet from the RTSPStreams set up in the AVFormatContext
* (which should contain a RTSPState struct as priv_data).
*/
@@ -595,7 +620,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
* Undo the effect of ff_rtsp_make_setup_request, close the
* transport_priv and rtp_handle fields.
*/
-void ff_rtsp_undo_setup(AVFormatContext *s);
+void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets);
/**
* Open RTSP transport context.
diff --git a/ffmpeg/libavformat/rtspdec.c b/ffmpeg/libavformat/rtspdec.c
index da571a8..74a7bf6 100644
--- a/ffmpeg/libavformat/rtspdec.c
+++ b/ffmpeg/libavformat/rtspdec.c
@@ -29,6 +29,7 @@
#include "internal.h"
#include "network.h"
#include "os_support.h"
+#include "rtpproto.h"
#include "rtsp.h"
#include "rdt.h"
#include "url.h"
@@ -768,7 +769,7 @@ static int resetup_tcp(AVFormatContext *s)
av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0,
s->filename);
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP,
rt->real_challenge);
}
@@ -876,7 +877,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/ffmpeg/libavformat/rtspenc.c b/ffmpeg/libavformat/rtspenc.c
index bad6fbd..d76ae87 100644
--- a/ffmpeg/libavformat/rtspenc.c
+++ b/ffmpeg/libavformat/rtspenc.c
@@ -136,7 +136,7 @@ static int rtsp_write_header(AVFormatContext *s)
return 0;
}
-static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
+int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
{
RTSPState *rt = s->priv_data;
AVFormatContext *rtpctx = rtsp_st->transport_priv;
@@ -145,6 +145,7 @@ static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
uint8_t *interleave_header, *interleaved_packet;
size = avio_close_dyn_buf(rtpctx->pb, &buf);
+ rtpctx->pb = NULL;
ptr = buf;
while (size > 4) {
uint32_t packet_len = AV_RB32(ptr);
@@ -171,8 +172,7 @@ static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
size -= packet_len;
}
av_free(buf);
- ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE);
- return 0;
+ return ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE);
}
static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)
@@ -217,7 +217,7 @@ static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)
* packets, so we need to send them out on the TCP connection separately.
*/
if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP)
- ret = tcp_write_packet(s, rtsp_st);
+ ret = ff_rtsp_tcp_write_packet(s, rtsp_st);
return ret;
}
@@ -225,6 +225,11 @@ static int rtsp_write_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
+ // If we want to send RTCP_BYE packets, these are sent by av_write_trailer.
+ // Thus call this on all streams before doing the teardown. This is
+ // done within ff_rtsp_undo_setup.
+ ff_rtsp_undo_setup(s, 1);
+
ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
ff_rtsp_close_streams(s);
diff --git a/ffmpeg/libavformat/sapdec.c b/ffmpeg/libavformat/sapdec.c
index ed3e857..fe7bd82 100644
--- a/ffmpeg/libavformat/sapdec.c
+++ b/ffmpeg/libavformat/sapdec.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "avio_internal.h"
#include "url.h"
+#include "rtpdec.h"
#if HAVE_POLL_H
#include <poll.h>
#endif
@@ -63,7 +64,7 @@ static int sap_read_header(AVFormatContext *s)
{
struct SAPState *sap = s->priv_data;
char host[1024], path[1024], url[1024];
- uint8_t recvbuf[1500];
+ uint8_t recvbuf[RTP_MAX_PACKET_LENGTH];
int port;
int ret, i;
AVInputFormat* infmt;
@@ -186,7 +187,7 @@ static int sap_fetch_packet(AVFormatContext *s, AVPacket *pkt)
int fd = ffurl_get_file_handle(sap->ann_fd);
int n, ret;
struct pollfd p = {fd, POLLIN, 0};
- uint8_t recvbuf[1500];
+ uint8_t recvbuf[RTP_MAX_PACKET_LENGTH];
if (sap->eof)
return AVERROR_EOF;
diff --git a/ffmpeg/libavformat/sapenc.c b/ffmpeg/libavformat/sapenc.c
index 6b1cd18..9fc78a8 100644
--- a/ffmpeg/libavformat/sapenc.c
+++ b/ffmpeg/libavformat/sapenc.c
@@ -26,7 +26,6 @@
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/time.h"
-#include "libavutil/dict.h"
#include "internal.h"
#include "network.h"
#include "os_support.h"
diff --git a/ffmpeg/libavformat/sbgdec.c b/ffmpeg/libavformat/sbgdec.c
index 30c3b49..36cd8a3 100644
--- a/ffmpeg/libavformat/sbgdec.c
+++ b/ffmpeg/libavformat/sbgdec.c
@@ -1333,11 +1333,9 @@ static int encode_intervals(struct sbg_script *s, AVCodecContext *avc,
if (edata_size < 0)
return AVERROR(ENOMEM);
}
- edata = av_malloc(edata_size);
- if (!edata)
+ if (ff_alloc_extradata(avc, edata_size))
return AVERROR(ENOMEM);
- avc->extradata = edata;
- avc->extradata_size = edata_size;
+ edata = avc->extradata;
#define ADD_EDATA32(v) do { AV_WL32(edata, (v)); edata += 4; } while(0)
#define ADD_EDATA64(v) do { AV_WL64(edata, (v)); edata += 8; } while(0)
diff --git a/ffmpeg/libavformat/sctp.c b/ffmpeg/libavformat/sctp.c
index 2fd5400..f88cd27 100644
--- a/ffmpeg/libavformat/sctp.c
+++ b/ffmpeg/libavformat/sctp.c
@@ -2,20 +2,20 @@
* SCTP protocol
* Copyright (c) 2012 Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,10 +56,10 @@
/*
* The sctp_recvmsg and sctp_sendmsg functions are part of the user
- * library that offers support
- * for the SCTP kernel Implementation. The main purpose of this
- * code is to provide the SCTP Socket API mappings for user
- * application to interface with the SCTP in kernel.
+ * library that offers support for the SCTP kernel Implementation.
+ * To avoid build-time clashes the functions sport an ff_-prefix here.
+ * The main purpose of this code is to provide the SCTP Socket API
+ * mappings for user applications to interface with SCTP in the kernel.
*
* This implementation is based on the Socket API Extensions for SCTP
* defined in <draft-ietf-tsvwg-sctpsocket-10.txt>
@@ -198,7 +198,7 @@ static int sctp_open(URLContext *h, const char *uri, int flags)
cur_ai = ai;
- fd = socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP);
+ fd = ff_socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP);
if (fd < 0)
goto fail;
diff --git a/ffmpeg/libavformat/sdp.c b/ffmpeg/libavformat/sdp.c
index 0124218..55ea0d9 100644
--- a/ffmpeg/libavformat/sdp.c
+++ b/ffmpeg/libavformat/sdp.c
@@ -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/ffmpeg/libavformat/seek-test.c b/ffmpeg/libavformat/seek-test.c
index 34ac4de..8b0611d 100644
--- a/ffmpeg/libavformat/seek-test.c
+++ b/ffmpeg/libavformat/seek-test.c
@@ -64,6 +64,7 @@ int main(int argc, char **argv)
int64_t seekfirst = AV_NOPTS_VALUE;
int firstback=0;
int frame_count = 1;
+ int duration = 4;
for(i=2; i<argc; i+=2){
if (!strcmp(argv[i], "-seekforw")){
@@ -73,6 +74,8 @@ int main(int argc, char **argv)
firstback = 1;
} else if(!strcmp(argv[i], "-frames")){
frame_count = atoi(argv[i+1]);
+ } else if(!strcmp(argv[i], "-duration")){
+ duration = atoi(argv[i+1]);
} else {
argc = 1;
}
@@ -133,7 +136,7 @@ int main(int argc, char **argv)
if(i>25) break;
stream_id= (i>>1)%(ic->nb_streams+1) - 1;
- timestamp= (i*19362894167LL) % (4*AV_TIME_BASE) - AV_TIME_BASE;
+ timestamp= (i*19362894167LL) % (duration*AV_TIME_BASE) - AV_TIME_BASE;
if(stream_id>=0){
st= ic->streams[stream_id];
timestamp= av_rescale_q(timestamp, AV_TIME_BASE_Q, st->time_base);
diff --git a/ffmpeg/libavformat/seek.c b/ffmpeg/libavformat/seek.c
index 0ae99eb..bb5ca87 100644
--- a/ffmpeg/libavformat/seek.c
+++ b/ffmpeg/libavformat/seek.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "seek.h"
#include "libavutil/mathematics.h"
#include "libavutil/mem.h"
@@ -428,13 +430,11 @@ AVParserState *ff_store_parser_state(AVFormatContext *s)
ss->parser = st->parser;
ss->last_IP_pts = st->last_IP_pts;
ss->cur_dts = st->cur_dts;
- ss->reference_dts = st->reference_dts;
ss->probe_packets = st->probe_packets;
st->parser = NULL;
st->last_IP_pts = AV_NOPTS_VALUE;
st->cur_dts = AV_NOPTS_VALUE;
- st->reference_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
}
@@ -467,7 +467,6 @@ void ff_restore_parser_state(AVFormatContext *s, AVParserState *state)
st->parser = ss->parser;
st->last_IP_pts = ss->last_IP_pts;
st->cur_dts = ss->cur_dts;
- st->reference_dts = ss->reference_dts;
st->probe_packets = ss->probe_packets;
}
diff --git a/ffmpeg/libavformat/seek.h b/ffmpeg/libavformat/seek.h
index b27cb42..3fa7ae3 100644
--- a/ffmpeg/libavformat/seek.h
+++ b/ffmpeg/libavformat/seek.h
@@ -33,7 +33,6 @@ typedef struct AVParserStreamState {
AVCodecParserContext *parser;
int64_t last_IP_pts;
int64_t cur_dts;
- int64_t reference_dts;
int probe_packets;
} AVParserStreamState;
diff --git a/ffmpeg/libavformat/segafilm.c b/ffmpeg/libavformat/segafilm.c
index a33ad85..8a0e8bc 100644
--- a/ffmpeg/libavformat/segafilm.c
+++ b/ffmpeg/libavformat/segafilm.c
@@ -62,10 +62,6 @@ typedef struct FilmDemuxContext {
unsigned int base_clock;
unsigned int version;
-
- /* buffer used for interleaving stereo PCM data */
- unsigned char *stereo_buffer;
- int stereo_buffer_size;
} FilmDemuxContext;
static int film_probe(AVProbeData *p)
@@ -73,6 +69,9 @@ static int film_probe(AVProbeData *p)
if (AV_RB32(&p->buf[0]) != FILM_TAG)
return 0;
+ if (AV_RB32(&p->buf[16]) != FDSC_TAG)
+ return 0;
+
return AVPROBE_SCORE_MAX;
}
@@ -87,8 +86,6 @@ static int film_read_header(AVFormatContext *s)
unsigned int audio_frame_counter;
film->sample_table = NULL;
- film->stereo_buffer = NULL;
- film->stereo_buffer_size = 0;
/* load the main FILM header */
if (avio_read(pb, scratch, 16) != 16)
@@ -117,9 +114,9 @@ static int film_read_header(AVFormatContext *s)
film->audio_type = AV_CODEC_ID_ADPCM_ADX;
else if (film->audio_channels > 0) {
if (film->audio_bits == 8)
- film->audio_type = AV_CODEC_ID_PCM_S8;
+ film->audio_type = AV_CODEC_ID_PCM_S8_PLANAR;
else if (film->audio_bits == 16)
- film->audio_type = AV_CODEC_ID_PCM_S16BE;
+ film->audio_type = AV_CODEC_ID_PCM_S16BE_PLANAR;
else
film->audio_type = AV_CODEC_ID_NONE;
} else
@@ -209,12 +206,14 @@ 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_free(film->sample_table);
+ av_freep(&film->sample_table);
return AVERROR(EIO);
}
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 (AV_RB32(&scratch[8]) == 0xFFFFFFFF) {
film->sample_table[i].stream = film->audio_stream_index;
film->sample_table[i].pts = audio_frame_counter;
@@ -244,8 +243,6 @@ static int film_read_packet(AVFormatContext *s,
AVIOContext *pb = s->pb;
film_sample *sample;
int ret = 0;
- int i;
- int left, right;
if (film->current_sample >= film->sample_count)
return AVERROR_EOF;
@@ -262,45 +259,6 @@ static int film_read_packet(AVFormatContext *s,
if (av_new_packet(pkt, sample->sample_size))
return AVERROR(ENOMEM);
avio_read(pb, pkt->data, sample->sample_size);
- } else if ((sample->stream == film->audio_stream_index) &&
- (film->audio_channels == 2) &&
- (film->audio_type != AV_CODEC_ID_ADPCM_ADX)) {
- /* stereo PCM needs to be interleaved */
-
- if (ffio_limit(pb, sample->sample_size) != sample->sample_size)
- return AVERROR(EIO);
- if (av_new_packet(pkt, sample->sample_size))
- return AVERROR(ENOMEM);
-
- /* make sure the interleave buffer is large enough */
- if (sample->sample_size > film->stereo_buffer_size) {
- av_free(film->stereo_buffer);
- film->stereo_buffer_size = sample->sample_size;
- film->stereo_buffer = av_malloc(film->stereo_buffer_size);
- if (!film->stereo_buffer) {
- film->stereo_buffer_size = 0;
- return AVERROR(ENOMEM);
- }
- }
-
- pkt->pos= avio_tell(pb);
- ret = avio_read(pb, film->stereo_buffer, sample->sample_size);
- if (ret != sample->sample_size)
- ret = AVERROR(EIO);
-
- left = 0;
- right = sample->sample_size / 2;
- for (i = 0; i + 1 + 2*(film->audio_bits != 8) < sample->sample_size; ) {
- if (film->audio_bits == 8) {
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[right++];
- } else {
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[right++];
- pkt->data[i++] = film->stereo_buffer[right++];
- }
- }
} else {
ret= av_get_packet(pb, pkt, sample->sample_size);
if (ret != sample->sample_size)
@@ -319,8 +277,7 @@ static int film_read_close(AVFormatContext *s)
{
FilmDemuxContext *film = s->priv_data;
- av_free(film->sample_table);
- av_free(film->stereo_buffer);
+ av_freep(&film->sample_table);
return 0;
}
diff --git a/ffmpeg/libavformat/segment.c b/ffmpeg/libavformat/segment.c
index dbcfe89..91c1432 100644
--- a/ffmpeg/libavformat/segment.c
+++ b/ffmpeg/libavformat/segment.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011, Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,7 +43,8 @@ typedef struct SegmentListEntry {
int index;
double start_time, end_time;
int64_t start_pts;
- char filename[1024];
+ int64_t offset_pts;
+ char *filename;
struct SegmentListEntry *next;
} SegmentListEntry;
@@ -71,6 +72,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
ListType list_type; ///< set the list type
AVIOContext *list_pb; ///< list file put-byte context
char *time_str; ///< segment duration specification string
@@ -85,12 +87,12 @@ typedef struct {
int nb_frames; ///< number of elments in the frames array
int frame_count;
- char *time_delta_str; ///< approximation value duration used for the segment times
int64_t time_delta;
int individual_header_trailer; /**< Set by a private option. */
int write_header_trailer; /**< Set by a private option. */
int reset_timestamps; ///< reset timestamps at the begin of each segment
+ int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds
char *reference_stream_specifier; ///< reference stream specifier
int reference_stream_index;
@@ -157,6 +159,7 @@ static int set_segment_filename(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc = seg->avf;
+ size_t size;
if (seg->segment_idx_wrap)
seg->segment_idx %= seg->segment_idx_wrap;
@@ -165,7 +168,19 @@ static int set_segment_filename(AVFormatContext *s)
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename);
return AVERROR(EINVAL);
}
- av_strlcpy(seg->cur_entry.filename, oc->filename, sizeof(seg->cur_entry.filename));
+
+ /* copy modified name in list entry */
+ size = strlen(av_basename(oc->filename)) + 1;
+ if (seg->list_entry_prefix)
+ size += strlen(seg->list_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 : "",
+ av_basename(oc->filename));
+
return 0;
}
@@ -186,11 +201,12 @@ static int segment_start(AVFormatContext *s, int write_header)
seg->segment_idx++;
if ((err = set_segment_filename(s)) < 0)
return err;
- seg->segment_count++;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
+ &s->interrupt_callback, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
return err;
+ }
if (oc->oformat->priv_class && oc->priv_data)
av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */
@@ -211,8 +227,10 @@ static int segment_list_open(AVFormatContext *s)
ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL);
- if (ret < 0)
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list);
return ret;
+ }
if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) {
SegmentListEntry *entry;
@@ -303,6 +321,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
if (seg->list_size && seg->segment_count > seg->list_size) {
entry = seg->segment_list_entries;
seg->segment_list_entries = seg->segment_list_entries->next;
+ av_free(entry->filename);
av_freep(&entry);
}
@@ -319,6 +338,10 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
avio_flush(seg->list_pb);
}
+ av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n",
+ seg->avf->filename, seg->segment_count);
+ seg->segment_count++;
+
end:
avio_close(oc->pb);
@@ -554,15 +577,6 @@ static int seg_write_header(AVFormatContext *s)
}
}
- if (seg->time_delta_str) {
- if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) {
- av_log(s, AV_LOG_ERROR,
- "Invalid time duration specification '%s' for delta option\n",
- seg->time_delta_str);
- return ret;
- }
- }
-
if (seg->list) {
if (seg->list_type == LIST_TYPE_UNDEFINED) {
if (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV;
@@ -602,12 +616,13 @@ static int seg_write_header(AVFormatContext *s)
if ((ret = set_segment_filename(s)) < 0)
goto fail;
- seg->segment_count++;
if (seg->write_header_trailer) {
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
+ &s->interrupt_callback, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
goto fail;
+ }
} else {
if ((ret = open_null_ctx(&oc->pb)) < 0)
goto fail;
@@ -644,18 +659,18 @@ 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;
+ int64_t end_pts = INT64_MAX, offset;
int start_frame = INT_MAX;
int ret;
if (seg->times) {
- end_pts = seg->segment_count <= seg->nb_times ?
- seg->times[seg->segment_count-1] : INT64_MAX;
+ end_pts = seg->segment_count < seg->nb_times ?
+ seg->times[seg->segment_count] : INT64_MAX;
} else if (seg->frames) {
start_frame = seg->segment_count <= seg->nb_frames ?
- seg->frames[seg->segment_count-1] : INT_MAX;
+ seg->frames[seg->segment_count] : INT_MAX;
} else {
- end_pts = seg->time * seg->segment_count;
+ end_pts = seg->time * (seg->segment_count+1);
}
av_dlog(s, "packet stream:%d pts:%s pts_time:%s is_key:%d frame:%d\n",
@@ -669,12 +684,10 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
(pkt->pts != AV_NOPTS_VALUE &&
av_compare_ts(pkt->pts, st->time_base,
end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
- ret = segment_end(s, seg->individual_header_trailer, 0);
-
- if (!ret)
- ret = segment_start(s, seg->individual_header_trailer);
+ if ((ret = segment_end(s, seg->individual_header_trailer, 0)) < 0)
+ goto fail;
- if (ret)
+ if ((ret = segment_start(s, seg->individual_header_trailer)) < 0)
goto fail;
oc = seg->avf;
@@ -688,29 +701,29 @@ 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;
}
- if (seg->reset_timestamps) {
- av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s",
- pkt->stream_index,
- av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q),
- av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
- av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
+ av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s",
+ pkt->stream_index,
+ av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
- /* compute new timestamps */
- if (pkt->pts != AV_NOPTS_VALUE)
- pkt->pts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base);
- if (pkt->dts != AV_NOPTS_VALUE)
- pkt->dts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base);
+ /* compute new timestamps */
+ offset = av_rescale_q(seg->initial_offset - (seg->reset_timestamps ? seg->cur_entry.start_pts : 0),
+ AV_TIME_BASE_Q, st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
- av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
- av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
- av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
- }
+ av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
@@ -754,6 +767,7 @@ fail:
cur = seg->segment_list_entries;
while (cur) {
next = cur->next;
+ av_free(cur->filename);
av_free(cur);
cur = next;
}
@@ -774,6 +788,7 @@ 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" },
@@ -784,7 +799,7 @@ static const AVOption options[] = {
{ "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
{ "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
- { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
+ { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E },
{ "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 },
@@ -793,6 +808,7 @@ static const AVOption options[] = {
{ "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 },
{ "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
+ { "initial_offset", "set initial timestamp offset", OFFSET(initial_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E },
{ NULL },
};
diff --git a/ffmpeg/libavformat/sierravmd.c b/ffmpeg/libavformat/sierravmd.c
index b0b582d..9bd42b4 100644
--- a/ffmpeg/libavformat/sierravmd.c
+++ b/ffmpeg/libavformat/sierravmd.c
@@ -64,8 +64,8 @@ typedef struct VmdDemuxContext {
static int vmd_probe(AVProbeData *p)
{
- int w, h;
- if (p->buf_size < 16)
+ int w, h, sample_rate;
+ if (p->buf_size < 806)
return 0;
/* check if the first 2 bytes of the file contain the appropriate size
* of a VMD header chunk */
@@ -73,23 +73,26 @@ static int vmd_probe(AVProbeData *p)
return 0;
w = AV_RL16(&p->buf[12]);
h = AV_RL16(&p->buf[14]);
- if (!w || w > 2048 || !h || h > 2048)
+ sample_rate = AV_RL16(&p->buf[804]);
+ if ((!w || w > 2048 || !h || h > 2048) &&
+ sample_rate != 22050)
return 0;
/* only return half certainty since this check is a bit sketchy */
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int vmd_read_header(AVFormatContext *s)
{
VmdDemuxContext *vmd = s->priv_data;
AVIOContext *pb = s->pb;
- AVStream *st = NULL, *vst;
+ AVStream *st = NULL, *vst = NULL;
unsigned int toc_offset;
unsigned char *raw_frame_table;
int raw_frame_table_size;
int64_t current_offset;
- int i, j;
+ int i, j, ret;
+ int width, height;
unsigned int total_frames;
int64_t current_audio_pts = 0;
unsigned char chunk[BYTES_PER_FRAME_RECORD];
@@ -101,28 +104,33 @@ static int vmd_read_header(AVFormatContext *s)
if (avio_read(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
return AVERROR(EIO);
- if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3')
- vmd->is_indeo3 = 1;
- else
- vmd->is_indeo3 = 0;
- /* start up the decoders */
- vst = avformat_new_stream(s, NULL);
- if (!vst)
- return AVERROR(ENOMEM);
- avpriv_set_pts_info(vst, 33, 1, 10);
- vmd->video_stream_index = vst->index;
- vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO;
- vst->codec->codec_tag = 0; /* no fourcc */
- vst->codec->width = AV_RL16(&vmd->vmd_header[12]);
- vst->codec->height = AV_RL16(&vmd->vmd_header[14]);
- if(vmd->is_indeo3 && vst->codec->width > 320){
- vst->codec->width >>= 1;
- vst->codec->height >>= 1;
+ width = AV_RL16(&vmd->vmd_header[12]);
+ height = AV_RL16(&vmd->vmd_header[14]);
+ if (width && height) {
+ if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3') {
+ vmd->is_indeo3 = 1;
+ } else {
+ vmd->is_indeo3 = 0;
+ }
+ /* start up the decoders */
+ vst = avformat_new_stream(s, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(vst, 33, 1, 10);
+ vmd->video_stream_index = vst->index;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO;
+ vst->codec->codec_tag = 0; /* no fourcc */
+ vst->codec->width = width;
+ vst->codec->height = height;
+ if(vmd->is_indeo3 && vst->codec->width > 320){
+ vst->codec->width >>= 1;
+ vst->codec->height >>= 1;
+ }
+ if (ff_alloc_extradata(vst->codec, VMD_HEADER_SIZE))
+ return AVERROR(ENOMEM);
+ memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE);
}
- vst->codec->extradata_size = VMD_HEADER_SIZE;
- vst->codec->extradata = av_mallocz(VMD_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE);
/* if sample rate is 0, assume no audio */
vmd->sample_rate = AV_RL16(&vmd->vmd_header[804]);
@@ -156,7 +164,8 @@ static int vmd_read_header(AVFormatContext *s)
num = st->codec->block_align;
den = st->codec->sample_rate * st->codec->channels;
av_reduce(&num, &den, num, den, (1UL<<31)-1);
- avpriv_set_pts_info(vst, 33, num, den);
+ if (vst)
+ avpriv_set_pts_info(vst, 33, num, den);
avpriv_set_pts_info(st, 33, num, den);
}
@@ -176,15 +185,13 @@ static int vmd_read_header(AVFormatContext *s)
raw_frame_table = av_malloc(raw_frame_table_size);
vmd->frame_table = av_malloc((vmd->frame_count * vmd->frames_per_block + sound_buffers) * sizeof(vmd_frame));
if (!raw_frame_table || !vmd->frame_table) {
- av_free(raw_frame_table);
- av_free(vmd->frame_table);
- return AVERROR(ENOMEM);
+ ret = AVERROR(ENOMEM);
+ goto error;
}
if (avio_read(pb, raw_frame_table, raw_frame_table_size) !=
raw_frame_table_size) {
- av_free(raw_frame_table);
- av_free(vmd->frame_table);
- return AVERROR(EIO);
+ ret = AVERROR(EIO);
+ goto error;
}
total_frames = 0;
@@ -197,9 +204,19 @@ 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) {
+ av_log(s, AV_LOG_ERROR, "Invalid frame size\n");
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
if(!size && type != 1)
continue;
switch(type) {
@@ -236,6 +253,11 @@ static int vmd_read_header(AVFormatContext *s)
vmd->frame_count = total_frames;
return 0;
+
+error:
+ av_freep(&raw_frame_table);
+ av_freep(&vmd->frame_table);
+ return ret;
}
static int vmd_read_packet(AVFormatContext *s,
@@ -285,7 +307,7 @@ static int vmd_read_close(AVFormatContext *s)
{
VmdDemuxContext *vmd = s->priv_data;
- av_free(vmd->frame_table);
+ av_freep(&vmd->frame_table);
return 0;
}
diff --git a/ffmpeg/libavformat/smacker.c b/ffmpeg/libavformat/smacker.c
index 883a2b7..0d38588 100644
--- a/ffmpeg/libavformat/smacker.c
+++ b/ffmpeg/libavformat/smacker.c
@@ -92,11 +92,14 @@ static const uint8_t smk_pal[64] = {
static int smacker_probe(AVProbeData *p)
{
- if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K'
- && (p->buf[3] == '2' || p->buf[3] == '4'))
- return AVPROBE_SCORE_MAX;
- else
+ if ( AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2')
+ && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4'))
return 0;
+
+ if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U)
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static int smacker_read_header(AVFormatContext *s)
@@ -142,8 +145,13 @@ static int smacker_read_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames);
return AVERROR_INVALIDDATA;
}
- smk->frm_size = av_malloc(smk->frames * 4);
+ smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size));
smk->frm_flags = av_malloc(smk->frames);
+ if (!smk->frm_size || !smk->frm_flags) {
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
+ return AVERROR(ENOMEM);
+ }
smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2'));
@@ -180,6 +188,8 @@ static int smacker_read_header(AVFormatContext *s)
smk->indexes[i] = -1;
if (smk->rates[i]) {
ast[i] = avformat_new_stream(s, NULL);
+ if (!ast[i])
+ return AVERROR(ENOMEM);
smk->indexes[i] = ast[i]->index;
ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO;
if (smk->aflags[i] & SMK_AUD_BINKAUD) {
@@ -210,18 +220,16 @@ static int smacker_read_header(AVFormatContext *s)
/* load trees to extradata, they will be unpacked by decoder */
- st->codec->extradata = av_malloc(smk->treesize + 16 + FF_INPUT_BUFFER_PADDING_SIZE);
- st->codec->extradata_size = smk->treesize + 16;
- if(!st->codec->extradata){
+ 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_free(smk->frm_size);
- av_free(smk->frm_flags);
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
return AVERROR(ENOMEM);
}
ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
if(ret != st->codec->extradata_size - 16){
- av_free(smk->frm_size);
- av_free(smk->frm_flags);
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
return AVERROR(EIO);
}
((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size);
@@ -276,7 +284,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
} else if(t & 0x40){ /* copy with offset */
off = avio_r8(s->pb);
j = (t & 0x3F) + 1;
- if (off + j > 0xff) {
+ if (off + j > 0x100) {
av_log(s, AV_LOG_ERROR,
"Invalid palette update, offset=%d length=%d extends beyond palette size\n",
off, j);
@@ -305,19 +313,21 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
/* if audio chunks are present, put them to stack and retrieve later */
for(i = 0; i < 7; i++) {
if(flags & 1) {
- unsigned int size;
- uint8_t *tmpbuf;
+ uint32_t size;
+ int err;
size = avio_rl32(s->pb) - 4;
- if(size + 4L > frame_size)
+ if (!size || size + 4L > frame_size) {
+ av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
return AVERROR_INVALIDDATA;
+ }
frame_size -= size;
frame_size -= 4;
smk->curstream++;
- tmpbuf = av_realloc(smk->bufs[smk->curstream], size);
- if (!tmpbuf)
- return AVERROR(ENOMEM);
- smk->bufs[smk->curstream] = tmpbuf;
+ if ((err = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) {
+ smk->buf_sizes[smk->curstream] = 0;
+ return err;
+ }
smk->buf_sizes[smk->curstream] = size;
ret = avio_read(s->pb, smk->bufs[smk->curstream], size);
if(ret != size)
@@ -326,7 +336,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
}
flags >>= 1;
}
- if (frame_size < 0)
+ if (frame_size < 0 || frame_size >= INT_MAX/2)
return AVERROR_INVALIDDATA;
if (av_new_packet(pkt, frame_size + 769))
return AVERROR(ENOMEM);
@@ -338,10 +348,13 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
if(ret != frame_size)
return AVERROR(EIO);
pkt->stream_index = smk->videoindex;
+ pkt->pts = smk->cur_frame;
pkt->size = ret + 769;
smk->cur_frame++;
smk->nextpos = avio_tell(s->pb);
} else {
+ if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream])
+ return AVERROR_INVALIDDATA;
if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
return AVERROR(ENOMEM);
memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
@@ -361,9 +374,9 @@ static int smacker_read_close(AVFormatContext *s)
int i;
for(i = 0; i < 7; i++)
- av_free(smk->bufs[i]);
- av_free(smk->frm_size);
- av_free(smk->frm_flags);
+ av_freep(&smk->bufs[i]);
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
return 0;
}
diff --git a/ffmpeg/libavformat/smjpegenc.c b/ffmpeg/libavformat/smjpegenc.c
index 0a27687..430a497 100644
--- a/ffmpeg/libavformat/smjpegenc.c
+++ b/ffmpeg/libavformat/smjpegenc.c
@@ -109,7 +109,6 @@ static int smjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wb32(pb, pkt->pts);
avio_wb32(pb, pkt->size);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
smc->duration = FFMAX(smc->duration, pkt->pts + pkt->duration);
return 0;
diff --git a/ffmpeg/libavformat/smoothstreamingenc.c b/ffmpeg/libavformat/smoothstreamingenc.c
index 096bf79..fe18a95 100644
--- a/ffmpeg/libavformat/smoothstreamingenc.c
+++ b/ffmpeg/libavformat/smoothstreamingenc.c
@@ -210,14 +210,15 @@ static int write_manifest(AVFormatContext *s, int final)
{
SmoothStreamingContext *c = s->priv_data;
AVIOContext *out;
- char filename[1024];
+ char filename[1024], temp_filename[1024];
int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0;
int64_t duration = 0;
snprintf(filename, sizeof(filename), "%s/Manifest", s->filename);
- ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
+ snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->filename);
+ ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
if (ret < 0) {
- av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", filename);
+ av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
return ret;
}
avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
@@ -278,6 +279,7 @@ static int write_manifest(AVFormatContext *s, int final)
avio_printf(out, "</SmoothStreamingMedia>\n");
avio_flush(out);
avio_close(out);
+ rename(temp_filename, filename);
return 0;
}
@@ -428,7 +430,7 @@ static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *sta
if (len < 8 || len >= *moof_size)
goto fail;
if (tag == MKTAG('u','u','i','d')) {
- const uint8_t tfxd[] = {
+ static const uint8_t tfxd[] = {
0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
};
@@ -451,12 +453,16 @@ fail:
static int add_fragment(OutputStream *os, const char *file, const char *infofile, int64_t start_time, int64_t duration, int64_t start_pos, int64_t size)
{
+ int err;
Fragment *frag;
if (os->nb_fragments >= os->fragments_size) {
os->fragments_size = (os->fragments_size + 1) * 2;
- os->fragments = av_realloc(os->fragments, sizeof(*os->fragments)*os->fragments_size);
- if (!os->fragments)
- return AVERROR(ENOMEM);
+ if ((err = av_reallocp(&os->fragments, sizeof(*os->fragments) *
+ os->fragments_size)) < 0) {
+ os->fragments_size = 0;
+ os->nb_fragments = 0;
+ return err;
+ }
}
frag = av_mallocz(sizeof(*frag));
if (!frag)
diff --git a/ffmpeg/libavformat/smush.c b/ffmpeg/libavformat/smush.c
index 9c8997c..e9c1937 100644
--- a/ffmpeg/libavformat/smush.c
+++ b/ffmpeg/libavformat/smush.c
@@ -145,11 +145,9 @@ static int smush_read_header(AVFormatContext *ctx)
avpriv_set_pts_info(vst, 64, 66667, 1000000);
if (!smush->version) {
- vst->codec->extradata = av_malloc(1024 + 2 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!vst->codec->extradata)
+ if (ff_alloc_extradata(vst->codec, 1024 + 2))
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 1024 + 2;
AV_WL16(vst->codec->extradata, subversion);
for (i = 0; i < 256; i++)
AV_WL32(vst->codec->extradata + 2 + i * 4, palette[i]);
diff --git a/ffmpeg/libavformat/spdif.h b/ffmpeg/libavformat/spdif.h
index 0a0d962..fee4ff7 100644
--- a/ffmpeg/libavformat/spdif.h
+++ b/ffmpeg/libavformat/spdif.h
@@ -41,9 +41,9 @@ enum IEC61937DataType {
IEC61937_DTS1 = 0x0B, ///< DTS type I (512 samples)
IEC61937_DTS2 = 0x0C, ///< DTS type II (1024 samples)
IEC61937_DTS3 = 0x0D, ///< DTS type III (2048 samples)
- IEC61937_ATRAC = 0x0E, ///< Atrac data
- IEC61937_ATRAC3 = 0x0F, ///< Atrac 3 data
- IEC61937_ATRACX = 0x10, ///< Atrac 3 plus data
+ IEC61937_ATRAC = 0x0E, ///< ATRAC data
+ IEC61937_ATRAC3 = 0x0F, ///< ATRAC3 data
+ IEC61937_ATRACX = 0x10, ///< ATRAC3+ data
IEC61937_DTSHD = 0x11, ///< DTS HD data
IEC61937_WMAPRO = 0x12, ///< WMA 9 Professional data
IEC61937_MPEG2_AAC_LSF_2048 = 0x13, ///< MPEG-2 AAC ADTS half-rate low sampling frequency
diff --git a/ffmpeg/libavformat/spdifdec.c b/ffmpeg/libavformat/spdifdec.c
index 726a85c..7da16c9 100644
--- a/ffmpeg/libavformat/spdifdec.c
+++ b/ffmpeg/libavformat/spdifdec.c
@@ -57,7 +57,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s,
break;
case IEC61937_MPEG2_AAC:
init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8);
- if (avpriv_aac_parse_header(&gbc, &aac_hdr)) {
+ if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) {
if (s) /* be silent during a probe */
av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n");
return AVERROR_INVALIDDATA;
@@ -154,10 +154,10 @@ int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec)
if (sync_codes >= 6)
/* good amount of sync codes but with unexpected offsets */
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
/* some sync codes were found */
- return AVPROBE_SCORE_MAX / 8;
+ return AVPROBE_SCORE_EXTENSION / 4;
}
static int spdif_read_header(AVFormatContext *s)
diff --git a/ffmpeg/libavformat/spdifenc.c b/ffmpeg/libavformat/spdifenc.c
index 778ab88..210d63f 100644
--- a/ffmpeg/libavformat/spdifenc.c
+++ b/ffmpeg/libavformat/spdifenc.c
@@ -92,7 +92,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass spdif_class = {
.class_name = "spdif",
.item_name = av_default_item_name,
.option = options,
@@ -395,15 +395,15 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt)
{
IEC61937Context *ctx = s->priv_data;
int mat_code_length = 0;
- const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 };
+ static const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 };
if (!ctx->hd_buf_count) {
- const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 };
+ static const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 };
mat_code_length = sizeof(mat_start_code) + BURST_HEADER_SIZE;
memcpy(ctx->hd_buf, mat_start_code, sizeof(mat_start_code));
} else if (ctx->hd_buf_count == 12) {
- const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 };
+ static const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 };
mat_code_length = sizeof(mat_middle_code) + MAT_MIDDLE_CODE_OFFSET;
memcpy(&ctx->hd_buf[12 * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + MAT_MIDDLE_CODE_OFFSET],
mat_middle_code, sizeof(mat_middle_code));
@@ -538,7 +538,6 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_DEBUG, "type=%x len=%i pkt_offset=%i\n",
ctx->data_type, ctx->out_bytes, ctx->pkt_offset);
- avio_flush(s->pb);
return 0;
}
@@ -553,5 +552,5 @@ AVOutputFormat ff_spdif_muxer = {
.write_packet = spdif_write_packet,
.write_trailer = spdif_write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
- .priv_class = &class,
+ .priv_class = &spdif_class,
};
diff --git a/ffmpeg/libavformat/srtdec.c b/ffmpeg/libavformat/srtdec.c
index 76e06e4..7f911bd 100644
--- a/ffmpeg/libavformat/srtdec.c
+++ b/ffmpeg/libavformat/srtdec.c
@@ -37,12 +37,14 @@ static int srt_probe(AVProbeData *p)
if (AV_RB24(ptr) == 0xEFBBBF)
ptr += 3; /* skip UTF-8 BOM */
+ while (*ptr == '\r' || *ptr == '\n')
+ ptr++;
for (i=0; i<2; i++) {
if ((num == i || num + 1 == i)
&& sscanf(ptr, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v) == 1)
return AVPROBE_SCORE_MAX;
num = atoi(ptr);
- ptr += strcspn(ptr, "\n") + 1;
+ ptr += ff_subtitles_next_line(ptr);
}
return 0;
}
@@ -63,10 +65,10 @@ static int64_t get_pts(const char **buf, int *duration,
int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
*duration = end - start;
- *buf += strcspn(*buf, "\n") + 1;
+ *buf += ff_subtitles_next_line(*buf);
return start;
}
- *buf += strcspn(*buf, "\n") + 1;
+ *buf += ff_subtitles_next_line(*buf);
}
return AV_NOPTS_VALUE;
}
diff --git a/ffmpeg/libavformat/srtenc.c b/ffmpeg/libavformat/srtenc.c
index e02c4ef..b43504b 100644
--- a/ffmpeg/libavformat/srtenc.c
+++ b/ffmpeg/libavformat/srtenc.c
@@ -98,7 +98,6 @@ static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt)
avio_write(avf->pb, pkt->data, pkt->size);
if (write_ts)
avio_write(avf->pb, "\n\n", 2);
- avio_flush(avf->pb);
srt->index++;
return 0;
}
diff --git a/ffmpeg/libavformat/srtp.c b/ffmpeg/libavformat/srtp.c
index 65309d0..b6e8211 100644
--- a/ffmpeg/libavformat/srtp.c
+++ b/ffmpeg/libavformat/srtp.c
@@ -25,6 +25,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "rtp.h"
+#include "rtpdec.h"
#include "srtp.h"
void ff_srtp_free(struct SRTPContext *s)
@@ -419,7 +420,7 @@ static void test_encrypt(const uint8_t *data, int in_len, const char *suite,
{
struct SRTPContext enc = { 0 }, dec = { 0 };
int len;
- char buf[1500];
+ char buf[RTP_MAX_PACKET_LENGTH];
ff_srtp_set_crypto(&enc, suite, key);
ff_srtp_set_crypto(&dec, suite, key);
len = ff_srtp_encrypt(&enc, data, in_len, buf, sizeof(buf));
@@ -441,7 +442,7 @@ int main(void)
static const char *aes128_32_suite = "AES_CM_128_HMAC_SHA1_32";
static const char *aes128_80_32_suite = "SRTP_AES128_CM_HMAC_SHA1_32";
static const char *test_key = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
- uint8_t buf[1500];
+ uint8_t buf[RTP_MAX_PACKET_LENGTH];
struct SRTPContext srtp = { 0 };
int len;
ff_srtp_set_crypto(&srtp, aes128_80_suite, aes128_80_key);
diff --git a/ffmpeg/libavformat/srtpproto.c b/ffmpeg/libavformat/srtpproto.c
index f5e3d14..f9d6b17 100644
--- a/ffmpeg/libavformat/srtpproto.c
+++ b/ffmpeg/libavformat/srtpproto.c
@@ -25,6 +25,7 @@
#include "url.h"
#include "internal.h"
+#include "rtpdec.h"
#include "srtp.h"
typedef struct SRTPProtoContext {
@@ -33,7 +34,7 @@ typedef struct SRTPProtoContext {
const char *out_suite, *out_params;
const char *in_suite, *in_params;
struct SRTPContext srtp_out, srtp_in;
- uint8_t encryptbuf[1500];
+ uint8_t encryptbuf[RTP_MAX_PACKET_LENGTH];
} SRTPProtoContext;
#define D AV_OPT_FLAG_DECODING_PARAM
diff --git a/ffmpeg/libavformat/subtitles.c b/ffmpeg/libavformat/subtitles.c
index 2af0450..fce2bf1 100644
--- a/ffmpeg/libavformat/subtitles.c
+++ b/ffmpeg/libavformat/subtitles.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Clément Bœsch
+ * Copyright (c) 2012-2013 Clément Bœsch <u pkh me>
*
* This file is part of FFmpeg.
*
@@ -57,7 +57,7 @@ AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q,
return sub;
}
-static int cmp_pkt_sub(const void *a, const void *b)
+static int cmp_pkt_sub_ts_pos(const void *a, const void *b)
{
const AVPacket *s1 = a;
const AVPacket *s2 = b;
@@ -69,11 +69,25 @@ static int cmp_pkt_sub(const void *a, const void *b)
return s1->pts > s2->pts ? 1 : -1;
}
+static int cmp_pkt_sub_pos_ts(const void *a, const void *b)
+{
+ const AVPacket *s1 = a;
+ const AVPacket *s2 = b;
+ if (s1->pos == s2->pos) {
+ if (s1->pts == s2->pts)
+ return 0;
+ return s1->pts > s2->pts ? 1 : -1;
+ }
+ return s1->pos > s2->pos ? 1 : -1;
+}
+
void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
{
int i;
- qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub);
+ qsort(q->subs, q->nb_subs, sizeof(*q->subs),
+ q->sort == SUB_SORT_TS_POS ? cmp_pkt_sub_ts_pos
+ : cmp_pkt_sub_pos_ts);
for (i = 0; i < q->nb_subs; i++)
if (q->subs[i].duration == -1 && i < q->nb_subs - 1)
q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts;
@@ -85,13 +99,37 @@ int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
if (q->current_sub_idx == q->nb_subs)
return AVERROR_EOF;
- av_copy_packet(pkt, sub);
+ if (av_copy_packet(pkt, sub) < 0) {
+ return AVERROR(ENOMEM);
+ }
pkt->dts = pkt->pts;
q->current_sub_idx++;
return 0;
}
+static int search_sub_ts(const FFDemuxSubtitlesQueue *q, int64_t ts)
+{
+ int s1 = 0, s2 = q->nb_subs - 1;
+
+ if (s2 < s1)
+ return AVERROR(ERANGE);
+
+ for (;;) {
+ int mid;
+
+ if (s1 == s2)
+ return s1;
+ if (s1 == s2 - 1)
+ return q->subs[s1].pts <= q->subs[s2].pts ? s1 : s2;
+ mid = (s1 + s2) / 2;
+ if (q->subs[mid].pts <= ts)
+ s1 = mid;
+ else
+ s2 = mid;
+ }
+}
+
int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
@@ -102,30 +140,43 @@ int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int st
return AVERROR(ERANGE);
q->current_sub_idx = ts;
} else {
- int i, idx = -1;
- int64_t min_ts_diff = INT64_MAX;
+ int i, idx = search_sub_ts(q, ts);
int64_t ts_selected;
- /* TODO: q->subs[] is sorted by pts so we could do a binary search */
- for (i = 0; i < q->nb_subs; i++) {
- int64_t pts = q->subs[i].pts;
- uint64_t ts_diff = FFABS(pts - ts);
- if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
- min_ts_diff = ts_diff;
- idx = i;
- }
- }
+
if (idx < 0)
+ return idx;
+ for (i = idx; i < q->nb_subs && q->subs[i].pts < min_ts; i++)
+ if (stream_index == -1 || q->subs[i].stream_index == stream_index)
+ idx = i;
+ for (i = idx; i > 0 && q->subs[i].pts > max_ts; i--)
+ if (stream_index == -1 || q->subs[i].stream_index == stream_index)
+ idx = i;
+
+ ts_selected = q->subs[idx].pts;
+ if (ts_selected < min_ts || ts_selected > max_ts)
return AVERROR(ERANGE);
+
/* look back in the latest subtitles for overlapping subtitles */
- ts_selected = q->subs[idx].pts;
for (i = idx - 1; i >= 0; i--) {
- if (q->subs[i].duration <= 0)
+ int64_t pts = q->subs[i].pts;
+ if (q->subs[i].duration <= 0 ||
+ (stream_index != -1 && q->subs[i].stream_index != stream_index))
continue;
- if (q->subs[i].pts > ts_selected - q->subs[i].duration)
+ if (pts >= min_ts && pts > ts_selected - q->subs[i].duration)
idx = i;
else
break;
}
+
+ /* If the queue is used to store multiple subtitles streams (like with
+ * VobSub) and the stream index is not specified, we need to make sure
+ * to focus on the smallest file position offset for a same timestamp;
+ * queue is ordered by pts and then filepos, so we can take the first
+ * entry for a given timestamp. */
+ if (stream_index == -1)
+ while (idx > 0 && q->subs[idx - 1].pts == q->subs[idx].pts)
+ idx--;
+
q->current_sub_idx = idx;
}
return 0;
@@ -191,7 +242,7 @@ static inline int is_eol(char c)
void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf)
{
- char eol_buf[5];
+ char eol_buf[5], last_was_cr = 0;
int n = 0, i = 0, nb_eol = 0;
av_bprint_clear(buf);
@@ -208,12 +259,13 @@ void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf)
/* line break buffering: we don't want to add the trailing \r\n */
if (is_eol(c)) {
- nb_eol += c == '\n';
+ nb_eol += c == '\n' || last_was_cr;
if (nb_eol == 2)
break;
eol_buf[i++] = c;
if (i == sizeof(eol_buf) - 1)
break;
+ last_was_cr = c == '\r';
continue;
}
diff --git a/ffmpeg/libavformat/subtitles.h b/ffmpeg/libavformat/subtitles.h
index 455b374..b5a96ec 100644
--- a/ffmpeg/libavformat/subtitles.h
+++ b/ffmpeg/libavformat/subtitles.h
@@ -25,11 +25,17 @@
#include "avformat.h"
#include "libavutil/bprint.h"
+enum sub_sort {
+ SUB_SORT_TS_POS = 0, ///< sort by timestamps, then position
+ SUB_SORT_POS_TS, ///< sort by position, then timestamps
+};
+
typedef struct {
AVPacket *subs; ///< array of subtitles packets
int nb_subs; ///< number of subtitles packets
int allocated_size; ///< allocated size for subs
int current_sub_idx; ///< current position for the read packet callback
+ enum sub_sort sort; ///< sort method to use when finalizing subtitles
} FFDemuxSubtitlesQueue;
/**
@@ -96,4 +102,23 @@ const char *ff_smil_get_attr_ptr(const char *s, const char *attr);
*/
void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf);
+/**
+ * Get the number of characters to increment to jump to the next line, or to
+ * the end of the string.
+ * The function handles the following line breaks schemes:
+ * LF, CRLF (MS), or standalone CR (old MacOS).
+ */
+static av_always_inline int ff_subtitles_next_line(const char *ptr)
+{
+ int n = strcspn(ptr, "\r\n");
+ ptr += n;
+ if (*ptr == '\r') {
+ ptr++;
+ n++;
+ }
+ if (*ptr == '\n')
+ n++;
+ return n;
+}
+
#endif /* AVFORMAT_SUBTITLES_H */
diff --git a/ffmpeg/libavformat/subviewer1dec.c b/ffmpeg/libavformat/subviewer1dec.c
index 0dc1942..1b831b7 100644
--- a/ffmpeg/libavformat/subviewer1dec.c
+++ b/ffmpeg/libavformat/subviewer1dec.c
@@ -36,7 +36,7 @@ static int subviewer1_probe(AVProbeData *p)
const unsigned char *ptr = p->buf;
if (strstr(ptr, "******** START SCRIPT ********"))
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
return 0;
}
diff --git a/ffmpeg/libavformat/subviewerdec.c b/ffmpeg/libavformat/subviewerdec.c
index 7cacd97..9e645d2 100644
--- a/ffmpeg/libavformat/subviewerdec.c
+++ b/ffmpeg/libavformat/subviewerdec.c
@@ -44,7 +44,7 @@ static int subviewer_probe(AVProbeData *p)
if (AV_RB24(ptr) == 0xEFBBBF)
ptr += 3; /* skip UTF-8 BOM */
if (sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1)
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
if (!strncmp(ptr, "[INFORMATION]", 13))
return AVPROBE_SCORE_MAX/3;
return 0;
diff --git a/ffmpeg/libavformat/swf.h b/ffmpeg/libavformat/swf.h
index b9722c1..c1667b3 100644
--- a/ffmpeg/libavformat/swf.h
+++ b/ffmpeg/libavformat/swf.h
@@ -120,9 +120,6 @@ enum {
#define VIDEO_ID 0
#define SHAPE_ID 1
-#undef NDEBUG
-#include <assert.h>
-
typedef struct SWFContext {
int64_t duration_pos;
int64_t tag_pos;
diff --git a/ffmpeg/libavformat/swfdec.c b/ffmpeg/libavformat/swfdec.c
index 54e0f6d..c95b18e 100644
--- a/ffmpeg/libavformat/swfdec.c
+++ b/ffmpeg/libavformat/swfdec.c
@@ -55,12 +55,18 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr)
static int swf_probe(AVProbeData *p)
{
+ if(p->buf_size < 15)
+ return 0;
+
/* check file header */
- if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
- p->buf[2] == 'S')
- return AVPROBE_SCORE_MAX;
- else
+ if ( AV_RB24(p->buf) != AV_RB24("CWS")
+ && AV_RB24(p->buf) != AV_RB24("FWS"))
return 0;
+
+ if (p->buf[3] >= 20)
+ return AVPROBE_SCORE_MAX / 4;
+
+ return AVPROBE_SCORE_MAX;
}
#if CONFIG_ZLIB
@@ -440,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/ffmpeg/libavformat/swfenc.c b/ffmpeg/libavformat/swfenc.c
index 5b7fd1f..8d9cf0c 100644
--- a/ffmpeg/libavformat/swfenc.c
+++ b/ffmpeg/libavformat/swfenc.c
@@ -234,7 +234,7 @@ static int swf_write_header(AVFormatContext *s)
}
if (!swf->audio_enc)
- swf->samples_per_frame = (44100. * rate_base) / rate;
+ swf->samples_per_frame = (44100.0 * rate_base) / rate;
else
swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate;
@@ -441,8 +441,6 @@ static int swf_write_video(AVFormatContext *s,
put_swf_tag(s, TAG_SHOWFRAME);
put_swf_end_tag(s);
- avio_flush(s->pb);
-
return 0;
}
diff --git a/ffmpeg/libavformat/takdec.c b/ffmpeg/libavformat/takdec.c
index 377c10c..2ed8a1e 100644
--- a/ffmpeg/libavformat/takdec.c
+++ b/ffmpeg/libavformat/takdec.c
@@ -19,8 +19,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/crc.h"
#include "libavcodec/tak.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "rawdec.h"
#include "apetag.h"
@@ -33,10 +35,16 @@ typedef struct TAKDemuxContext {
static int tak_probe(AVProbeData *p)
{
if (!memcmp(p->buf, "tBaK", 4))
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
return 0;
}
+static unsigned long tak_check_crc(unsigned long checksum, const uint8_t *buf,
+ unsigned int len)
+{
+ return av_crc(av_crc_get_table(AV_CRC_24_IEEE), checksum, buf, len);
+}
+
static int tak_read_header(AVFormatContext *s)
{
TAKDemuxContext *tc = s->priv_data;
@@ -71,16 +79,27 @@ static int tak_read_header(AVFormatContext *s)
case TAK_METADATA_STREAMINFO:
case TAK_METADATA_LAST_FRAME:
case TAK_METADATA_ENCODER:
- buffer = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (size <= 3)
+ return AVERROR_INVALIDDATA;
+
+ buffer = av_malloc(size - 3 + FF_INPUT_BUFFER_PADDING_SIZE);
if (!buffer)
return AVERROR(ENOMEM);
- if (avio_read(pb, buffer, size) != size) {
+ ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U);
+ if (avio_read(pb, buffer, size - 3) != size - 3) {
av_freep(&buffer);
return AVERROR(EIO);
}
+ if (ffio_get_checksum(s->pb) != avio_rb24(pb)) {
+ av_log(s, AV_LOG_ERROR, "%d metadata block CRC error.\n", type);
+ if (s->error_recognition & AV_EF_EXPLODE) {
+ av_freep(&buffer);
+ return AVERROR_INVALIDDATA;
+ }
+ }
- init_get_bits(&gb, buffer, size * 8);
+ init_get_bits8(&gb, buffer, size - 3);
break;
case TAK_METADATA_MD5: {
uint8_t md5[16];
@@ -88,8 +107,14 @@ static int tak_read_header(AVFormatContext *s)
if (size != 19)
return AVERROR_INVALIDDATA;
+ ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U);
avio_read(pb, md5, 16);
- avio_skip(pb, 3);
+ if (ffio_get_checksum(s->pb) != avio_rb24(pb)) {
+ av_log(s, AV_LOG_ERROR, "MD5 metadata block CRC error.\n");
+ if (s->error_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ }
+
av_log(s, AV_LOG_VERBOSE, "MD5=");
for (i = 0; i < 16; i++)
av_log(s, AV_LOG_VERBOSE, "%02x", md5[i]);
@@ -127,7 +152,7 @@ static int tak_read_header(AVFormatContext *s)
st->start_time = 0;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
st->codec->extradata = buffer;
- st->codec->extradata_size = size;
+ st->codec->extradata_size = size - 3;
buffer = NULL;
} else if (type == TAK_METADATA_LAST_FRAME) {
if (size != 11)
@@ -155,7 +180,7 @@ static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
int64_t size, left;
- left = tc->data_end - avio_tell(s->pb);
+ left = tc->data_end - avio_tell(pb);
size = FFMIN(left, 1024);
if (size <= 0)
return AVERROR_EOF;
diff --git a/ffmpeg/libavformat/tcp.c b/ffmpeg/libavformat/tcp.c
index 0d792e7..e457fba 100644
--- a/ffmpeg/libavformat/tcp.c
+++ b/ffmpeg/libavformat/tcp.c
@@ -34,6 +34,7 @@ typedef struct TCPContext {
const AVClass *class;
int fd;
int listen;
+ int open_timeout;
int rw_timeout;
int listen_timeout;
} TCPContext;
@@ -43,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 = 0}, 0, 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}
};
@@ -64,10 +65,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
const char *p;
char buf[256];
int ret;
- socklen_t optlen;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
- h->rw_timeout = 5000000;
+ s->open_timeout = 5000000;
av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
&port, path, sizeof(path), uri);
@@ -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);
}
@@ -88,7 +93,10 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
s->listen_timeout = strtol(buf, NULL, 10);
}
}
- h->rw_timeout = s->rw_timeout;
+ if (s->rw_timeout >= 0) {
+ s->open_timeout =
+ h->rw_timeout = s->rw_timeout;
+ }
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", port);
@@ -108,89 +116,31 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
cur_ai = ai;
restart:
- ret = AVERROR(EIO);
- fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
- if (fd < 0)
+ fd = ff_socket(cur_ai->ai_family,
+ cur_ai->ai_socktype,
+ cur_ai->ai_protocol);
+ if (fd < 0) {
+ ret = ff_neterrno();
goto fail;
+ }
if (s->listen) {
- int fd1;
- int reuse = 1;
- struct pollfd lp = { fd, POLLIN, 0 };
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
- ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
- if (ret) {
- ret = ff_neterrno();
- goto fail1;
- }
- ret = listen(fd, 1);
- if (ret) {
- ret = ff_neterrno();
- goto fail1;
- }
- ret = poll(&lp, 1, s->listen_timeout >= 0 ? s->listen_timeout : -1);
- if (ret <= 0) {
- ret = AVERROR(ETIMEDOUT);
- goto fail1;
- }
- fd1 = accept(fd, NULL, NULL);
- if (fd1 < 0) {
- ret = ff_neterrno();
+ if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
+ s->listen_timeout, h)) < 0) {
+ ret = fd;
goto fail1;
}
- closesocket(fd);
- fd = fd1;
- ff_socket_nonblock(fd, 1);
} else {
- redo:
- ff_socket_nonblock(fd, 1);
- ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
- }
+ if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
+ s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
- if (ret < 0) {
- struct pollfd p = {fd, POLLOUT, 0};
- int64_t wait_started;
- ret = ff_neterrno();
- if (ret == AVERROR(EINTR)) {
- if (ff_check_interrupt(&h->interrupt_callback)) {
- ret = AVERROR_EXIT;
+ if (ret == AVERROR_EXIT)
goto fail1;
- }
- goto redo;
- }
- if (ret != AVERROR(EINPROGRESS) &&
- ret != AVERROR(EAGAIN))
- goto fail;
-
- /* wait until we are connected or until abort */
- wait_started = av_gettime();
- do {
- if (ff_check_interrupt(&h->interrupt_callback)) {
- ret = AVERROR_EXIT;
- goto fail1;
- }
- ret = poll(&p, 1, 100);
- if (ret > 0)
- break;
- } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout));
- if (ret <= 0) {
- ret = AVERROR(ETIMEDOUT);
- goto fail;
- }
- /* test error */
- optlen = sizeof(ret);
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
- ret = AVUNERROR(ff_neterrno());
- if (ret != 0) {
- char errbuf[100];
- ret = AVERROR(ret);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(h, AV_LOG_ERROR,
- "TCP connection to %s:%d failed: %s\n",
- hostname, port, errbuf);
- goto fail;
+ else
+ goto fail;
}
}
+
h->is_streamed = 1;
s->fd = fd;
freeaddrinfo(ai);
@@ -202,6 +152,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
cur_ai = cur_ai->ai_next;
if (fd >= 0)
closesocket(fd);
+ ret = 0;
goto restart;
}
fail1:
diff --git a/ffmpeg/libavformat/tedcaptionsdec.c b/ffmpeg/libavformat/tedcaptionsdec.c
index 048ba96..68063fa 100644
--- a/ffmpeg/libavformat/tedcaptionsdec.c
+++ b/ffmpeg/libavformat/tedcaptionsdec.c
@@ -153,7 +153,8 @@ static int parse_label(AVIOContext *pb, int *cur_byte, AVBPrint *bp)
static int parse_boolean(AVIOContext *pb, int *cur_byte, int *result)
{
- const char *text[] = { "false", "true" }, *p;
+ static const char * const text[] = { "false", "true" };
+ const char *p;
int i;
skip_spaces(pb, cur_byte);
@@ -340,7 +341,7 @@ static av_cold int tedcaptions_read_probe(AVProbeData *p)
count++;
}
return count == FF_ARRAY_ELEMS(tags) ? AVPROBE_SCORE_MAX :
- count ? AVPROBE_SCORE_MAX / 2 : 0;
+ count ? AVPROBE_SCORE_EXTENSION : 0;
}
static int tedcaptions_read_seek(AVFormatContext *avf, int stream_index,
diff --git a/ffmpeg/libavformat/tee.c b/ffmpeg/libavformat/tee.c
index 10787ca..12ea0ea 100644
--- a/ffmpeg/libavformat/tee.c
+++ b/ffmpeg/libavformat/tee.c
@@ -1,5 +1,5 @@
/*
- * Tee pesudo-muxer
+ * Tee pseudo-muxer
* Copyright (c) 2012 Nicolas George
*
* This file is part of FFmpeg.
@@ -27,16 +27,26 @@
#define MAX_SLAVES 16
+typedef struct {
+ AVFormatContext *avf;
+ AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+
+ /** map from input to output streams indexes,
+ * disabled output streams are set to -1 */
+ int *stream_map;
+} TeeSlave;
+
typedef struct TeeContext {
const AVClass *class;
unsigned nb_slaves;
- AVFormatContext *slaves[MAX_SLAVES];
+ TeeSlave slaves[MAX_SLAVES];
} TeeContext;
static const char *const slave_delim = "|";
static const char *const slave_opt_open = "[";
static const char *const slave_opt_close = "]";
static const char *const slave_opt_delim = ":]"; /* must have the close too */
+static const char *const slave_bsfs_spec_sep = "/";
static const AVClass tee_muxer_class = {
.class_name = "Tee muxer",
@@ -82,34 +92,104 @@ fail:
return ret;
}
-static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf)
+/**
+ * Parse list of bitstream filters and add them to the list of filters
+ * pointed to by bsfs.
+ *
+ * The list must be specified in the form:
+ * BSFS ::= BSF[,BSFS]
+ */
+static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
+ AVBitStreamFilterContext **bsfs)
+{
+ char *bsf_name, *buf, *dup, *saveptr;
+ int ret = 0;
+
+ if (!(dup = buf = av_strdup(bsfs_spec)))
+ return AVERROR(ENOMEM);
+
+ while (bsf_name = av_strtok(buf, ",", &saveptr)) {
+ AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
+
+ if (!bsf) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Cannot initialize bitstream filter with name '%s', "
+ "unknown filter or internal error happened\n",
+ bsf_name);
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ /* append bsf context to the list of bsf contexts */
+ *bsfs = bsf;
+ bsfs = &bsf->next;
+
+ buf = NULL;
+ }
+
+end:
+ av_free(dup);
+ return ret;
+}
+
+static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
{
int i, ret;
AVDictionary *options = NULL;
AVDictionaryEntry *entry;
char *filename;
- char *format = NULL;
+ char *format = NULL, *select = NULL;
AVFormatContext *avf2 = NULL;
AVStream *st, *st2;
+ int stream_count;
if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
return ret;
- if ((entry = av_dict_get(options, "f", NULL, 0))) {
- format = entry->value;
- entry->value = NULL; /* prevent it from being freed */
- av_dict_set(&options, "f", NULL, 0);
- }
+
+#define STEAL_OPTION(option, field) do { \
+ if ((entry = av_dict_get(options, option, NULL, 0))) { \
+ field = entry->value; \
+ entry->value = NULL; /* prevent it from being freed */ \
+ av_dict_set(&options, option, NULL, 0); \
+ } \
+ } while (0)
+
+ STEAL_OPTION("f", format);
+ STEAL_OPTION("select", select);
ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
if (ret < 0)
- goto fail;
- av_free(format);
+ goto end;
+ av_dict_copy(&avf2->metadata, avf->metadata, 0);
+ tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
+ if (!tee_slave->stream_map) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ stream_count = 0;
for (i = 0; i < avf->nb_streams; i++) {
st = avf->streams[i];
+ if (select) {
+ ret = avformat_match_stream_specifier(avf, avf->streams[i], select);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR,
+ "Invalid stream specifier '%s' for output '%s'\n",
+ select, slave);
+ goto end;
+ }
+
+ if (ret == 0) { /* no match */
+ tee_slave->stream_map[i] = -1;
+ continue;
+ }
+ }
+ tee_slave->stream_map[i] = stream_count++;
+
if (!(st2 = avformat_new_stream(avf2, NULL))) {
ret = AVERROR(ENOMEM);
- goto fail;
+ goto end;
}
st2->id = st->id;
st2->r_frame_rate = st->r_frame_rate;
@@ -122,34 +202,85 @@ static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf)
st2->avg_frame_rate = st->avg_frame_rate;
av_dict_copy(&st2->metadata, st->metadata, 0);
if ((ret = avcodec_copy_context(st2->codec, st->codec)) < 0)
- goto fail;
+ goto end;
}
if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
if ((ret = avio_open(&avf2->pb, filename, AVIO_FLAG_WRITE)) < 0) {
av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n",
slave, av_err2str(ret));
- goto fail;
+ goto end;
}
}
if ((ret = avformat_write_header(avf2, &options)) < 0) {
av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
slave, av_err2str(ret));
- goto fail;
+ goto end;
+ }
+
+ tee_slave->avf = avf2;
+ tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(TeeSlave));
+ if (!tee_slave->bsfs) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ entry = NULL;
+ while (entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ const char *spec = entry->key + strlen("bsfs");
+ if (*spec) {
+ if (strspn(spec, slave_bsfs_spec_sep) != 1) {
+ av_log(avf, AV_LOG_ERROR,
+ "Specifier separator in '%s' is '%c', but only characters '%s' "
+ "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
+ return AVERROR(EINVAL);
+ }
+ spec++; /* consume separator */
+ }
+
+ for (i = 0; i < avf2->nb_streams; i++) {
+ ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR,
+ "Invalid stream specifier '%s' in bsfs option '%s' for slave "
+ "output '%s'\n", spec, entry->key, filename);
+ goto end;
+ }
+
+ if (ret > 0) {
+ av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
+ "output '%s'\n", spec, entry->value, i, filename);
+ if (tee_slave->bsfs[i]) {
+ av_log(avf, AV_LOG_WARNING,
+ "Duplicate bsfs specification associated to stream %d of slave "
+ "output '%s', filters will be ignored\n", i, filename);
+ continue;
+ }
+ ret = parse_bsfs(avf, entry->value, &tee_slave->bsfs[i]);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR,
+ "Error parsing bitstream filter sequence '%s' associated to "
+ "stream %d of slave output '%s'\n", entry->value, i, filename);
+ goto end;
+ }
+ }
+ }
+
+ av_dict_set(&options, entry->key, NULL, 0);
}
+
if (options) {
entry = NULL;
while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX)))
av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
ret = AVERROR_OPTION_NOT_FOUND;
- goto fail;
+ goto end;
}
- *ravf = avf2;
- return 0;
-
-fail:
+end:
+ av_free(format);
+ av_free(select);
av_dict_free(&options);
return ret;
}
@@ -158,14 +289,50 @@ static void close_slaves(AVFormatContext *avf)
{
TeeContext *tee = avf->priv_data;
AVFormatContext *avf2;
- unsigned i;
+ unsigned i, j;
for (i = 0; i < tee->nb_slaves; i++) {
- avf2 = tee->slaves[i];
+ avf2 = tee->slaves[i].avf;
+
+ for (j = 0; j < avf2->nb_streams; j++) {
+ AVBitStreamFilterContext *bsf_next, *bsf = tee->slaves[i].bsfs[j];
+ while (bsf) {
+ bsf_next = bsf->next;
+ av_bitstream_filter_close(bsf);
+ bsf = bsf_next;
+ }
+ }
+ av_freep(&tee->slaves[i].stream_map);
+ av_freep(&tee->slaves[i].bsfs);
+
avio_close(avf2->pb);
avf2->pb = NULL;
avformat_free_context(avf2);
- tee->slaves[i] = NULL;
+ tee->slaves[i].avf = NULL;
+ }
+}
+
+static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
+{
+ int i;
+ av_log(log_ctx, log_level, "filename:'%s' format:%s\n",
+ slave->avf->filename, slave->avf->oformat->name);
+ for (i = 0; i < slave->avf->nb_streams; i++) {
+ AVStream *st = slave->avf->streams[i];
+ AVBitStreamFilterContext *bsf = slave->bsfs[i];
+
+ av_log(log_ctx, log_level, " stream:%d codec:%s type:%s",
+ i, avcodec_get_name(st->codec->codec_id),
+ av_get_media_type_string(st->codec->codec_type));
+ if (bsf) {
+ av_log(log_ctx, log_level, " bsfs:");
+ while (bsf) {
+ av_log(log_ctx, log_level, "%s%s",
+ bsf->filter->name, bsf->next ? "," : "");
+ bsf = bsf->next;
+ }
+ }
+ av_log(log_ctx, log_level, "\n");
}
}
@@ -195,10 +362,20 @@ static int tee_write_header(AVFormatContext *avf)
for (i = 0; i < nb_slaves; i++) {
if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0)
goto fail;
+ log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
av_freep(&slaves[i]);
}
tee->nb_slaves = nb_slaves;
+
+ for (i = 0; i < avf->nb_streams; i++) {
+ int j, mapped = 0;
+ for (j = 0; j < tee->nb_slaves; j++)
+ mapped += tee->slaves[j].stream_map[i] >= 0;
+ if (!mapped)
+ av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
+ "to any slave.\n", i);
+ }
return 0;
fail:
@@ -208,6 +385,46 @@ fail:
return ret;
}
+static int filter_packet(void *log_ctx, AVPacket *pkt,
+ AVFormatContext *fmt_ctx, AVBitStreamFilterContext *bsf_ctx)
+{
+ AVCodecContext *enc_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
+ int ret = 0;
+
+ while (bsf_ctx) {
+ AVPacket new_pkt = *pkt;
+ ret = av_bitstream_filter_filter(bsf_ctx, enc_ctx, NULL,
+ &new_pkt.data, &new_pkt.size,
+ pkt->data, pkt->size,
+ pkt->flags & AV_PKT_FLAG_KEY);
+ if (ret == 0 && new_pkt.data != pkt->data && new_pkt.destruct) {
+ if ((ret = av_copy_packet(&new_pkt, pkt)) < 0)
+ break;
+ ret = 1;
+ }
+
+ if (ret > 0) {
+ av_free_packet(pkt);
+ new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
+ av_buffer_default_free, NULL, 0);
+ if (!new_pkt.buf)
+ break;
+ }
+ *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;
+}
+
static int tee_write_trailer(AVFormatContext *avf)
{
TeeContext *tee = avf->priv_data;
@@ -216,7 +433,7 @@ static int tee_write_trailer(AVFormatContext *avf)
unsigned i;
for (i = 0; i < tee->nb_slaves; i++) {
- avf2 = tee->slaves[i];
+ avf2 = tee->slaves[i].avf;
if ((ret = av_write_trailer(avf2)) < 0)
if (!ret_all)
ret_all = ret;
@@ -238,27 +455,30 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
AVPacket pkt2;
int ret_all = 0, ret;
unsigned i, s;
+ int s2;
AVRational tb, tb2;
for (i = 0; i < tee->nb_slaves; i++) {
- avf2 = tee->slaves[i];
+ avf2 = tee->slaves[i].avf;
s = pkt->stream_index;
- if (s >= avf2->nb_streams) {
- if (!ret_all)
- ret_all = AVERROR(EINVAL);
+ s2 = tee->slaves[i].stream_map[s];
+ if (s2 < 0)
continue;
- }
+
if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
(ret = av_dup_packet(&pkt2))< 0)
if (!ret_all) {
ret = ret_all;
continue;
}
- tb = avf ->streams[s]->time_base;
- tb2 = avf2->streams[s]->time_base;
+ tb = avf ->streams[s ]->time_base;
+ tb2 = avf2->streams[s2]->time_base;
pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
+ pkt2.stream_index = s2;
+
+ filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s2]);
if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
if (!ret_all)
ret_all = ret;
diff --git a/ffmpeg/libavformat/thp.c b/ffmpeg/libavformat/thp.c
index 3717b8f..bc4f0da 100644
--- a/ffmpeg/libavformat/thp.c
+++ b/ffmpeg/libavformat/thp.c
@@ -26,15 +26,15 @@
typedef struct ThpDemuxContext {
int version;
- int first_frame;
- int first_framesz;
- int last_frame;
+ unsigned first_frame;
+ unsigned first_framesz;
+ unsigned last_frame;
int compoff;
- int framecnt;
+ unsigned framecnt;
AVRational fps;
- int frame;
- int next_frame;
- int next_framesz;
+ unsigned frame;
+ int64_t next_frame;
+ unsigned next_framesz;
int video_stream_index;
int audio_stream_index;
int compcount;
@@ -47,11 +47,16 @@ typedef struct ThpDemuxContext {
static int thp_probe(AVProbeData *p)
{
+ double d;
/* check file header */
- if (AV_RL32(p->buf) == MKTAG('T', 'H', 'P', '\0'))
- return AVPROBE_SCORE_MAX;
- else
+ if (AV_RL32(p->buf) != MKTAG('T', 'H', 'P', '\0'))
return 0;
+
+ d = av_int2float(AV_RB32(p->buf + 16));
+ if (d < 0.1 || d > 1000 || isnan(d))
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static int thp_read_header(AVFormatContext *s)
@@ -109,7 +114,6 @@ static int thp_read_header(AVFormatContext *s)
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = avio_rb32(pb);
st->codec->height = avio_rb32(pb);
- st->codec->sample_rate = av_q2d(thp->fps);
st->nb_frames =
st->duration = thp->framecnt;
thp->vst = st;
@@ -158,7 +162,7 @@ static int thp_read_packet(AVFormatContext *s,
avio_seek(pb, thp->next_frame, SEEK_SET);
/* Locate the next frame and read out its size. */
- thp->next_frame += thp->next_framesz;
+ thp->next_frame += FFMAX(thp->next_framesz, 1);
thp->next_framesz = avio_rb32(pb);
avio_rb32(pb); /* Previous total size. */
diff --git a/ffmpeg/libavformat/tls.c b/ffmpeg/libavformat/tls.c
index 2c85d1d..5da82db 100644
--- a/ffmpeg/libavformat/tls.c
+++ b/ffmpeg/libavformat/tls.c
@@ -2,29 +2,31 @@
* TLS/SSL Protocol
* Copyright (c) 2011 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "url.h"
#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#if CONFIG_GNUTLS
#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
#define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size)
#define TLS_write(c, buf, size) gnutls_record_send(c->session, buf, size)
#define TLS_shutdown(c) gnutls_bye(c->session, GNUTLS_SHUT_RDWR)
@@ -66,14 +68,46 @@ typedef struct {
SSL *ssl;
#endif
int fd;
+ char *ca_file;
+ int verify;
+ char *cert_file;
+ char *key_file;
+ int listen;
} TLSContext;
+#define OFFSET(x) offsetof(TLSContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"ca_file", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E },
+ {"cafile", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E },
+ {"tls_verify", "Verify the peer certificate", OFFSET(verify), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
+ {"cert_file", "Certificate file", OFFSET(cert_file), AV_OPT_TYPE_STRING, .flags = D|E },
+ {"key_file", "Private key file", OFFSET(key_file), AV_OPT_TYPE_STRING, .flags = D|E },
+ {"listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
+ { NULL }
+};
+
+static const AVClass tls_class = {
+ .class_name = "tls",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static int do_tls_poll(URLContext *h, int ret)
{
TLSContext *c = h->priv_data;
struct pollfd p = { c->fd, 0, 0 };
#if CONFIG_GNUTLS
- if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED) {
+ switch (ret) {
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ break;
+ case GNUTLS_E_WARNING_ALERT_RECEIVED:
+ av_log(h, AV_LOG_WARNING, "%s\n", gnutls_strerror(ret));
+ break;
+ default:
av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
return AVERROR(EIO);
}
@@ -107,52 +141,26 @@ static int do_tls_poll(URLContext *h, int ret)
static void set_options(URLContext *h, const char *uri)
{
TLSContext *c = h->priv_data;
- char buf[1024], key[1024];
- int has_cert, has_key, verify = 0;
-#if CONFIG_GNUTLS
- int ret;
-#endif
+ char buf[1024];
const char *p = strchr(uri, '?');
if (!p)
return;
- if (av_find_info_tag(buf, sizeof(buf), "cafile", p)) {
-#if CONFIG_GNUTLS
- ret = gnutls_certificate_set_x509_trust_file(c->cred, buf, GNUTLS_X509_FMT_PEM);
- if (ret < 0)
- av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
-#elif CONFIG_OPENSSL
- if (!SSL_CTX_load_verify_locations(c->ctx, buf, NULL))
- av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL));
-#endif
- }
+ if (!c->ca_file && av_find_info_tag(buf, sizeof(buf), "cafile", p))
+ c->ca_file = av_strdup(buf);
- if (av_find_info_tag(buf, sizeof(buf), "verify", p)) {
+ if (!c->verify && av_find_info_tag(buf, sizeof(buf), "verify", p)) {
char *endptr = NULL;
- verify = strtol(buf, &endptr, 10);
+ c->verify = strtol(buf, &endptr, 10);
if (buf == endptr)
- verify = 1;
+ c->verify = 1;
}
- has_cert = av_find_info_tag(buf, sizeof(buf), "cert", p);
- has_key = av_find_info_tag(key, sizeof(key), "key", p);
-#if CONFIG_GNUTLS
- if (has_cert && has_key) {
- ret = gnutls_certificate_set_x509_key_file(c->cred, buf, key, GNUTLS_X509_FMT_PEM);
- if (ret < 0)
- av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
- } else if (has_cert ^ has_key) {
- av_log(h, AV_LOG_ERROR, "cert and key required\n");
- }
- gnutls_certificate_set_verify_flags(c->cred, verify);
-#elif CONFIG_OPENSSL
- if (has_cert && !SSL_CTX_use_certificate_chain_file(c->ctx, buf))
- av_log(h, AV_LOG_ERROR, "SSL_CTX_use_certificate_chain_file %s\n", ERR_error_string(ERR_get_error(), NULL));
- if (has_key && !SSL_CTX_use_PrivateKey_file(c->ctx, key, SSL_FILETYPE_PEM))
- av_log(h, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey_file %s\n", ERR_error_string(ERR_get_error(), NULL));
- if (verify)
- SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
-#endif
+ if (!c->cert_file && av_find_info_tag(buf, sizeof(buf), "cert", p))
+ c->cert_file = av_strdup(buf);
+
+ if (!c->key_file && av_find_info_tag(buf, sizeof(buf), "key", p))
+ c->key_file = av_strdup(buf);
}
static int tls_open(URLContext *h, const char *uri, int flags)
@@ -160,20 +168,22 @@ static int tls_open(URLContext *h, const char *uri, int flags)
TLSContext *c = h->priv_data;
int ret;
int port;
- char buf[200], host[200], path[1024];
+ char buf[200], host[200], opts[50] = "";
int numerichost = 0;
struct addrinfo hints = { 0 }, *ai = NULL;
const char *proxy_path;
int use_proxy;
- int server = 0;
const char *p = strchr(uri, '?');
- if (p && av_find_info_tag(buf, sizeof(buf), "listen", p))
- server = 1;
ff_tls_init();
- av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), uri);
- ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", path);
+ if(p && av_find_info_tag(buf, sizeof(buf), "listen", p))
+ c->listen = 1;
+ if (c->listen)
+ snprintf(opts, sizeof(opts), "?listen=1");
+
+ av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri);
+ ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", opts);
hints.ai_flags = AI_NUMERICHOST;
if (!getaddrinfo(host, NULL, &hints, &ai)) {
@@ -203,11 +213,35 @@ static int tls_open(URLContext *h, const char *uri, int flags)
c->fd = ffurl_get_file_handle(c->tcp);
#if CONFIG_GNUTLS
- gnutls_init(&c->session, server ? GNUTLS_SERVER : GNUTLS_CLIENT);
- if (!numerichost)
+ gnutls_init(&c->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT);
+ if (!c->listen && !numerichost)
gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host));
gnutls_certificate_allocate_credentials(&c->cred);
set_options(h, uri);
+ if (c->ca_file) {
+ ret = gnutls_certificate_set_x509_trust_file(c->cred, c->ca_file, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
+ }
+#if GNUTLS_VERSION_MAJOR >= 3
+ else
+ gnutls_certificate_set_x509_system_trust(c->cred);
+#endif
+ gnutls_certificate_set_verify_flags(c->cred, c->verify ?
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0);
+ if (c->cert_file && c->key_file) {
+ ret = gnutls_certificate_set_x509_key_file(c->cred,
+ c->cert_file, c->key_file,
+ GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ av_log(h, AV_LOG_ERROR,
+ "Unable to set cert/key files %s and %s: %s\n",
+ c->cert_file, c->key_file, gnutls_strerror(ret));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ } else if (c->cert_file || c->key_file)
+ av_log(h, AV_LOG_ERROR, "cert and key required\n");
gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t)
(intptr_t) c->fd);
@@ -219,14 +253,66 @@ static int tls_open(URLContext *h, const char *uri, int flags)
if ((ret = do_tls_poll(h, ret)) < 0)
goto fail;
}
+ if (c->verify) {
+ unsigned int status, cert_list_size;
+ gnutls_x509_crt_t cert;
+ const gnutls_datum_t *cert_list;
+ if ((ret = gnutls_certificate_verify_peers2(c->session, &status)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n",
+ gnutls_strerror(ret));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ if (status & GNUTLS_CERT_INVALID) {
+ av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n");
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ if (gnutls_certificate_type_get(c->session) != GNUTLS_CRT_X509) {
+ av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n");
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ gnutls_x509_crt_init(&cert);
+ cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size);
+ gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER);
+ ret = gnutls_x509_crt_check_hostname(cert, host);
+ gnutls_x509_crt_deinit(cert);
+ if (!ret) {
+ av_log(h, AV_LOG_ERROR,
+ "The certificate's owner does not match hostname %s\n", host);
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ }
#elif CONFIG_OPENSSL
- c->ctx = SSL_CTX_new(server ? TLSv1_server_method() : TLSv1_client_method());
+ c->ctx = SSL_CTX_new(c->listen ? TLSv1_server_method() : TLSv1_client_method());
if (!c->ctx) {
av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ret = AVERROR(EIO);
goto fail;
}
set_options(h, uri);
+ if (c->ca_file) {
+ if (!SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL))
+ av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (c->cert_file && !SSL_CTX_use_certificate_chain_file(c->ctx, c->cert_file)) {
+ av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n",
+ c->cert_file, ERR_error_string(ERR_get_error(), NULL));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ if (c->key_file && !SSL_CTX_use_PrivateKey_file(c->ctx, c->key_file, SSL_FILETYPE_PEM)) {
+ av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n",
+ c->key_file, ERR_error_string(ERR_get_error(), NULL));
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ // Note, this doesn't check that the peer certificate actually matches
+ // the requested hostname.
+ if (c->verify)
+ SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
c->ssl = SSL_new(c->ctx);
if (!c->ssl) {
av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
@@ -234,10 +320,10 @@ static int tls_open(URLContext *h, const char *uri, int flags)
goto fail;
}
SSL_set_fd(c->ssl, c->fd);
- if (!server && !numerichost)
+ if (!c->listen && !numerichost)
SSL_set_tlsext_host_name(c->ssl, host);
while (1) {
- ret = server ? SSL_accept(c->ssl) : SSL_connect(c->ssl);
+ ret = c->listen ? SSL_accept(c->ssl) : SSL_connect(c->ssl);
if (ret > 0)
break;
if (ret == 0) {
@@ -306,4 +392,5 @@ URLProtocol ff_tls_protocol = {
.url_close = tls_close,
.priv_data_size = sizeof(TLSContext),
.flags = URL_PROTOCOL_FLAG_NETWORK,
+ .priv_data_class = &tls_class,
};
diff --git a/ffmpeg/libavformat/tta.c b/ffmpeg/libavformat/tta.c
index 445389e..7174fd5 100644
--- a/ffmpeg/libavformat/tta.c
+++ b/ffmpeg/libavformat/tta.c
@@ -20,9 +20,12 @@
*/
#include "libavcodec/get_bits.h"
+#include "apetag.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "id3v1.h"
+#include "libavutil/crc.h"
#include "libavutil/dict.h"
typedef struct {
@@ -31,12 +34,20 @@ typedef struct {
int last_frame_size;
} TTAContext;
-static int tta_probe(AVProbeData *p)
+static unsigned long tta_check_crc(unsigned long checksum, const uint8_t *buf,
+ unsigned int len)
{
- const uint8_t *d = p->buf;
+ return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len);
+}
- if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1')
- return 80;
+static int tta_probe(AVProbeData *p)
+{
+ if (AV_RL32(&p->buf[0]) == MKTAG('T', 'T', 'A', '1') &&
+ (AV_RL16(&p->buf[4]) == 1 || AV_RL16(&p->buf[4]) == 2) &&
+ AV_RL16(&p->buf[6]) > 0 &&
+ AV_RL16(&p->buf[8]) > 0 &&
+ AV_RL32(&p->buf[10]) > 0)
+ return AVPROBE_SCORE_EXTENSION + 30;
return 0;
}
@@ -46,14 +57,14 @@ static int tta_read_header(AVFormatContext *s)
AVStream *st;
int i, channels, bps, samplerate;
uint64_t framepos, start_offset;
- uint32_t datalen;
+ uint32_t nb_samples, crc;
- if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
- ff_id3v1_read(s);
+ ff_id3v1_read(s);
start_offset = avio_tell(s->pb);
+ ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX);
if (avio_rl32(s->pb) != AV_RL32("TTA1"))
- return -1; // not tta file
+ return AVERROR_INVALIDDATA;
avio_skip(s->pb, 2); // FIXME: flags
channels = avio_rl16(s->pb);
@@ -61,27 +72,31 @@ static int tta_read_header(AVFormatContext *s)
samplerate = avio_rl32(s->pb);
if(samplerate <= 0 || samplerate > 1000000){
av_log(s, AV_LOG_ERROR, "nonsense samplerate\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- datalen = avio_rl32(s->pb);
- if (!datalen) {
- av_log(s, AV_LOG_ERROR, "invalid datalen\n");
+ nb_samples = avio_rl32(s->pb);
+ if (!nb_samples) {
+ av_log(s, AV_LOG_ERROR, "invalid number of samples\n");
return AVERROR_INVALIDDATA;
}
- avio_skip(s->pb, 4); // header crc
+ crc = ffio_get_checksum(s->pb) ^ UINT32_MAX;
+ if (crc != avio_rl32(s->pb)) {
+ av_log(s, AV_LOG_ERROR, "Header CRC error\n");
+ return AVERROR_INVALIDDATA;
+ }
c->frame_size = samplerate * 256 / 245;
- c->last_frame_size = datalen % c->frame_size;
+ c->last_frame_size = nb_samples % c->frame_size;
if (!c->last_frame_size)
c->last_frame_size = c->frame_size;
- c->totalframes = datalen / c->frame_size + (c->last_frame_size < c->frame_size);
+ c->totalframes = nb_samples / c->frame_size + (c->last_frame_size < c->frame_size);
c->currentframe = 0;
if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){
av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes);
- return -1;
+ return AVERROR_INVALIDDATA;
}
st = avformat_new_stream(s, NULL);
@@ -90,17 +105,28 @@ static int tta_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, samplerate);
st->start_time = 0;
- st->duration = datalen;
+ st->duration = nb_samples;
framepos = avio_tell(s->pb) + 4*c->totalframes + 4;
+ if (ff_alloc_extradata(st->codec, avio_tell(s->pb) - start_offset))
+ return AVERROR(ENOMEM);
+
+ avio_seek(s->pb, start_offset, SEEK_SET);
+ avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
+
+ ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX);
for (i = 0; i < c->totalframes; i++) {
uint32_t size = avio_rl32(s->pb);
av_add_index_entry(st, framepos, i * c->frame_size, size, 0,
AVINDEX_KEYFRAME);
framepos += size;
}
- avio_skip(s->pb, 4); // seektable crc
+ crc = ffio_get_checksum(s->pb) ^ UINT32_MAX;
+ if (crc != avio_rl32(s->pb)) {
+ av_log(s, AV_LOG_ERROR, "Seek table CRC error\n");
+ return AVERROR_INVALIDDATA;
+ }
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_TTA;
@@ -108,19 +134,11 @@ static int tta_read_header(AVFormatContext *s)
st->codec->sample_rate = samplerate;
st->codec->bits_per_coded_sample = bps;
- st->codec->extradata_size = avio_tell(s->pb) - start_offset;
- if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){
- //this check is redundant as avio_read should fail
- av_log(s, AV_LOG_ERROR, "extradata_size too large\n");
- return -1;
- }
- st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
- st->codec->extradata_size = 0;
- return AVERROR(ENOMEM);
+ if (s->pb->seekable) {
+ int64_t pos = avio_tell(s->pb);
+ ff_ape_parse_tag(s);
+ avio_seek(s->pb, pos, SEEK_SET);
}
- avio_seek(s->pb, start_offset, SEEK_SET);
- avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
diff --git a/ffmpeg/libavformat/tty.c b/ffmpeg/libavformat/tty.c
index 9b3fa0a..3afb9b2 100644
--- a/ffmpeg/libavformat/tty.c
+++ b/ffmpeg/libavformat/tty.c
@@ -38,8 +38,8 @@ typedef struct {
AVClass *class;
int chars_per_frame;
uint64_t fsize; /**< file size less metadata buffer */
- char *video_size;/**< A string describing video size, set by a private option. */
- char *framerate; /**< Set by a private option. */
+ int width, height; /**< Set by a private option. */
+ AVRational framerate; /**< Set by a private option. */
} TtyDemuxContext;
/**
@@ -75,9 +75,8 @@ static int efi_read(AVFormatContext *avctx, uint64_t start_pos)
static int read_header(AVFormatContext *avctx)
{
TtyDemuxContext *s = avctx->priv_data;
- int width = 0, height = 0, ret = 0;
+ int ret = 0;
AVStream *st = avformat_new_stream(avctx, NULL);
- AVRational framerate;
if (!st) {
ret = AVERROR(ENOMEM);
@@ -87,18 +86,10 @@ static int read_header(AVFormatContext *avctx)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_ANSI;
- if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log (avctx, AV_LOG_ERROR, "Couldn't parse video size.\n");
- goto fail;
- }
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate);
- goto fail;
- }
- st->codec->width = width;
- st->codec->height = height;
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
- st->avg_frame_rate = framerate;
+ st->codec->width = s->width;
+ st->codec->height = s->height;
+ avpriv_set_pts_info(st, 60, s->framerate.den, s->framerate.num);
+ st->avg_frame_rate = s->framerate;
/* simulate tty display speed */
s->chars_per_frame = FFMAX(av_q2d(st->time_base)*s->chars_per_frame, 1);
@@ -146,8 +137,8 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{ "chars_per_frame", "", offsetof(TtyDemuxContext, chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ NULL },
};
diff --git a/ffmpeg/libavformat/udp.c b/ffmpeg/libavformat/udp.c
index e8a01db..047ff7c 100644
--- a/ffmpeg/libavformat/udp.c
+++ b/ffmpeg/libavformat/udp.c
@@ -84,23 +84,24 @@ 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 },
+{"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 +141,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 +173,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;
@@ -237,7 +244,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr,
int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
SOCK_DGRAM, AF_UNSPEC,
- AI_NUMERICHOST);
+ 0);
if (!sourceaddr)
return AVERROR(ENOENT);
@@ -267,7 +274,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr,
struct ip_mreq_source mreqs;
struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
SOCK_DGRAM, AF_UNSPEC,
- AI_NUMERICHOST);
+ 0);
if (!sourceaddr)
return AVERROR(ENOENT);
if (sourceaddr->ai_addr->sa_family != AF_INET) {
@@ -326,7 +333,7 @@ static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr,
if (res0 == 0)
goto fail;
for (res = res0; res; res=res->ai_next) {
- udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
+ udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0);
if (udp_fd != -1) break;
log_net_error(NULL, AV_LOG_ERROR, "socket");
}
@@ -494,6 +501,27 @@ end:
}
#endif
+static int parse_source_list(char *buf, char **sources, int *num_sources,
+ int max_sources)
+{
+ char *source_start;
+
+ source_start = buf;
+ while (1) {
+ char *next = strchr(source_start, ',');
+ if (next)
+ *next = '\0';
+ sources[*num_sources] = av_strdup(source_start);
+ if (!sources[*num_sources])
+ return AVERROR(ENOMEM);
+ source_start = next + 1;
+ (*num_sources)++;
+ if (*num_sources >= max_sources || !next)
+ break;
+ }
+ return 0;
+}
+
/* put it in UDP context */
/* return non zero if error */
static int udp_open(URLContext *h, const char *uri, int flags)
@@ -507,8 +535,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
struct sockaddr_storage my_addr;
socklen_t len;
int reuse_specified = 0;
- int i, include = 0, num_sources = 0;
- char *sources[32];
+ int i, num_include_sources = 0, num_exclude_sources = 0;
+ char *include_sources[32], *exclude_sources[32];
h->is_streamed = 1;
@@ -562,31 +590,26 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
av_strlcpy(localaddr, buf, sizeof(localaddr));
}
- if (av_find_info_tag(buf, sizeof(buf), "sources", p))
- include = 1;
- if (include || av_find_info_tag(buf, sizeof(buf), "block", p)) {
- char *source_start;
-
- source_start = buf;
- while (1) {
- char *next = strchr(source_start, ',');
- if (next)
- *next = '\0';
- sources[num_sources] = av_strdup(source_start);
- if (!sources[num_sources])
- goto fail;
- source_start = next + 1;
- num_sources++;
- if (num_sources >= FF_ARRAY_ELEMS(sources) || !next)
- break;
- }
+ if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
+ if (parse_source_list(buf, include_sources, &num_include_sources,
+ FF_ARRAY_ELEMS(include_sources)))
+ goto fail;
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
+ if (parse_source_list(buf, exclude_sources, &num_exclude_sources,
+ FF_ARRAY_ELEMS(exclude_sources)))
+ goto fail;
}
if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p))
s->timeout = strtol(buf, NULL, 10);
}
/* handling needed to support options picking from both AVOption and URL */
s->circular_buffer_size *= 188;
- h->max_packet_size = s->packet_size;
+ if (flags & AVIO_FLAG_WRITE) {
+ h->max_packet_size = s->packet_size;
+ } else {
+ h->max_packet_size = UDP_MAX_PKT_SIZE;
+ }
h->rw_timeout = s->timeout;
/* fill the dest addr */
@@ -608,6 +631,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.
*/
@@ -644,20 +669,20 @@ static int udp_open(URLContext *h, const char *uri, int flags)
}
if (h->flags & AVIO_FLAG_READ) {
/* input */
- if (num_sources == 0 || !include) {
- if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
- goto fail;
-
- if (num_sources) {
- if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 0) < 0)
- goto fail;
- }
- } else if (include && num_sources) {
- if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 1) < 0)
+ if (num_include_sources && num_exclude_sources) {
+ av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n");
+ goto fail;
+ }
+ if (num_include_sources) {
+ 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 {
- av_log(NULL, AV_LOG_ERROR, "invalid udp settings: inclusive multicast but no sources given\n");
- goto fail;
+ 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) {
+ if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0)
+ goto fail;
}
}
}
@@ -686,8 +711,10 @@ static int udp_open(URLContext *h, const char *uri, int flags)
}
}
- for (i = 0; i < num_sources; i++)
- av_freep(&sources[i]);
+ for (i = 0; i < num_include_sources; i++)
+ av_freep(&include_sources[i]);
+ for (i = 0; i < num_exclude_sources; i++)
+ av_freep(&exclude_sources[i]);
s->udp_fd = udp_fd;
@@ -727,8 +754,10 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (udp_fd >= 0)
closesocket(udp_fd);
av_fifo_free(s->fifo);
- for (i = 0; i < num_sources; i++)
- av_freep(&sources[i]);
+ for (i = 0; i < num_include_sources; i++)
+ av_freep(&include_sources[i]);
+ for (i = 0; i < num_exclude_sources; i++)
+ av_freep(&exclude_sources[i]);
return AVERROR(EIO);
}
@@ -818,7 +847,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) {
diff --git a/ffmpeg/libavformat/url-test.c b/ffmpeg/libavformat/url-test.c
index ee5f06e..a1da82e 100644
--- a/ffmpeg/libavformat/url-test.c
+++ b/ffmpeg/libavformat/url-test.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "internal.h"
+#include "url.h"
static void test(const char *base, const char *rel)
{
diff --git a/ffmpeg/libavformat/url.h b/ffmpeg/libavformat/url.h
index 5f75dc9..712ea0f 100644
--- a/ffmpeg/libavformat/url.h
+++ b/ffmpeg/libavformat/url.h
@@ -101,7 +101,7 @@ typedef struct URLProtocol {
* is to be opened
* @param int_cb interrupt callback to use for the URLContext, may be
* NULL
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
@@ -130,7 +130,7 @@ int ffurl_connect(URLContext *uc, AVDictionary **options);
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_open(URLContext **puc, const char *filename, int flags,
@@ -226,10 +226,8 @@ int ffurl_shutdown(URLContext *h, int flags);
/**
* Register the URLProtocol protocol.
- *
- * @param size the size of the URLProtocol struct referenced
*/
-int ffurl_register_protocol(URLProtocol *protocol, int size);
+int ffurl_register_protocol(URLProtocol *protocol);
/**
* Check if the user has requested to interrup a blocking function
@@ -248,4 +246,41 @@ URLProtocol *ffurl_protocol_next(URLProtocol *prev);
int ff_udp_set_remote_url(URLContext *h, const char *uri);
int ff_udp_get_local_port(URLContext *h);
+/**
+ * Assemble a URL string from components. This is the reverse operation
+ * of av_url_split.
+ *
+ * Note, this requires networking to be initialized, so the caller must
+ * ensure ff_network_init has been called.
+ *
+ * @see av_url_split
+ *
+ * @param str the buffer to fill with the url
+ * @param size the size of the str buffer
+ * @param proto the protocol identifier, if null, the separator
+ * after the identifier is left out, too
+ * @param authorization an optional authorization string, may be null.
+ * An empty string is treated the same as a null string.
+ * @param hostname the host name string
+ * @param port the port number, left out from the string if negative
+ * @param fmt a generic format string for everything to add after the
+ * host/port, may be null
+ * @return the number of characters written to the destination buffer
+ */
+int ff_url_join(char *str, int size, const char *proto,
+ const char *authorization, const char *hostname,
+ int port, const char *fmt, ...) av_printf_format(7, 8);
+
+/**
+ * Convert a relative url into an absolute url, given a base url.
+ *
+ * @param buf the buffer where output absolute url is written
+ * @param size the size of buf
+ * @param base the base url, may be equal to buf.
+ * @param rel the new url, which is interpreted relative to base
+ */
+void ff_make_absolute_url(char *buf, int size, const char *base,
+ const char *rel);
+
+
#endif /* AVFORMAT_URL_H */
diff --git a/ffmpeg/libavformat/utils.c b/ffmpeg/libavformat/utils.c
index f9acc0e..40d886f 100644
--- a/ffmpeg/libavformat/utils.c
+++ b/ffmpeg/libavformat/utils.c
@@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/* #define DEBUG */
+#include <stdint.h>
#include "avformat.h"
#include "avio_internal.h"
@@ -27,9 +27,9 @@
#include "libavcodec/internal.h"
#include "libavcodec/raw.h"
#include "libavcodec/bytestream.h"
-#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
+#include "libavutil/internal.h"
#include "libavutil/pixdesc.h"
#include "metadata.h"
#include "id3v2.h"
@@ -99,156 +99,34 @@ static int64_t wrap_timestamp(AVStream *st, int64_t timestamp)
return timestamp;
}
-#define MAKE_ACCESSORS(str, name, type, field) \
- type av_##name##_get_##field(const str *s) { return s->field; } \
- void av_##name##_set_##field(str *s, type v) { s->field = v; }
-
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)
-/** head of registered input format linked list */
-static AVInputFormat *first_iformat = NULL;
-/** head of registered output format linked list */
-static AVOutputFormat *first_oformat = NULL;
-
-AVInputFormat *av_iformat_next(AVInputFormat *f)
-{
- if(f) return f->next;
- else return first_iformat;
-}
-
-AVOutputFormat *av_oformat_next(AVOutputFormat *f)
-{
- if(f) return f->next;
- else return first_oformat;
-}
-
-void av_register_input_format(AVInputFormat *format)
-{
- AVInputFormat **p;
- p = &first_iformat;
- while (*p != NULL) p = &(*p)->next;
- *p = format;
- format->next = NULL;
-}
-
-void av_register_output_format(AVOutputFormat *format)
-{
- AVOutputFormat **p;
- p = &first_oformat;
- while (*p != NULL) p = &(*p)->next;
- *p = format;
- format->next = NULL;
-}
-
-int av_match_ext(const char *filename, const char *extensions)
+static AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id)
{
- const char *ext, *p;
- char ext1[32], *q;
-
- if(!filename)
- return 0;
+ if (st->codec->codec)
+ return st->codec->codec;
- ext = strrchr(filename, '.');
- if (ext) {
- ext++;
- p = extensions;
- for(;;) {
- q = ext1;
- while (*p != '\0' && *p != ',' && q-ext1<sizeof(ext1)-1)
- *q++ = *p++;
- *q = '\0';
- if (!av_strcasecmp(ext1, ext))
- return 1;
- if (*p == '\0')
- break;
- p++;
- }
- }
- return 0;
-}
-
-static int match_format(const char *name, const char *names)
-{
- const char *p;
- int len, namelen;
-
- if (!name || !names)
- return 0;
-
- namelen = strlen(name);
- while ((p = strchr(names, ','))) {
- len = FFMAX(p - names, namelen);
- if (!av_strncasecmp(name, names, len))
- return 1;
- names = p+1;
- }
- return !av_strcasecmp(name, names);
-}
-
-AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
- const char *mime_type)
-{
- AVOutputFormat *fmt = NULL, *fmt_found;
- int score_max, score;
-
- /* specific test for image sequences */
-#if CONFIG_IMAGE2_MUXER
- if (!short_name && filename &&
- av_filename_number_test(filename) &&
- ff_guess_image2_codec(filename) != AV_CODEC_ID_NONE) {
- return av_guess_format("image2", NULL, NULL);
- }
-#endif
- /* Find the proper file type. */
- fmt_found = NULL;
- score_max = 0;
- while ((fmt = av_oformat_next(fmt))) {
- score = 0;
- if (fmt->name && short_name && match_format(short_name, fmt->name))
- score += 100;
- if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
- score += 10;
- if (filename && fmt->extensions &&
- av_match_ext(filename, fmt->extensions)) {
- score += 5;
- }
- if (score > score_max) {
- score_max = score;
- fmt_found = fmt;
- }
+ switch(st->codec->codec_type){
+ case AVMEDIA_TYPE_VIDEO:
+ if(s->video_codec) return s->video_codec;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if(s->audio_codec) return s->audio_codec;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if(s->subtitle_codec) return s->subtitle_codec;
+ break;
}
- return fmt_found;
-}
-
-enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
- const char *filename, const char *mime_type, enum AVMediaType type){
- if(type == AVMEDIA_TYPE_VIDEO){
- enum AVCodecID codec_id= AV_CODEC_ID_NONE;
-#if CONFIG_IMAGE2_MUXER
- if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){
- codec_id= ff_guess_image2_codec(filename);
- }
-#endif
- if(codec_id == AV_CODEC_ID_NONE)
- codec_id= fmt->video_codec;
- return codec_id;
- }else if(type == AVMEDIA_TYPE_AUDIO)
- return fmt->audio_codec;
- else if (type == AVMEDIA_TYPE_SUBTITLE)
- return fmt->subtitle_codec;
- else
- return AV_CODEC_ID_NONE;
+ return avcodec_find_decoder(codec_id);
}
-AVInputFormat *av_find_input_format(const char *short_name)
+int av_format_get_probe_score(const AVFormatContext *s)
{
- AVInputFormat *fmt = NULL;
- while ((fmt = av_iformat_next(fmt))) {
- if (match_format(short_name, fmt->name))
- return fmt;
- }
- return NULL;
+ return s->probe_score;
}
/* an arbitrarily chosen "sane" max packet size -- 50M */
@@ -280,7 +158,7 @@ int ffio_limit(AVIOContext *s, int size)
*/
static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
{
- int orig_pos = pkt->pos; // av_grow_packet might reset pos
+ int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos
int orig_size = pkt->size;
int ret;
@@ -372,10 +250,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score
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_MAX/4-1 : 1);
+ score = FFMAX(score, nodat ? AVPROBE_SCORE_EXTENSION / 2 - 1 : 1);
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions)) {
- score = 50;
+ score = AVPROBE_SCORE_EXTENSION;
}
}
if (score > score_max) {
@@ -384,6 +262,8 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score
}else if (score == score_max)
fmt = NULL;
}
+ if(nodat)
+ score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
*score_ret= score_max;
return fmt;
@@ -458,11 +338,7 @@ int av_demuxer_open(AVFormatContext *ic){
}
-/** size of probe buffer, for guessing file type from file contents */
-#define PROBE_BUF_MIN 2048
-#define PROBE_BUF_MAX (1<<20)
-
-int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
+int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
const char *filename, void *logctx,
unsigned int offset, unsigned int max_probe_size)
{
@@ -470,6 +346,7 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
unsigned char *buf = NULL;
uint8_t *mime_type;
int ret = 0, probe_size, buf_offset = 0;
+ int score = 0;
if (!max_probe_size) {
max_probe_size = PROBE_BUF_MAX;
@@ -494,20 +371,15 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
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))) {
- int score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
- void *buftmp;
if (probe_size < offset) {
continue;
}
+ score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
/* read probe data */
- buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
- if(!buftmp){
- av_free(buf);
- return AVERROR(ENOMEM);
- }
- buf=buftmp;
+ 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 != AVERROR_EOF) {
@@ -529,6 +401,11 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
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);
+ fclose(f);
+#endif
}
}
@@ -540,9 +417,18 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
/* rewind. reuse probe buffer to avoid seeking */
ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size);
- return ret;
+ return ret < 0 ? ret : score;
}
+int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
+ const char *filename, void *logctx,
+ unsigned int offset, unsigned int max_probe_size)
+{
+ int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size);
+ 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)
{
@@ -553,7 +439,7 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
- return av_probe_input_buffer(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");
@@ -562,14 +448,14 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o
if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
- return 0;
+ return score;
if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
&s->interrupt_callback, options)) < 0)
return ret;
if (s->iformat)
return 0;
- return av_probe_input_buffer(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,
@@ -629,6 +515,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
+ s->probe_score = ret;
avio_skip(s->pb, s->skip_initial_bytes);
/* check filename in case an image number is expected */
@@ -665,7 +552,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
goto fail;
if (id3v2_extra_meta) {
- if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac")) {
+ 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)
goto fail;
} else
@@ -715,7 +603,7 @@ static void force_codec_ids(AVFormatContext *s, AVStream *st)
}
}
-static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
+static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
{
if(st->request_probe>0){
AVProbeData *pd = &st->probe_data;
@@ -725,8 +613,12 @@ static void 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);
pd->buf_size += pkt->size;
@@ -758,11 +650,76 @@ no_packet:
force_codec_ids(s, st);
}
}
+ return 0;
+}
+
+static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt)
+{
+ int64_t ref = pkt->dts;
+ int i, pts_wrap_behavior;
+ int64_t pts_wrap_reference;
+ AVProgram *first_program;
+
+ if (ref == AV_NOPTS_VALUE)
+ 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;
+
+ // 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)) ?
+ AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
+
+ first_program = av_find_program_from_stream(s, NULL, stream_index);
+
+ 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++) {
+ s->streams[i]->pts_wrap_reference = pts_wrap_reference;
+ s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
+ }
+ }
+ else {
+ st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
+ st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
+ }
+ }
+ else {
+ AVProgram *program = first_program;
+ while (program) {
+ if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
+ pts_wrap_reference = program->pts_wrap_reference;
+ pts_wrap_behavior = program->pts_wrap_behavior;
+ break;
+ }
+ program = av_find_program_from_stream(s, program, stream_index);
+ }
+
+ // update every program with differing pts_wrap_reference
+ program = first_program;
+ while(program) {
+ if (program->pts_wrap_reference != pts_wrap_reference) {
+ 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;
+ }
+
+ program->pts_wrap_reference = pts_wrap_reference;
+ program->pts_wrap_behavior = pts_wrap_behavior;
+ }
+ program = av_find_program_from_stream(s, program, stream_index);
+ }
+ }
+ return 1;
}
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
- int ret, i;
+ int ret, i, err;
AVStream *st;
for(;;){
@@ -771,8 +728,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (pktl) {
*pkt = pktl->pkt;
st = s->streams[pkt->stream_index];
- if (s->raw_packet_buffer_remaining_size <= 0)
- probe_codec(s, st, NULL);
+ 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;
s->raw_packet_buffer_remaining_size += pkt->size;
@@ -791,7 +750,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if (st->probe_packets) {
- probe_codec(s, st, NULL);
+ if ((err = probe_codec(s, st, NULL)) < 0)
+ return err;
}
av_assert0(st->request_probe <= 0);
}
@@ -807,15 +767,23 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
continue;
}
- if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))
- av_packet_merge_side_data(pkt);
-
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];
+
+ 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
+ if (!is_relative(st->first_dts))
+ st->first_dts = wrap_timestamp(st, st->first_dts);
+ if (!is_relative(st->start_time))
+ st->start_time = wrap_timestamp(st, st->start_time);
+ if (!is_relative(st->cur_dts))
+ st->cur_dts = wrap_timestamp(st, st->cur_dts);
+ }
+
pkt->dts = wrap_timestamp(st, pkt->dts);
pkt->pts = wrap_timestamp(st, pkt->pts);
@@ -831,7 +799,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
s->raw_packet_buffer_remaining_size -= pkt->size;
- probe_codec(s, st, pkt);
+ if ((err = probe_codec(s, st, pkt)) < 0)
+ return err;
}
}
@@ -870,7 +839,7 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux)
if ((frame_size = av_get_audio_frame_duration(enc, size)) > 0)
return frame_size;
- /* fallback to using frame_size if muxing */
+ /* Fall back on using frame_size if muxing. */
if (enc->frame_size > 1)
return enc->frame_size;
@@ -950,7 +919,7 @@ 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 wont increase anymore for stream copy
+ 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 &&
@@ -974,65 +943,6 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList
return NULL;
}
-static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
-{
- if (s->correct_ts_overflow && st->pts_wrap_bits < 63 &&
- st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
- int i;
-
- // reference time stamp should be 60 s before first time stamp
- int64_t pts_wrap_reference = st->first_dts - 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
- int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
- (st->first_dts < (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;
-
- AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index);
-
- 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++) {
- s->streams[i]->pts_wrap_reference = pts_wrap_reference;
- s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
- }
- }
- else {
- st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
- st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
- }
- }
- else {
- AVProgram *program = first_program;
- while (program) {
- if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
- pts_wrap_reference = program->pts_wrap_reference;
- pts_wrap_behavior = program->pts_wrap_behavior;
- break;
- }
- program = av_find_program_from_stream(s, program, stream_index);
- }
-
- // update every program with differing pts_wrap_reference
- program = first_program;
- while(program) {
- if (program->pts_wrap_reference != pts_wrap_reference) {
- 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;
- }
-
- program->pts_wrap_reference = pts_wrap_reference;
- program->pts_wrap_behavior = pts_wrap_behavior;
- }
- program = av_find_program_from_stream(s, program, stream_index);
- }
- }
- return 1;
- }
- return 0;
-}
-
static void update_initial_timestamps(AVFormatContext *s, int stream_index,
int64_t dts, int64_t pts, AVPacket *pkt)
{
@@ -1077,15 +987,6 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
}
}
- if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
- // correct first time stamps to negative values
- st->first_dts = wrap_timestamp(st, st->first_dts);
- st->cur_dts = wrap_timestamp(st, st->cur_dts);
- pkt->dts = wrap_timestamp(st, pkt->dts);
- pkt->pts = wrap_timestamp(st, pkt->pts);
- pts = wrap_timestamp(st, pts);
- }
-
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = pts;
}
@@ -1106,7 +1007,8 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st,
}
}
if(pktl && pktl->pkt.dts != st->first_dts) {
- av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s in the queue\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.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) {
@@ -1148,7 +1050,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts= AV_NOPTS_VALUE;
- if (st->codec->codec_id != AV_CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B)
+ if (pc && pc->pict_type == AV_PICTURE_TYPE_B
+ && !st->codec->has_b_frames)
//FIXME Set low_delay = 0 when has_b_frames = 1
st->codec->has_b_frames = 1;
@@ -1162,7 +1065,9 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
- 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 (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;
} else
@@ -1174,7 +1079,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
// 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){
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
+ 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;
}
@@ -1198,25 +1104,6 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pkt->dts += offset;
}
- if (pc && pc->dts_sync_point >= 0) {
- // we have synchronization info from the parser
- int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num;
- if (den > 0) {
- int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den;
- if (pkt->dts != AV_NOPTS_VALUE) {
- // got DTS from the stream, update reference timestamp
- st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den;
- pkt->pts = pkt->dts + pc->pts_dts_delta * num / den;
- } else if (st->reference_dts != AV_NOPTS_VALUE) {
- // compute DTS based on reference timestamp
- pkt->dts = st->reference_dts + pc->dts_ref_dts_delta * num / den;
- pkt->pts = pkt->dts + pc->pts_dts_delta * num / den;
- }
- if (pc->dts_sync_point > 0)
- st->reference_dts = pkt->dts; // new reference
- }
- }
-
/* This may be redundant, but it should not hurt. */
if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts)
presentation_delayed = 1;
@@ -1338,6 +1225,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
if (!out_pkt.size)
continue;
+ 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;
+ }
+
/* set the duration */
out_pkt.duration = 0;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -1377,8 +1271,10 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
out_pkt.buf = pkt->buf;
pkt->buf = NULL;
#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
out_pkt.destruct = pkt->destruct;
pkt->destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
#endif
}
if ((ret = av_dup_packet(&out_pkt)) < 0)
@@ -1502,6 +1398,9 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
st->skip_to_keyframe = 0;
if (st->skip_to_keyframe) {
av_free_packet(&cur_pkt);
+ if (got_packet) {
+ *pkt = cur_pkt;
+ }
got_packet = 0;
}
}
@@ -1509,6 +1408,21 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
if (!got_packet && s->parse_queue)
ret = read_from_packet_buffer(&s->parse_queue, &s->parse_queue_end, pkt);
+ if (ret >= 0) {
+ AVStream *st = s->streams[pkt->stream_index];
+ if (st->skip_samples) {
+ uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+ if (p) {
+ AV_WL32(p, st->skip_samples);
+ av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);
+ }
+ st->skip_samples = 0;
+ }
+ }
+
+ if(ret >= 0 && !(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,
@@ -1598,13 +1512,6 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
return_packet:
st = s->streams[pkt->stream_index];
- if (st->skip_samples) {
- uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
- AV_WL32(p, st->skip_samples);
- av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);
- st->skip_samples = 0;
- }
-
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
ff_reduce_index(s, st->index);
av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
@@ -1672,7 +1579,6 @@ void ff_read_frame_flush(AVFormatContext *s)
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->reference_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
@@ -1721,6 +1627,9 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
if(timestamp == AV_NOPTS_VALUE)
return AVERROR(EINVAL);
+ if (size < 0 || size > 0x3FFFFFFF)
+ return AVERROR(EINVAL);
+
if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
timestamp -= RELATIVE_TS_BASE;
@@ -1738,7 +1647,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
if(index<0){
index= (*nb_index_entries)++;
ie= &entries[index];
- assert(index==0 || ie[-1].timestamp < timestamp);
+ av_assert0(index==0 || ie[-1].timestamp < timestamp);
}else{
ie= &entries[index];
if(ie->timestamp != timestamp){
@@ -1850,14 +1759,14 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
av_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
pos_min, av_ts2str(ts_min));
}else{
- assert(index==0);
+ av_assert1(index==0);
}
index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD);
- assert(index < st->nb_index_entries);
+ av_assert0(index < st->nb_index_entries);
if(index >= 0){
e= &st->index_entries[index];
- assert(e->timestamp >= target_ts);
+ av_assert1(e->timestamp >= target_ts);
pos_max= e->pos;
ts_max= e->timestamp;
pos_limit= pos_max - e->min_distance;
@@ -1880,14 +1789,51 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts
return 0;
}
+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 limit, ts_max;
+ int64_t filesize = avio_size(s->pb);
+ 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);
+ if (ts_max == AV_NOPTS_VALUE)
+ return -1;
+
+ 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)
+ break;
+ av_assert0(tmp_pos > pos_max);
+ ts_max = tmp_ts;
+ pos_max = tmp_pos;
+ if(tmp_pos >= filesize)
+ break;
+ }
+
+ if (ts)
+ *ts = ts_max;
+ if (pos)
+ *pos = pos_max;
+
+ return 0;
+}
+
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 pos, ts;
- int64_t start_pos, filesize;
+ int64_t start_pos;
int no_change;
+ int ret;
av_dlog(s, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
@@ -1904,27 +1850,8 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
}
if(ts_max == AV_NOPTS_VALUE){
- int step= 1024;
- filesize = avio_size(s->pb);
- pos_max = filesize - 1;
- do{
- pos_max = FFMAX(0, pos_max - step);
- ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp);
- step += step;
- }while(ts_max == AV_NOPTS_VALUE && pos_max > 0);
- if (ts_max == AV_NOPTS_VALUE)
- return -1;
-
- 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)
- break;
- ts_max= tmp_ts;
- pos_max= tmp_pos;
- if(tmp_pos >= filesize)
- break;
- }
+ if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0)
+ return ret;
pos_limit= pos_max;
}
@@ -2014,6 +1941,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, in
avio_seek(s->pb, pos, SEEK_SET);
+ s->io_repositioned = 1;
+
return 0;
}
@@ -2037,7 +1966,7 @@ static int seek_frame_generic(AVFormatContext *s,
int nonkey=0;
if(st->nb_index_entries){
- assert(st->index_entries);
+ av_assert0(st->index_entries);
ie= &st->index_entries[st->nb_index_entries-1];
if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
return ret;
@@ -2127,7 +2056,19 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index,
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
- int ret = seek_frame_internal(s, stream_index, timestamp, flags);
+ int ret;
+
+ if (s->iformat->read_seek2 && !s->iformat->read_seek) {
+ int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
+ if ((flags & AVSEEK_FLAG_BACKWARD))
+ max_ts = timestamp;
+ else
+ min_ts = timestamp;
+ return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
+ flags & ~AVSEEK_FLAG_BACKWARD);
+ }
+
+ ret = seek_frame_internal(s, stream_index, timestamp, flags);
if (ret >= 0)
ret = avformat_queue_attached_pictures(s);
@@ -2144,6 +2085,7 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
if(s->seek2any>0)
flags |= AVSEEK_FLAG_ANY;
+ flags &= ~AVSEEK_FLAG_BACKWARD;
if (s->iformat->read_seek2) {
int ret;
@@ -2171,8 +2113,8 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
//try to seek via read_timestamp()
}
- //Fallback to old API if new is not implemented but old is
- //Note the old has somewhat different semantics
+ // Fall back on old API if new is not implemented but old is.
+ // Note the old API has somewhat different semantics.
if (s->iformat->read_seek || 1) {
int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
int ret = av_seek_frame(s, stream_index, ts, flags | dir);
@@ -2304,16 +2246,21 @@ static void fill_all_stream_timings(AVFormatContext *ic)
static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
int64_t filesize, duration;
- int bit_rate, i;
+ int i, show_warning = 0;
AVStream *st;
/* if bit_rate is already set, we believe it */
if (ic->bit_rate <= 0) {
- bit_rate = 0;
+ int bit_rate = 0;
for(i=0;i<ic->nb_streams;i++) {
st = ic->streams[i];
- if (st->codec->bit_rate > 0)
- bit_rate += st->codec->bit_rate;
+ if (st->codec->bit_rate > 0) {
+ if (INT_MAX - st->codec->bit_rate < bit_rate) {
+ bit_rate = 0;
+ break;
+ }
+ bit_rate += st->codec->bit_rate;
+ }
}
ic->bit_rate = bit_rate;
}
@@ -2325,12 +2272,17 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic)
if (filesize > 0) {
for(i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
- duration= av_rescale(8*filesize, st->time_base.den, ic->bit_rate*(int64_t)st->time_base.num);
- if (st->duration == AV_NOPTS_VALUE)
+ 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);
st->duration = duration;
+ show_warning = 1;
+ }
}
}
}
+ if (show_warning)
+ av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n");
}
#define DURATION_MAX_READ_SIZE 250000LL
@@ -2410,7 +2362,6 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
st= ic->streams[i];
st->cur_dts= st->first_dts;
st->last_IP_pts = AV_NOPTS_VALUE;
- st->reference_dts = AV_NOPTS_VALUE;
}
}
@@ -2438,7 +2389,6 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
fill_all_stream_timings(ic);
ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM;
} else {
- av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n");
/* less precise: use bitrate info */
estimate_timings_from_bit_rate(ic);
ic->duration_estimation_method = AVFMT_DURATION_FROM_BITRATE;
@@ -2507,11 +2457,11 @@ 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(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;
- AVFrame *frame = avcodec_alloc_frame();
+ AVFrame *frame = av_frame_alloc();
AVSubtitle subtitle;
AVPacket pkt = *avpkt;
@@ -2521,8 +2471,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
if (!avcodec_is_open(st->codec) && !st->info->found_decoder) {
AVDictionary *thread_opt = NULL;
- codec = st->codec->codec ? st->codec->codec :
- avcodec_find_decoder(st->codec->codec_id);
+ codec = find_decoder(s, st, st->codec->codec_id);
if (!codec) {
st->info->found_decoder = -1;
@@ -2555,7 +2504,6 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
!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) {
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_decode_video2(st->codec, frame,
@@ -2585,7 +2533,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option
ret = -1;
fail:
- avcodec_free_frame(&frame);
+ av_frame_free(&frame);
return ret;
}
@@ -2733,9 +2681,158 @@ int av_find_stream_info(AVFormatContext *ic)
}
#endif
+int ff_alloc_extradata(AVCodecContext *avctx, int size)
+{
+ int ret;
+
+ if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+ avctx->extradata_size = 0;
+ return AVERROR(EINVAL);
+ }
+ avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (avctx->extradata) {
+ memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ avctx->extradata_size = size;
+ ret = 0;
+ } else {
+ avctx->extradata_size = 0;
+ ret = AVERROR(ENOMEM);
+ }
+ 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 (!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)
+// av_log(NULL, AV_LOG_ERROR, "%f\n", dts);
+ 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);
+ double error= sdts - ticks + j*0.5;
+ st->info->duration_error[j][0][i] += error;
+ st->info->duration_error[j][1][i] += error*error;
+ }
+ }
+ }
+ 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++) {
+ 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;
+ double a1 = st->info->duration_error[1][0][i] / n;
+ double error1 = st->info->duration_error[1][1][i] / n - a1*a1;
+ if (error0 > 0.04 && error1 > 0.04) {
+ st->info->duration_error[0][1][i] = 2e10;
+ st->info->duration_error[1][1][i] = 2e10;
+ }
+ }
+ }
+ }
+
+ // ignore the first 4 values, they might have some random jitter
+ if (st->info->duration_count > 3 && is_relative(ts) == is_relative(last))
+ st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
+ }
+ if (ts != AV_NOPTS_VALUE)
+ st->info->last_dts = ts;
+
+ return 0;
+}
+
+void ff_rfps_calculate(AVFormatContext *ic)
+{
+ int i, j;
+
+ for (i = 0; i<ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+
+ if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+ // the check for tb_unreliable() is not completely correct, since this is not about handling
+ // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
+ // ipmovie.c produces.
+ if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
+ if (st->info->duration_count>1 && !st->r_frame_rate.num
+ && tb_unreliable(st->codec)) {
+ int num = 0;
+ double best_error= 0.01;
+
+ 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))
+ continue;
+ 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;
+ 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){
+ best_error= error;
+ num = get_std_framerate(j);
+ }
+ 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)))
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
+ }
+
+ av_freep(&st->info->duration_error);
+ st->info->last_dts = AV_NOPTS_VALUE;
+ st->info->duration_count = 0;
+ st->info->rfps_duration_sum = 0;
+ }
+}
+
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
- int i, count, ret, j;
+ int i, count, ret = 0, j;
int64_t read_size;
AVStream *st;
AVPacket pkt1, *pkt;
@@ -2744,7 +2841,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
int flush_codecs = ic->probesize > 0;
if(ic->pb)
- av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(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++) {
const AVCodec *codec;
@@ -2773,8 +2871,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
avcodec_get_name(st->codec->codec_id));
}
}
- codec = st->codec->codec ? st->codec->codec :
- avcodec_find_decoder(st->codec->codec_id);
+ 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 */
@@ -2782,15 +2879,16 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
/* 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
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);
@@ -2859,7 +2957,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
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]->info->duration_count <= 1 &&
+ strcmp(ic->iformat->name, "image2"))
av_log(ic, AV_LOG_WARNING,
"Stream #%d: not enough frames to estimate rate; "
"consider increasing probesize\n", i);
@@ -2877,18 +2976,23 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
break;
}
- if (ic->flags & AVFMT_FLAG_NOBUFFER) {
- pkt = &pkt1;
- } else {
+ if (ic->flags & AVFMT_FLAG_NOBUFFER)
+ free_packet_buffer(&ic->packet_buffer, &ic->packet_buffer_end);
+ {
pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1,
&ic->packet_buffer_end);
+ if (!pkt) {
+ ret = AVERROR(ENOMEM);
+ goto find_stream_info_err;
+ }
if ((ret = av_dup_packet(pkt)) < 0)
goto find_stream_info_err;
}
- read_size += pkt->size;
-
st = ic->streams[pkt->stream_index];
+ if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ read_size += pkt->size;
+
if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
/* check for non-increasing dts */
if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
@@ -2928,57 +3032,30 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
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
+ && 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_WARNING, "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->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
- {
- int64_t last = st->info->last_dts;
-
- if( pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last
- && pkt->dts - (uint64_t)last < INT64_MAX){
- double dts= (is_relative(pkt->dts) ? pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base);
- int64_t duration= pkt->dts - last;
-
- if (!st->info->duration_error)
- st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2);
-
-// 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++) {
- 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;
- }
- }
- st->info->duration_count++;
- // ignore the first 4 values, they might have some random jitter
- if (st->info->duration_count > 3 && is_relative(pkt->dts) == is_relative(last))
- st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
- }
- if (pkt->dts != AV_NOPTS_VALUE)
- st->info->last_dts = pkt->dts;
- }
+ 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 (i > 0 && i < FF_MAX_EXTRADATA_SIZE) {
- st->codec->extradata_size= i;
- st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, i))
return AVERROR(ENOMEM);
memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
- memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
}
}
@@ -2991,7 +3068,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
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(st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL);
+ try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL);
st->codec_info_nb_frames++;
count++;
@@ -3002,16 +3079,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
int err = 0;
av_init_packet(&empty_pkt);
- ret = -1; /* we could not have all the codec parameters before EOF */
for(i=0;i<ic->nb_streams;i++) {
- const char *errmsg;
st = ic->streams[i];
/* flush the decoders */
if (st->info->found_decoder == 1) {
do {
- err = try_decode_frame(st, &empty_pkt,
+ err = try_decode_frame(ic, st, &empty_pkt,
(options && i < orig_nb_streams) ?
&options[i] : NULL);
} while (err > 0 && !has_codec_parameters(st, NULL));
@@ -3021,17 +3096,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
"decoding for stream %d failed\n", st->index);
}
}
-
- if (!has_codec_parameters(st, &errmsg)) {
- char buf[256];
- avcodec_string(buf, sizeof(buf), st->codec, 0);
- av_log(ic, AV_LOG_WARNING,
- "Could not find codec parameters for stream %d (%s): %s\n"
- "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n",
- i, buf, errmsg);
- } else {
- ret = 0;
- }
}
}
@@ -3040,6 +3104,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
st = ic->streams[i];
avcodec_close(st->codec);
}
+
+ ff_rfps_calculate(ic);
+
for(i=0;i<ic->nb_streams;i++) {
st = ic->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -3054,6 +3121,10 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
int best_fps = 0;
double best_error = 0.01;
+ if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2||
+ st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||
+ 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);
@@ -3074,40 +3145,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
best_fps, 12*1001, INT_MAX);
}
}
- // the check for tb_unreliable() is not completely correct, since this is not about handling
- // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
- // ipmovie.c produces.
- if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
- av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
- if (st->info->duration_count>1 && !st->r_frame_rate.num
- && tb_unreliable(st->codec)) {
- int num = 0;
- double best_error= 0.01;
-
- 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))
- continue;
- if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j))
- continue;
- 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){
- best_error= error;
- num = get_std_framerate(j);
- }
- 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)))
- av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
- }
if (!st->r_frame_rate.num){
if( st->codec->time_base.den * (int64_t)st->time_base.num
@@ -3141,19 +3178,37 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
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++) {
+ const char *errmsg;
+ st = ic->streams[i];
+ if (!has_codec_parameters(st, &errmsg)) {
+ char buf[256];
+ avcodec_string(buf, sizeof(buf), st->codec, 0);
+ av_log(ic, AV_LOG_WARNING,
+ "Could not find codec parameters for stream %d (%s): %s\n"
+ "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n",
+ i, buf, errmsg);
+ } else {
+ ret = 0;
+ }
+ }
+
compute_chapters_end(ic);
find_stream_info_err:
for (i=0; i < ic->nb_streams; i++) {
st = ic->streams[i];
- if (ic->streams[i]->codec)
+ if (ic->streams[i]->codec && 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)
- av_log(ic, AV_LOG_DEBUG, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(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;
}
@@ -3204,7 +3259,7 @@ int av_find_best_stream(AVFormatContext *ic,
if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED))
continue;
if (decoder_ret) {
- decoder = avcodec_find_decoder(st->codec->codec_id);
+ decoder = find_decoder(ic, st, st->codec->codec_id);
if (!decoder) {
if (ret < 0)
ret = AVERROR_DECODER_NOT_FOUND;
@@ -3264,6 +3319,7 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){
if (st->attached_pic.data)
av_free_packet(&st->attached_pic);
av_dict_free(&st->metadata);
+ av_freep(&st->probe_data.buf);
av_freep(&st->index_entries);
av_freep(&st->codec->extradata);
av_freep(&st->codec->subtitle_header);
@@ -3272,7 +3328,6 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){
if (st->info)
av_freep(&st->info->duration_error);
av_freep(&st->info);
- av_freep(&st->probe_data.buf);
av_freep(&s->streams[ --s->nb_streams ]);
}
@@ -3316,8 +3371,14 @@ void av_close_input_file(AVFormatContext *s)
void avformat_close_input(AVFormatContext **ps)
{
- AVFormatContext *s = *ps;
- AVIOContext *pb = s->pb;
+ AVFormatContext *s;
+ AVIOContext *pb;
+
+ if (!ps || !*ps)
+ return;
+
+ s = *ps;
+ pb = s->pb;
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
@@ -3355,7 +3416,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
if (s->nb_streams >= INT_MAX/sizeof(*streams))
return NULL;
- streams = av_realloc(s->streams, (s->nb_streams + 1) * sizeof(*streams));
+ streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));
if (!streams)
return NULL;
s->streams = streams;
@@ -3392,7 +3453,6 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
st->last_IP_pts = AV_NOPTS_VALUE;
for(i=0; i<MAX_REORDER_DELAY+1; i++)
st->pts_buffer[i]= AV_NOPTS_VALUE;
- st->reference_dts = AV_NOPTS_VALUE;
st->sample_aspect_ratio = (AVRational){0,1};
@@ -3477,7 +3537,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i
if(program->stream_index[j] == idx)
return;
- tmp = av_realloc(program->stream_index, sizeof(unsigned int)*(program->nb_stream_indexes+1));
+ tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int));
if(!tmp)
return;
program->stream_index = tmp;
@@ -3788,27 +3848,11 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int
av_hex_dump(f, pkt->data, pkt->size);
}
-#if FF_API_PKT_DUMP
-void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload)
-{
- AVRational tb = { 1, AV_TIME_BASE };
- pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb);
-}
-#endif
-
void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st)
{
pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base);
}
-#if FF_API_PKT_DUMP
-void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload)
-{
- AVRational tb = { 1, AV_TIME_BASE };
- pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb);
-}
-#endif
-
void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload,
AVStream *st)
{
@@ -3956,72 +4000,6 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
s->pts_wrap_bits = pts_wrap_bits;
}
-int ff_url_join(char *str, int size, const char *proto,
- const char *authorization, const char *hostname,
- int port, const char *fmt, ...)
-{
-#if CONFIG_NETWORK
- struct addrinfo hints = { 0 }, *ai;
-#endif
-
- str[0] = '\0';
- if (proto)
- av_strlcatf(str, size, "%s://", proto);
- if (authorization && authorization[0])
- av_strlcatf(str, size, "%s@", authorization);
-#if CONFIG_NETWORK && defined(AF_INET6)
- /* Determine if hostname is a numerical IPv6 address,
- * properly escape it within [] in that case. */
- hints.ai_flags = AI_NUMERICHOST;
- if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
- if (ai->ai_family == AF_INET6) {
- av_strlcat(str, "[", size);
- av_strlcat(str, hostname, size);
- av_strlcat(str, "]", size);
- } else {
- av_strlcat(str, hostname, size);
- }
- freeaddrinfo(ai);
- } else
-#endif
- /* Not an IPv6 address, just output the plain string. */
- av_strlcat(str, hostname, size);
-
- if (port >= 0)
- av_strlcatf(str, size, ":%d", port);
- if (fmt) {
- va_list vl;
- int len = strlen(str);
-
- va_start(vl, fmt);
- vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
- va_end(vl);
- }
- return strlen(str);
-}
-
-int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
- AVFormatContext *src)
-{
- AVPacket local_pkt;
-
- local_pkt = *pkt;
- local_pkt.stream_index = dst_stream;
- if (pkt->pts != AV_NOPTS_VALUE)
- local_pkt.pts = av_rescale_q(pkt->pts,
- src->streams[pkt->stream_index]->time_base,
- dst->streams[dst_stream]->time_base);
- if (pkt->dts != AV_NOPTS_VALUE)
- local_pkt.dts = av_rescale_q(pkt->dts,
- src->streams[pkt->stream_index]->time_base,
- dst->streams[dst_stream]->time_base);
- if (pkt->duration)
- local_pkt.duration = av_rescale_q(pkt->duration,
- src->streams[pkt->stream_index]->time_base,
- dst->streams[dst_stream]->time_base);
- return av_write_frame(dst, &local_pkt);
-}
-
void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf,
void *context)
{
@@ -4086,75 +4064,6 @@ int ff_find_stream_index(AVFormatContext *s, int id)
return -1;
}
-void ff_make_absolute_url(char *buf, int size, const char *base,
- const char *rel)
-{
- char *sep, *path_query;
- /* Absolute path, relative to the current server */
- if (base && strstr(base, "://") && rel[0] == '/') {
- if (base != buf)
- av_strlcpy(buf, base, size);
- sep = strstr(buf, "://");
- if (sep) {
- /* Take scheme from base url */
- if (rel[1] == '/') {
- sep[1] = '\0';
- } else {
- /* Take scheme and host from base url */
- sep += 3;
- sep = strchr(sep, '/');
- if (sep)
- *sep = '\0';
- }
- }
- av_strlcat(buf, rel, size);
- return;
- }
- /* If rel actually is an absolute url, just copy it */
- if (!base || strstr(rel, "://") || rel[0] == '/') {
- av_strlcpy(buf, rel, size);
- return;
- }
- if (base != buf)
- av_strlcpy(buf, base, size);
-
- /* Strip off any query string from base */
- path_query = strchr(buf, '?');
- if (path_query != NULL)
- *path_query = '\0';
-
- /* Is relative path just a new query part? */
- if (rel[0] == '?') {
- av_strlcat(buf, rel, size);
- return;
- }
-
- /* Remove the file name from the base url */
- sep = strrchr(buf, '/');
- if (sep)
- sep[1] = '\0';
- else
- buf[0] = '\0';
- while (av_strstart(rel, "../", NULL) && sep) {
- /* Remove the path delimiter at the end */
- sep[0] = '\0';
- sep = strrchr(buf, '/');
- /* If the next directory name to pop off is "..", break here */
- if (!strcmp(sep ? &sep[1] : buf, "..")) {
- /* Readd the slash we just removed */
- av_strlcat(buf, "/", size);
- break;
- }
- /* Cut off the directory name */
- if (sep)
- sep[1] = '\0';
- else
- buf[0] = '\0';
- rel += 3;
- }
- av_strlcat(buf, rel, size);
-}
-
int64_t ff_iso8601_to_unix_time(const char *datestr)
{
struct tm time1 = {0}, time2 = {0};
@@ -4244,15 +4153,6 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels,
return 0;
}
-const struct AVCodecTag *avformat_get_riff_video_tags(void)
-{
- return ff_codec_bmp_tags;
-}
-const struct AVCodecTag *avformat_get_riff_audio_tags(void)
-{
- return ff_codec_wav_tags;
-}
-
AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame)
{
AVRational undef = {0, 1};
@@ -4276,6 +4176,22 @@ AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *strea
return frame_sample_aspect_ratio;
}
+AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame)
+{
+ AVRational fr = st->r_frame_rate;
+
+ 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)
+ fr = codec_fr;
+ }
+
+ return fr;
+}
+
int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
const char *spec)
{
@@ -4337,7 +4253,7 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
return AVERROR(EINVAL);
}
-void ff_generate_avci_extradata(AVStream *st)
+int ff_generate_avci_extradata(AVStream *st)
{
static const uint8_t avci100_1080p_extradata[] = {
// SPS
@@ -4404,8 +4320,10 @@ void ff_generate_avci_extradata(AVStream *st)
0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x31, 0x12,
0x11
};
+
+ const uint8_t *data = NULL;
int size = 0;
- const uint8_t *data = 0;
+
if (st->codec->width == 1920) {
if (st->codec->field_order == AV_FIELD_PROGRESSIVE) {
data = avci100_1080p_extradata;
@@ -4421,67 +4339,14 @@ void ff_generate_avci_extradata(AVStream *st)
data = avci100_720p_extradata;
size = sizeof(avci100_720p_extradata);
}
+
if (!size)
- return;
+ return 0;
+
av_freep(&st->codec->extradata);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return;
+ if (ff_alloc_extradata(st->codec, size))
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, data, size);
- st->codec->extradata_size = size;
-}
-static int match_host_pattern(const char *pattern, const char *hostname)
-{
- int len_p, len_h;
- if (!strcmp(pattern, "*"))
- return 1;
- // Skip a possible *. at the start of the pattern
- if (pattern[0] == '*')
- pattern++;
- if (pattern[0] == '.')
- pattern++;
- len_p = strlen(pattern);
- len_h = strlen(hostname);
- if (len_p > len_h)
- return 0;
- // Simply check if the end of hostname is equal to 'pattern'
- if (!strcmp(pattern, &hostname[len_h - len_p])) {
- if (len_h == len_p)
- return 1; // Exact match
- if (hostname[len_h - len_p - 1] == '.')
- return 1; // The matched substring is a domain and not just a substring of a domain
- }
return 0;
}
-
-int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
-{
- char *buf, *start;
- int ret = 0;
- if (!no_proxy)
- return 0;
- if (!hostname)
- return 0;
- buf = av_strdup(no_proxy);
- if (!buf)
- return 0;
- start = buf;
- while (start) {
- char *sep, *next = NULL;
- start += strspn(start, " ,");
- sep = start + strcspn(start, " ,");
- if (*sep) {
- next = sep + 1;
- *sep = '\0';
- }
- if (match_host_pattern(start, hostname)) {
- ret = 1;
- break;
- }
- start = next;
- }
- av_free(buf);
- return ret;
-}
diff --git a/ffmpeg/libavformat/vc1test.c b/ffmpeg/libavformat/vc1test.c
index e411a25..e5303fa 100644
--- a/ffmpeg/libavformat/vc1test.c
+++ b/ffmpeg/libavformat/vc1test.c
@@ -39,7 +39,7 @@ static int vc1t_probe(AVProbeData *p)
if (p->buf[3] != 0xC5 || AV_RL32(&p->buf[4]) != 4 || AV_RL32(&p->buf[20]) != 0xC)
return 0;
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int vc1t_read_header(AVFormatContext *s)
@@ -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;
- st->codec->extradata = av_malloc(VC1_EXTRADATA_SIZE);
- st->codec->extradata_size = VC1_EXTRADATA_SIZE;
- avio_read(pb, st->codec->extradata, VC1_EXTRADATA_SIZE);
+ if (ff_get_extradata(st->codec, pb, VC1_EXTRADATA_SIZE) < 0)
+ return AVERROR(ENOMEM);
st->codec->height = avio_rl32(pb);
st->codec->width = avio_rl32(pb);
if(avio_rl32(pb) != 0xC)
diff --git a/ffmpeg/libavformat/vc1testenc.c b/ffmpeg/libavformat/vc1testenc.c
index 9debf19..751333a 100644
--- a/ffmpeg/libavformat/vc1testenc.c
+++ b/ffmpeg/libavformat/vc1testenc.c
@@ -63,7 +63,6 @@ static int vc1test_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_wl32(pb, pkt->size | ((pkt->flags & AV_PKT_FLAG_KEY) ? 0x80000000 : 0));
avio_wl32(pb, pkt->pts);
avio_write(pb, pkt->data, pkt->size);
- avio_flush(pb);
ctx->frames++;
return 0;
diff --git a/ffmpeg/libavformat/version.h b/ffmpeg/libavformat/version.h
index 6332878..ee8679d 100644
--- a/ffmpeg/libavformat/version.h
+++ b/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 0
+#define LIBAVFORMAT_VERSION_MINOR 22
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
@@ -48,13 +48,10 @@
* dropped at a future version bump. The defines themselves are not part of
* the public API and may change, break or disappear at any time.
*/
-
-#ifndef FF_API_OLD_AVIO
-#define FF_API_OLD_AVIO (LIBAVFORMAT_VERSION_MAJOR < 55)
-#endif
-#ifndef FF_API_PKT_DUMP
-#define FF_API_PKT_DUMP (LIBAVFORMAT_VERSION_MAJOR < 54)
+#ifndef FF_API_REFERENCE_DTS
+#define FF_API_REFERENCE_DTS (LIBAVFORMAT_VERSION_MAJOR < 56)
#endif
+
#ifndef FF_API_ALLOC_OUTPUT_CONTEXT
#define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56)
#endif
@@ -73,6 +70,9 @@
#ifndef FF_API_READ_PACKET
#define FF_API_READ_PACKET (LIBAVFORMAT_VERSION_MAJOR < 56)
#endif
+#ifndef FF_API_ASS_SSA
+#define FF_API_ASS_SSA (LIBAVFORMAT_VERSION_MAJOR < 56)
+#endif
#ifndef FF_API_R_FRAME_RATE
#define FF_API_R_FRAME_RATE 1
#endif
diff --git a/ffmpeg/libavformat/vocdec.c b/ffmpeg/libavformat/vocdec.c
index 62215fc..0b6b5a5 100644
--- a/ffmpeg/libavformat/vocdec.c
+++ b/ffmpeg/libavformat/vocdec.c
@@ -75,7 +75,7 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
while (!voc->remaining_size) {
type = avio_r8(pb);
if (type == VOC_TYPE_EOF)
- return AVERROR(EIO);
+ return AVERROR_EOF;
voc->remaining_size = avio_rl24(pb);
if (!voc->remaining_size) {
if (!s->pb->seekable)
@@ -91,11 +91,11 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
if (sample_rate)
dec->sample_rate = sample_rate;
avpriv_set_pts_info(st, 64, 1, dec->sample_rate);
+ dec->channels = channels;
+ dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id);
} else
avio_skip(pb, 1);
- dec->channels = channels;
tmp_codec = avio_r8(pb);
- dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id);
voc->remaining_size -= 2;
max_size -= 2;
channels = 1;
@@ -117,10 +117,10 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
if (!dec->sample_rate) {
dec->sample_rate = avio_rl32(pb);
avpriv_set_pts_info(st, 64, 1, dec->sample_rate);
+ dec->bits_per_coded_sample = avio_r8(pb);
+ dec->channels = avio_r8(pb);
} else
- avio_skip(pb, 4);
- dec->bits_per_coded_sample = avio_r8(pb);
- dec->channels = avio_r8(pb);
+ avio_skip(pb, 6);
tmp_codec = avio_rl16(pb);
avio_skip(pb, 4);
voc->remaining_size -= 12;
diff --git a/ffmpeg/libavformat/vorbiscomment.c b/ffmpeg/libavformat/vorbiscomment.c
index 9b38e6a..f17a0c1 100644
--- a/ffmpeg/libavformat/vorbiscomment.c
+++ b/ffmpeg/libavformat/vorbiscomment.c
@@ -34,6 +34,7 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = {
{ "ALBUMARTIST", "album_artist"},
{ "TRACKNUMBER", "track" },
{ "DISCNUMBER", "disc" },
+ { "DESCRIPTION", "comment" },
{ 0 }
};
diff --git a/ffmpeg/libavformat/vqf.c b/ffmpeg/libavformat/vqf.c
index f1e6aaf..526b596 100644
--- a/ffmpeg/libavformat/vqf.c
+++ b/ffmpeg/libavformat/vqf.c
@@ -43,7 +43,10 @@ static int vqf_probe(AVProbeData *probe_packet)
if (!memcmp(probe_packet->buf + 4, "00052200", 8))
return AVPROBE_SCORE_MAX;
- return AVPROBE_SCORE_MAX/2;
+ if (AV_RL32(probe_packet->buf + 12) > (1<<27))
+ return AVPROBE_SCORE_EXTENSION/2;
+
+ return AVPROBE_SCORE_EXTENSION;
}
static void add_metadata(AVFormatContext *s, uint32_t tag,
@@ -132,6 +135,11 @@ static int vqf_read_header(AVFormatContext *s)
rate_flag = AV_RB32(comm_chunk + 8);
avio_skip(s->pb, len-12);
+ if (st->codec->channels <= 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid number of channels\n");
+ return AVERROR_INVALIDDATA;
+ }
+
st->codec->bit_rate = read_bitrate*1000;
break;
case MKTAG('D','S','I','Z'): // size of compressed data
@@ -158,7 +166,7 @@ static int vqf_read_header(AVFormatContext *s)
header_size -= len;
- } while (header_size >= 0);
+ } while (header_size >= 0 && !url_feof(s->pb));
switch (rate_flag) {
case -1:
@@ -174,14 +182,21 @@ static int vqf_read_header(AVFormatContext *s)
st->codec->sample_rate = 11025;
break;
default:
- st->codec->sample_rate = rate_flag*1000;
- if (st->codec->sample_rate <= 0) {
- av_log(s, AV_LOG_ERROR, "sample rate %d is invalid\n", st->codec->sample_rate);
- return -1;
+ if (rate_flag < 8 || rate_flag > 44) {
+ av_log(s, AV_LOG_ERROR, "Invalid rate flag %d\n", rate_flag);
+ return AVERROR_INVALIDDATA;
}
+ st->codec->sample_rate = rate_flag*1000;
break;
}
+ if (read_bitrate / st->codec->channels < 8 ||
+ read_bitrate / st->codec->channels > 48) {
+ av_log(s, AV_LOG_ERROR, "Invalid bitrate per channel %d\n",
+ read_bitrate / st->codec->channels);
+ return AVERROR_INVALIDDATA;
+ }
+
switch (((st->codec->sample_rate/1000) << 8) +
read_bitrate/st->codec->channels) {
case (11<<8) + 8 :
@@ -208,9 +223,8 @@ static int vqf_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, size, st->codec->sample_rate);
/* put first 12 bytes of COMM chunk in extradata */
- if (!(st->codec->extradata = av_malloc(12 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ if (ff_alloc_extradata(st->codec, 12))
return AVERROR(ENOMEM);
- st->codec->extradata_size = 12;
memcpy(st->codec->extradata, comm_chunk, 12);
ff_metadata_conv_ctx(s, NULL, vqf_metadata_conv);
diff --git a/ffmpeg/libavformat/w64.c b/ffmpeg/libavformat/w64.c
index 7bf5502..ef2d90a 100644
--- a/ffmpeg/libavformat/w64.c
+++ b/ffmpeg/libavformat/w64.c
@@ -20,20 +20,31 @@
#include "w64.h"
-const uint8_t ff_w64_guid_riff[16] = { 'r', 'i', 'f', 'f',
- 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 };
+const uint8_t ff_w64_guid_riff[16] = {
+ 'r', 'i', 'f', 'f',
+ 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
+};
-const uint8_t ff_w64_guid_wave[16] = { 'w', 'a', 'v', 'e',
- 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };
+const uint8_t ff_w64_guid_wave[16] = {
+ 'w', 'a', 'v', 'e',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
-const uint8_t ff_w64_guid_fmt [16] = { 'f', 'm', 't', ' ',
- 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };
+const uint8_t ff_w64_guid_fmt [16] = {
+ 'f', 'm', 't', ' ',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
const uint8_t ff_w64_guid_fact[16] = { 'f', 'a', 'c', 't',
- 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
-const uint8_t ff_w64_guid_data[16] = { 'd', 'a', 't', 'a',
- 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };
+const uint8_t ff_w64_guid_data[16] = {
+ 'd', 'a', 't', 'a',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
-const uint8_t ff_w64_guid_summarylist[16] = { 0xBC, 0x94, 0x5F, 0x92,
- 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A };
+const uint8_t ff_w64_guid_summarylist[16] = {
+ 0xBC, 0x94, 0x5F, 0x92,
+ 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
diff --git a/ffmpeg/libavformat/wavdec.c b/ffmpeg/libavformat/wavdec.c
index 782fa64..daea64e 100644
--- a/ffmpeg/libavformat/wavdec.c
+++ b/ffmpeg/libavformat/wavdec.c
@@ -23,19 +23,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdint.h>
+
#include "libavutil/avassert.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "avformat.h"
-#include "internal.h"
+#include "avio.h"
#include "avio_internal.h"
+#include "internal.h"
+#include "metadata.h"
#include "pcm.h"
#include "riff.h"
#include "w64.h"
-#include "avio.h"
-#include "metadata.h"
#include "spdif.h"
typedef struct WAVDemuxContext {
@@ -51,9 +54,11 @@ typedef struct WAVDemuxContext {
int audio_eof;
int ignore_length;
int spdif;
+ int smv_cur_pt;
+ int smv_given_first;
+ int unaligned; // e.g. if an odd number of bytes ID3 tag was prepended
} WAVDemuxContext;
-
#if CONFIG_WAV_DEMUXER
static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
@@ -62,19 +67,27 @@ static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
return avio_rl32(pb);
}
+/* RIFF chunks are always at even offsets relative to where they start. */
+static int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offset, int whence)
+{
+ offset += offset < INT64_MAX && offset + wav->unaligned & 1;
+
+ return avio_seek(s, offset, whence);
+}
+
/* return the size of the found tag */
-static int64_t find_tag(AVIOContext *pb, uint32_t tag1)
+static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
{
unsigned int tag;
int64_t size;
for (;;) {
if (url_feof(pb))
- return -1;
+ return AVERROR_EOF;
size = next_tag(pb, &tag);
if (tag == tag1)
break;
- avio_skip(pb, size);
+ wav_seek_tag(wav, pb, size, SEEK_CUR);
}
return size;
}
@@ -86,11 +99,9 @@ static int wav_probe(AVProbeData *p)
return 0;
if (!memcmp(p->buf + 8, "WAVE", 4)) {
if (!memcmp(p->buf, "RIFF", 4))
- /*
- Since ACT demuxer has standard WAV header at top of it's own,
- returning score is decreased to avoid probe conflict
- between ACT and WAV.
- */
+ /* Since the ACT demuxer has a standard WAV header at the top of
+ * its own, the returned score is decreased to avoid a probe
+ * conflict between ACT and WAV. */
return AVPROBE_SCORE_MAX - 1;
else if (!memcmp(p->buf, "RF64", 4) &&
!memcmp(p->buf + 12, "ds64", 4))
@@ -102,7 +113,7 @@ static int wav_probe(AVProbeData *p)
static void handle_stream_probing(AVStream *st)
{
if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
- st->request_probe = AVPROBE_SCORE_MAX/2;
+ st->request_probe = AVPROBE_SCORE_EXTENSION;
st->probe_packets = FFMIN(st->probe_packets, 4);
}
}
@@ -173,16 +184,22 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
if (umid_mask) {
/* the string formatting below is per SMPTE 330M-2004 Annex C */
- if (umid_parts[4] == 0 && umid_parts[5] == 0 && umid_parts[6] == 0 && umid_parts[7] == 0) {
+ if (umid_parts[4] == 0 && umid_parts[5] == 0 &&
+ umid_parts[6] == 0 && umid_parts[7] == 0) {
/* basic UMID */
- snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
- umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3]);
+ snprintf(temp, sizeof(temp),
+ "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
+ umid_parts[0], umid_parts[1],
+ umid_parts[2], umid_parts[3]);
} else {
/* extended UMID */
- snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64
- "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
- umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3],
- umid_parts[4], umid_parts[5], umid_parts[6], umid_parts[7]);
+ snprintf(temp, sizeof(temp),
+ "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64
+ "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
+ umid_parts[0], umid_parts[1],
+ umid_parts[2], umid_parts[3],
+ umid_parts[4], umid_parts[5],
+ umid_parts[6], umid_parts[7]);
}
if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0)
@@ -197,7 +214,7 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
/* CodingHistory present */
size -= 602;
- if (!(coding_history = av_malloc(size+1)))
+ if (!(coding_history = av_malloc(size + 1)))
return AVERROR(ENOMEM);
if ((ret = avio_read(s->pb, coding_history, size)) < 0)
@@ -213,26 +230,28 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
}
static const AVMetadataConv wav_metadata_conv[] = {
- {"description", "comment" },
- {"originator", "encoded_by" },
- {"origination_date", "date" },
- {"origination_time", "creation_time"},
- {0},
+ { "description", "comment" },
+ { "originator", "encoded_by" },
+ { "origination_date", "date" },
+ { "origination_time", "creation_time" },
+ { 0 },
};
/* wav input */
static int wav_read_header(AVFormatContext *s)
{
int64_t size, av_uninit(data_size);
- int64_t sample_count=0;
+ int64_t sample_count = 0;
int rf64;
uint32_t tag;
- AVIOContext *pb = s->pb;
- AVStream *st = NULL;
+ AVIOContext *pb = s->pb;
+ AVStream *st = NULL;
WAVDemuxContext *wav = s->priv_data;
int ret, got_fmt = 0;
int64_t next_tag_ofs, data_ofs = -1;
+ wav->unaligned = avio_tell(s->pb) & 1;
+
wav->smv_data_ofs = -1;
/* check RIFF header */
@@ -240,21 +259,23 @@ static int wav_read_header(AVFormatContext *s)
rf64 = tag == MKTAG('R', 'F', '6', '4');
if (!rf64 && tag != MKTAG('R', 'I', 'F', 'F'))
- return -1;
+ return AVERROR_INVALIDDATA;
avio_rl32(pb); /* file size */
tag = avio_rl32(pb);
if (tag != MKTAG('W', 'A', 'V', 'E'))
- return -1;
+ return AVERROR_INVALIDDATA;
if (rf64) {
if (avio_rl32(pb) != MKTAG('d', 's', '6', '4'))
- return -1;
+ return AVERROR_INVALIDDATA;
size = avio_rl32(pb);
if (size < 24)
- return -1;
+ return AVERROR_INVALIDDATA;
avio_rl64(pb); /* RIFF size */
- data_size = avio_rl64(pb);
+
+ data_size = avio_rl64(pb);
sample_count = avio_rl64(pb);
+
if (data_size < 0 || sample_count < 0) {
av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in "
"ds64: data_size = %"PRId64", sample_count = %"PRId64"\n",
@@ -267,7 +288,7 @@ static int wav_read_header(AVFormatContext *s)
for (;;) {
AVStream *vst;
- size = next_tag(pb, &tag);
+ size = next_tag(pb, &tag);
next_tag_ofs = avio_tell(pb) + size;
if (url_feof(pb))
@@ -285,14 +306,15 @@ static int wav_read_header(AVFormatContext *s)
break;
case MKTAG('d', 'a', 't', 'a'):
if (!got_fmt) {
- av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'data' tag\n");
+ av_log(s, AV_LOG_ERROR,
+ "found no 'fmt ' tag before the 'data' tag\n");
return AVERROR_INVALIDDATA;
}
if (rf64) {
next_tag_ofs = wav->data_end = avio_tell(pb) + data_size;
} else {
- data_size = size;
+ data_size = size;
next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX;
}
@@ -304,11 +326,11 @@ static int wav_read_header(AVFormatContext *s)
if (!pb->seekable || (!rf64 && !size))
goto break_loop;
break;
- case MKTAG('f','a','c','t'):
+ case MKTAG('f', 'a', 'c', 't'):
if (!sample_count)
sample_count = avio_rl32(pb);
break;
- case MKTAG('b','e','x','t'):
+ case MKTAG('b', 'e', 'x', 't'):
if ((ret = wav_parse_bext_tag(s, size)) < 0)
return ret;
break;
@@ -323,15 +345,20 @@ static int wav_read_header(AVFormatContext *s)
goto break_loop;
}
av_log(s, AV_LOG_DEBUG, "Found SMV data\n");
+ wav->smv_given_first = 0;
vst = avformat_new_stream(s, NULL);
if (!vst)
return AVERROR(ENOMEM);
avio_r8(pb);
vst->id = 1;
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- vst->codec->codec_id = AV_CODEC_ID_MJPEG;
+ vst->codec->codec_id = AV_CODEC_ID_SMVJPEG;
vst->codec->width = avio_rl24(pb);
vst->codec->height = avio_rl24(pb);
+ if (ff_alloc_extradata(vst->codec, 4)) {
+ av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n");
+ return AVERROR(ENOMEM);
+ }
size = avio_rl24(pb);
wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3;
avio_rl24(pb);
@@ -341,6 +368,12 @@ static int wav_read_header(AVFormatContext *s)
avio_rl24(pb);
avio_rl24(pb);
wav->smv_frames_per_jpeg = avio_rl24(pb);
+ if (wav->smv_frames_per_jpeg > 65536) {
+ av_log(s, AV_LOG_ERROR, "too many frames per jpeg\n");
+ return AVERROR_INVALIDDATA;
+ }
+ AV_WL32(vst->codec->extradata, wav->smv_frames_per_jpeg);
+ wav->smv_cur_pt = 0;
goto break_loop;
case MKTAG('L', 'I', 'S', 'T'):
if (size < 4) {
@@ -356,10 +389,11 @@ static int wav_read_header(AVFormatContext *s)
/* seek to next tag unless we know that we'll run into EOF */
if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) ||
- avio_seek(pb, next_tag_ofs, SEEK_SET) < 0) {
+ wav_seek_tag(wav, pb, next_tag_ofs, SEEK_SET) < 0) {
break;
}
}
+
break_loop:
if (data_ofs < 0) {
av_log(s, AV_LOG_ERROR, "no 'data' tag found\n");
@@ -368,8 +402,15 @@ break_loop:
avio_seek(pb, data_ofs, SEEK_SET);
- if (!sample_count && st->codec->channels && av_get_bits_per_sample(st->codec->codec_id) && wav->data_end <= avio_size(pb))
- sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id));
+ if (!sample_count || av_get_exact_bits_per_sample(st->codec->codec_id) > 0)
+ if ( st->codec->channels
+ && data_size
+ && av_get_bits_per_sample(st->codec->codec_id)
+ && wav->data_end <= avio_size(pb))
+ sample_count = (data_size << 3)
+ /
+ (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id));
+
if (sample_count)
st->duration = sample_count;
@@ -379,7 +420,8 @@ break_loop:
return 0;
}
-/** Find chunk with w64 GUID by skipping over other chunks
+/**
+ * Find chunk with w64 GUID by skipping over other chunks.
* @return the size of the found chunk
*/
static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16])
@@ -391,18 +433,17 @@ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16])
avio_read(pb, guid, 16);
size = avio_rl64(pb);
if (size <= 24)
- return -1;
+ return AVERROR_INVALIDDATA;
if (!memcmp(guid, guid1, 16))
return size;
avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
}
- return -1;
+ return AVERROR_EOF;
}
#define MAX_SIZE 4096
-static int wav_read_packet(AVFormatContext *s,
- AVPacket *pkt)
+static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, size;
int64_t left;
@@ -414,7 +455,7 @@ static int wav_read_packet(AVFormatContext *s,
enum AVCodecID codec;
ret = ff_spdif_probe(s->pb->buffer, s->pb->buf_end - s->pb->buffer,
&codec);
- if (ret > AVPROBE_SCORE_MAX / 2) {
+ if (ret > AVPROBE_SCORE_EXTENSION) {
s->streams[0]->codec->codec_id = codec;
wav->spdif = 1;
} else {
@@ -427,12 +468,15 @@ static int wav_read_packet(AVFormatContext *s,
if (wav->smv_data_ofs > 0) {
int64_t audio_dts, video_dts;
smv_retry:
- audio_dts = s->streams[0]->cur_dts;
- video_dts = s->streams[1]->cur_dts;
+ audio_dts = (int32_t)s->streams[0]->cur_dts;
+ video_dts = (int32_t)s->streams[1]->cur_dts;
+
if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) {
- audio_dts = av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q);
- video_dts = av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q);
- wav->smv_last_stream = video_dts >= audio_dts;
+ /*We always return a video frame first to get the pixel format first*/
+ wav->smv_last_stream = wav->smv_given_first ?
+ av_compare_ts(video_dts, s->streams[1]->time_base,
+ audio_dts, s->streams[0]->time_base) > 0 : 0;
+ wav->smv_given_first = 1;
}
wav->smv_last_stream = !wav->smv_last_stream;
wav->smv_last_stream |= wav->audio_eof;
@@ -450,8 +494,13 @@ smv_retry:
if (ret < 0)
goto smv_out;
pkt->pos -= 3;
- pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg;
- wav->smv_block++;
+ pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg + wav->smv_cur_pt;
+ wav->smv_cur_pt++;
+ if (wav->smv_frames_per_jpeg > 0)
+ wav->smv_cur_pt %= wav->smv_frames_per_jpeg;
+ if (!wav->smv_cur_pt)
+ wav->smv_block++;
+
pkt->stream_index = 1;
smv_out:
avio_seek(s->pb, old_pos, SEEK_SET);
@@ -467,19 +516,19 @@ smv_out:
left = wav->data_end - avio_tell(s->pb);
if (wav->ignore_length)
- left= INT_MAX;
- if (left <= 0){
+ left = INT_MAX;
+ if (left <= 0) {
if (CONFIG_W64_DEMUXER && wav->w64)
left = find_guid(s->pb, ff_w64_guid_data) - 24;
else
- left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a'));
+ left = find_tag(wav, s->pb, MKTAG('d', 'a', 't', 'a'));
if (left < 0) {
wav->audio_eof = 1;
if (wav->smv_data_ofs > 0 && !wav->smv_eof)
goto smv_retry;
return AVERROR_EOF;
}
- wav->data_end= avio_tell(s->pb) + left;
+ wav->data_end = avio_tell(s->pb) + left;
}
size = MAX_SIZE;
@@ -510,7 +559,10 @@ static int wav_read_seek(AVFormatContext *s,
smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base);
else
timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base);
- wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
+ if (wav->smv_frames_per_jpeg > 0) {
+ wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
+ wav->smv_cur_pt = smv_timestamp % wav->smv_frames_per_jpeg;
+ }
}
st = s->streams[0];
@@ -549,12 +601,11 @@ AVInputFormat ff_wav_demuxer = {
.read_packet = wav_read_packet,
.read_seek = wav_read_seek,
.flags = AVFMT_GENERIC_INDEX,
- .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+ .codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 },
.priv_class = &wav_demuxer_class,
};
#endif /* CONFIG_WAV_DEMUXER */
-
#if CONFIG_W64_DEMUXER
static int w64_probe(AVProbeData *p)
{
@@ -570,23 +621,24 @@ static int w64_probe(AVProbeData *p)
static int w64_read_header(AVFormatContext *s)
{
int64_t size, data_ofs = 0;
- AVIOContext *pb = s->pb;
- WAVDemuxContext *wav = s->priv_data;
+ AVIOContext *pb = s->pb;
+ WAVDemuxContext *wav = s->priv_data;
AVStream *st;
uint8_t guid[16];
int ret;
avio_read(pb, guid, 16);
if (memcmp(guid, ff_w64_guid_riff, 16))
- return -1;
+ return AVERROR_INVALIDDATA;
- if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8) /* riff + wave + fmt + sizes */
- return -1;
+ /* riff + wave + fmt + sizes */
+ if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8)
+ return AVERROR_INVALIDDATA;
avio_read(pb, guid, 16);
if (memcmp(guid, ff_w64_guid_wave, 16)) {
av_log(s, AV_LOG_ERROR, "could not find wave guid\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
wav->w64 = 1;
@@ -629,7 +681,7 @@ static int w64_read_header(AVFormatContext *s)
uint32_t count, chunk_size, i;
start = avio_tell(pb);
- end = start + size;
+ end = start + FFALIGN(size, INT64_C(8)) - 24;
count = avio_rl32(pb);
for (i = 0; i < count; i++) {
@@ -655,7 +707,7 @@ static int w64_read_header(AVFormatContext *s)
avio_skip(pb, end - avio_tell(pb));
} else {
av_log(s, AV_LOG_DEBUG, "unknown guid: "FF_PRI_GUID"\n", FF_ARG_GUID(guid));
- avio_skip(pb, size - 24);
+ avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
}
}
@@ -682,6 +734,6 @@ AVInputFormat ff_w64_demuxer = {
.read_packet = wav_read_packet,
.read_seek = wav_read_seek,
.flags = AVFMT_GENERIC_INDEX,
- .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+ .codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 },
};
#endif /* CONFIG_W64_DEMUXER */
diff --git a/ffmpeg/libavformat/wavenc.c b/ffmpeg/libavformat/wavenc.c
index fea38cf..0067dfe 100644
--- a/ffmpeg/libavformat/wavenc.c
+++ b/ffmpeg/libavformat/wavenc.c
@@ -116,6 +116,11 @@ static int wav_write_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t fmt;
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n");
+ return AVERROR(EINVAL);
+ }
+
if (wav->rf64 == RF64_ALWAYS) {
ffio_wfourcc(pb, "RF64");
avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */
diff --git a/ffmpeg/libavformat/webvttdec.c b/ffmpeg/libavformat/webvttdec.c
index 694a020..0654485 100644
--- a/ffmpeg/libavformat/webvttdec.c
+++ b/ffmpeg/libavformat/webvttdec.c
@@ -29,9 +29,12 @@
#include "subtitles.h"
#include "libavutil/bprint.h"
#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
typedef struct {
+ const AVClass *class;
FFDemuxSubtitlesQueue q;
+ int kind;
} WebVTTContext;
static int webvtt_probe(AVProbeData *p)
@@ -66,6 +69,7 @@ static int webvtt_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, 1000);
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id = AV_CODEC_ID_WEBVTT;
+ st->disposition |= webvtt->kind;
av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
av_bprint_init(&cue, 0, AV_BPRINT_SIZE_UNLIMITED);
@@ -74,8 +78,8 @@ static int webvtt_read_header(AVFormatContext *s)
int i;
int64_t pos;
AVPacket *sub;
- const char *p, *identifier;
- //const char *settings = NULL;
+ const char *p, *identifier, *settings;
+ int identifier_len, settings_len;
int64_t ts_start, ts_end;
ff_subtitles_read_chunk(s->pb, &cue);
@@ -92,15 +96,23 @@ static int webvtt_read_header(AVFormatContext *s)
continue;
/* optional cue identifier (can be a number like in SRT or some kind of
- * chaptering id), silently skip it */
- for (i = 0; p[i] && p[i] != '\n'; i++) {
+ * chaptering id) */
+ for (i = 0; p[i] && p[i] != '\n' && p[i] != '\r'; i++) {
if (!strncmp(p + i, "-->", 3)) {
identifier = NULL;
break;
}
}
- if (identifier)
- p += strcspn(p, "\n");
+ if (!identifier)
+ identifier_len = 0;
+ else {
+ identifier_len = strcspn(p, "\r\n");
+ p += identifier_len;
+ if (*p == '\r')
+ p++;
+ if (*p == '\n')
+ p++;
+ }
/* cue timestamps */
if ((ts_start = read_ts(p)) == AV_NOPTS_VALUE)
@@ -112,14 +124,15 @@ static int webvtt_read_header(AVFormatContext *s)
if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE)
break;
- /* optional cue settings, TODO: store in side_data */
+ /* optional cue settings */
p += strcspn(p, "\n\t ");
while (*p == '\t' || *p == ' ')
p++;
- if (*p != '\n') {
- //settings = p;
- p += strcspn(p, "\n");
- }
+ settings = p;
+ settings_len = strcspn(p, "\r\n");
+ p += settings_len;
+ if (*p == '\r')
+ p++;
if (*p == '\n')
p++;
@@ -132,6 +145,20 @@ static int webvtt_read_header(AVFormatContext *s)
sub->pos = pos;
sub->pts = ts_start;
sub->duration = ts_end - ts_start;
+
+#define SET_SIDE_DATA(name, type) do { \
+ if (name##_len) { \
+ uint8_t *buf = av_packet_new_side_data(sub, type, name##_len); \
+ if (!buf) { \
+ res = AVERROR(ENOMEM); \
+ goto end; \
+ } \
+ memcpy(buf, name, name##_len); \
+ } \
+} while (0)
+
+ SET_SIDE_DATA(identifier, AV_PKT_DATA_WEBVTT_IDENTIFIER);
+ SET_SIDE_DATA(settings, AV_PKT_DATA_WEBVTT_SETTINGS);
}
ff_subtitles_queue_finalize(&webvtt->q);
@@ -163,6 +190,25 @@ static int webvtt_read_close(AVFormatContext *s)
return 0;
}
+#define OFFSET(x) offsetof(WebVTTContext, x)
+#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM
+
+static const AVOption options[] = {
+ { "kind", "Set kind of WebVTT track", OFFSET(kind), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, KIND_FLAGS, "webvtt_kind" },
+ { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { NULL }
+};
+
+static const AVClass webvtt_demuxer_class = {
+ .class_name = "WebVTT demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVInputFormat ff_webvtt_demuxer = {
.name = "webvtt",
.long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
@@ -173,4 +219,5 @@ AVInputFormat ff_webvtt_demuxer = {
.read_seek2 = webvtt_read_seek,
.read_close = webvtt_read_close,
.extensions = "vtt",
+ .priv_class = &webvtt_demuxer_class,
};
diff --git a/ffmpeg/libavformat/westwood_aud.c b/ffmpeg/libavformat/westwood_aud.c
index d666117..f2bd3a1 100644
--- a/ffmpeg/libavformat/westwood_aud.c
+++ b/ffmpeg/libavformat/westwood_aud.c
@@ -77,7 +77,7 @@ static int wsaud_probe(AVProbeData *p)
return 0;
/* return 1/2 certainty since this file check is a little sketchy */
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int wsaud_read_header(AVFormatContext *s)
diff --git a/ffmpeg/libavformat/westwood_vqa.c b/ffmpeg/libavformat/westwood_vqa.c
index c996dad..2a988ad 100644
--- a/ffmpeg/libavformat/westwood_vqa.c
+++ b/ffmpeg/libavformat/westwood_vqa.c
@@ -81,10 +81,10 @@ static int wsvqa_read_header(AVFormatContext *s)
WsVqaDemuxContext *wsvqa = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
- unsigned char *header;
- unsigned char scratch[VQA_PREAMBLE_SIZE];
- unsigned int chunk_tag;
- unsigned int chunk_size;
+ uint8_t *header;
+ uint8_t scratch[VQA_PREAMBLE_SIZE];
+ uint32_t chunk_tag;
+ uint32_t chunk_size;
int fps;
/* initialize the video decoder stream */
@@ -101,14 +101,9 @@ static int wsvqa_read_header(AVFormatContext *s)
avio_seek(pb, 20, SEEK_SET);
/* the VQA header needs to go to the decoder */
- st->codec->extradata_size = VQA_HEADER_SIZE;
- st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- header = (unsigned char *)st->codec->extradata;
- if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) !=
- VQA_HEADER_SIZE) {
- av_free(st->codec->extradata);
- return AVERROR(EIO);
- }
+ if (ff_get_extradata(st->codec, pb, VQA_HEADER_SIZE) < 0)
+ return AVERROR(ENOMEM);
+ header = (uint8_t *)st->codec->extradata;
st->codec->width = AV_RL16(&header[6]);
st->codec->height = AV_RL16(&header[8]);
fps = header[12];
@@ -167,9 +162,9 @@ static int wsvqa_read_packet(AVFormatContext *s,
WsVqaDemuxContext *wsvqa = s->priv_data;
AVIOContext *pb = s->pb;
int ret = -1;
- unsigned char preamble[VQA_PREAMBLE_SIZE];
- unsigned int chunk_type;
- unsigned int chunk_size;
+ uint8_t preamble[VQA_PREAMBLE_SIZE];
+ uint32_t chunk_type;
+ uint32_t chunk_size;
int skip_byte;
while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) {
@@ -220,9 +215,7 @@ static int wsvqa_read_packet(AVFormatContext *s,
break;
case SND2_TAG:
st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
- st->codec->extradata_size = 2;
- st->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 2))
return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata, wsvqa->version);
break;
diff --git a/ffmpeg/libavformat/wtv.c b/ffmpeg/libavformat/wtv.c
deleted file mode 100644
index 5b1e61b..0000000
--- a/ffmpeg/libavformat/wtv.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Windows Television (WTV)
- * 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
- */
-
-#include "wtv.h"
-
-/* WTV GUIDs*/
-const ff_asf_guid ff_dir_entry_guid =
- {0x92,0xB7,0x74,0x91,0x59,0x70,0x70,0x44,0x88,0xDF,0x06,0x3B,0x82,0xCC,0x21,0x3D};
-const ff_asf_guid ff_wtv_guid =
- {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-const ff_asf_guid ff_timestamp_guid =
- {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97};
-const ff_asf_guid ff_data_guid =
- {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT =
- {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE};
-const ff_asf_guid ff_stream1_guid =
- {0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-const ff_asf_guid ff_sync_guid =
- {0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-const ff_asf_guid ff_index_guid =
- {0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-const ff_asf_guid ff_mediatype_audio =
- {'a','u','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-const ff_asf_guid ff_mediatype_video =
- {'v','i','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-const ff_asf_guid ff_format_none =
- {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96};
-
-/* declare utf16le strings */
-#define _ , 0,
-const uint8_t ff_timeline_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0};
-const uint8_t ff_timeline_table_0_entries_Events_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
-const uint8_t ff_table_0_entries_legacy_attrib_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
-const uint8_t ff_table_0_entries_time_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0};
-#undef _
-
-const ff_asf_guid ff_DSATTRIB_TRANSPORT_PROPERTIES =
- {0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A};
-const ff_asf_guid ff_metadata_guid =
- {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53};
-const ff_asf_guid ff_stream2_guid =
- {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-
-/* Media subtypes */
-const ff_asf_guid ff_mediasubtype_cpfilters_processed =
- {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D};
-
-/* Formats */
-const ff_asf_guid ff_format_cpfilters_processed =
- {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A};
-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 AVCodecGuid ff_video_guids[] = {
- {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
- {AV_CODEC_ID_NONE}
-};
diff --git a/ffmpeg/libavformat/wtv.h b/ffmpeg/libavformat/wtv.h
index efe90d6..f26ad5e 100644
--- a/ffmpeg/libavformat/wtv.h
+++ b/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/ffmpeg/libavformat/wtvdec.c b/ffmpeg/libavformat/wtvdec.c
index e423370..21236fa 100644
--- a/ffmpeg/libavformat/wtvdec.c
+++ b/ffmpeg/libavformat/wtvdec.c
@@ -47,17 +47,22 @@
*/
typedef struct {
- AVIOContext *pb_filesystem; /** file system (AVFormatContext->pb) */
+ AVIOContext *pb_filesystem; /**< file system (AVFormatContext->pb) */
- int sector_bits; /** sector shift bits; used to convert sector number into pb_filesystem offset */
- uint32_t *sectors; /** file allocation table */
- int nb_sectors; /** number of sectors */
+ int sector_bits; /**< sector shift bits; used to convert sector number into pb_filesystem offset */
+ uint32_t *sectors; /**< file allocation table */
+ int nb_sectors; /**< number of sectors */
int error;
int64_t position;
int64_t length;
} WtvFile;
+static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
+{
+ return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
+}
+
/**
* @return bytes read, 0 on end of file, or <0 on error
*/
@@ -88,7 +93,7 @@ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
int i = wf->position >> wf->sector_bits;
if (i >= wf->nb_sectors ||
(wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
- avio_seek(pb, (int64_t)wf->sectors[i] << WTV_SECTOR_BITS, SEEK_SET) < 0)) {
+ seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
wf->error = 1;
break;
}
@@ -113,8 +118,8 @@ static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
offset = wf->length;
wf->error = offset < 0 || offset >= wf->length ||
- avio_seek(pb, ((int64_t)wf->sectors[offset >> wf->sector_bits] << WTV_SECTOR_BITS)
- + (offset & ((1 << wf->sector_bits) - 1)), SEEK_SET) < 0;
+ seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
+ offset & ((1 << wf->sector_bits) - 1)) < 0;
wf->position = offset;
return offset;
}
@@ -148,8 +153,9 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
AVIOContext *pb;
WtvFile *wf;
uint8_t *buffer;
+ int64_t size;
- if (avio_seek(s->pb, (int64_t)first_sector << WTV_SECTOR_BITS, SEEK_SET) < 0)
+ if (seek_by_sector(s->pb, first_sector, 0) < 0)
return NULL;
wf = av_mallocz(sizeof(WtvFile));
@@ -176,14 +182,14 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4);
int i;
- wf->sectors = av_malloc(nb_sectors1 << WTV_SECTOR_BITS);
+ wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS);
if (!wf->sectors) {
av_free(wf);
return NULL;
}
wf->nb_sectors = 0;
for (i = 0; i < nb_sectors1; i++) {
- if (avio_seek(s->pb, (int64_t)sectors1[i] << WTV_SECTOR_BITS, SEEK_SET) < 0)
+ if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
break;
wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
}
@@ -200,7 +206,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 */
@@ -213,7 +220,7 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int
/* seek to initial sector */
wf->position = 0;
- if (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 0) {
+ if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
av_free(wf->sectors);
av_free(wf);
return NULL;
@@ -261,7 +268,12 @@ static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int b
dir_length = AV_RL16(buf + 16);
file_length = AV_RL64(buf + 24);
name_size = 2 * AV_RL32(buf + 32);
- if (buf + 48 + (int64_t)name_size > buf_end || name_size<0) {
+ if (name_size < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "bad filename length, remaining directory entries ignored\n");
+ break;
+ }
+ if (48 + (int64_t)name_size > buf_end - buf) {
av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
break;
}
@@ -306,10 +318,10 @@ typedef struct {
} WtvStream;
typedef struct {
- AVIOContext *pb; /** timeline file */
+ AVIOContext *pb; /**< timeline file */
int64_t epoch;
- int64_t pts; /** pts for next data chunk */
- int64_t last_valid_pts; /** latest valid pts, used for interative seeking */
+ int64_t pts; /**< pts for next data chunk */
+ int64_t last_valid_pts; /**< latest valid pts, used for interative seeking */
/* maintain private seek index, as the AVIndexEntry->pos is relative to the
start of the 'timeline' file, not the file system (AVFormatContext->pb) */
@@ -360,10 +372,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;
@@ -436,6 +444,7 @@ static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
av_dict_set(&st->metadata, "title", description, 0);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ st->id = -1;
ret = av_get_packet(pb, &st->attached_pic, filesize);
if (ret < 0)
goto done;
@@ -495,7 +504,7 @@ static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int ty
else
snprintf(buf, buf_size, "%"PRIi64, num);
} else if (type == 5 && length == 2) {
- snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb));
+ snprintf(buf, buf_size, "%u", avio_rl16(pb));
} else if (type == 6 && length == 16) {
ff_asf_guid guid;
avio_read(pb, guid, 16);
@@ -678,7 +687,7 @@ 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)) {
@@ -935,7 +944,7 @@ static int read_header(AVFormatContext *s)
avio_skip(s->pb, 4);
root_sector = avio_rl32(s->pb);
- avio_seek(s->pb, (int64_t)root_sector << WTV_SECTOR_BITS, SEEK_SET);
+ seek_by_sector(s->pb, root_sector, 0);
root_size = avio_read(s->pb, root, root_size);
if (root_size < 0)
return AVERROR_INVALIDDATA;
diff --git a/ffmpeg/libavformat/wtvenc.c b/ffmpeg/libavformat/wtvenc.c
index 22917a4..5e3b9b9 100644
--- a/ffmpeg/libavformat/wtvenc.c
+++ b/ffmpeg/libavformat/wtvenc.c
@@ -28,6 +28,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/avassert.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "wtv.h"
#include "asf.h"
@@ -87,10 +88,10 @@ typedef struct {
typedef struct {
int64_t timeline_start_pos;
WtvFile file[WTV_FILES];
- int64_t serial; /** chunk serial number */
- int64_t last_chunk_pos; /** last chunk position */
- int64_t last_timestamp_pos; /** last timestamp chunk position */
- int64_t first_index_pos; /** first index_chunk position */
+ int64_t serial; /**< chunk serial number */
+ int64_t last_chunk_pos; /**< last chunk position */
+ int64_t last_timestamp_pos; /**< last timestamp chunk position */
+ int64_t first_index_pos; /**< first index_chunk position */
WtvChunkEntry index[MAX_NB_INDEX];
int nb_index;
@@ -127,12 +128,7 @@ typedef struct {
WTVHeaderWriteFunc *write_header;
} WTVRootEntryTable;
-static int write_pad(AVIOContext *pb, int size)
-{
- for (; size > 0; size--)
- avio_w8(pb, 0);
- return 0;
-}
+#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)
{
@@ -227,10 +223,52 @@ 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) {
+ /* MPEG2VIDEOINFO */
+ avio_wl32(pb, 0);
+ avio_wl32(pb, st->codec->extradata_size);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, 0);
+ avio_write(pb, st->codec->extradata, st->codec->extradata_size);
+ avio_wl64(pb, 0);
+ }
+}
+
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;
@@ -238,21 +276,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);
@@ -261,15 +296,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)
+ format_type = &ff_format_none;
}
hdr_size = avio_tell(pb) - hdr_pos_start;
@@ -277,7 +307,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;
@@ -457,7 +497,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
wctx->serial++;
- avio_flush(pb);
return 0;
}
diff --git a/ffmpeg/libavformat/wv.c b/ffmpeg/libavformat/wv.c
index 97a6c1f..0f4f807 100644
--- a/ffmpeg/libavformat/wv.c
+++ b/ffmpeg/libavformat/wv.c
@@ -1,6 +1,5 @@
/*
- * WavPack demuxer
- * Copyright (c) 2006,2011 Konstantin Shishkov
+ * WavPack shared functions
*
* This file is part of FFmpeg.
*
@@ -19,379 +18,35 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/channel_layout.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/dict.h"
-#include "avformat.h"
-#include "internal.h"
-#include "apetag.h"
-#include "id3v1.h"
-
-// specs say that maximum block size is 1Mb
-#define WV_BLOCK_LIMIT 1047576
-
-#define WV_EXTRA_SIZE 12
-
-#define WV_START_BLOCK 0x0800
-#define WV_END_BLOCK 0x1000
-#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK)
-
-enum WV_FLAGS {
- WV_MONO = 0x0004,
- WV_HYBRID = 0x0008,
- WV_JOINT = 0x0010,
- WV_CROSSD = 0x0020,
- WV_HSHAPE = 0x0040,
- WV_FLOAT = 0x0080,
- WV_INT32 = 0x0100,
- WV_HBR = 0x0200,
- WV_HBAL = 0x0400,
- WV_MCINIT = 0x0800,
- WV_MCEND = 0x1000,
-};
+#include <stdint.h>
+#include <string.h>
-static const int wv_rates[16] = {
- 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
- 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1
-};
-
-typedef struct {
- uint32_t blksize, flags;
- int rate, chan, bpp;
- uint32_t chmask;
- uint32_t samples, soff;
- int multichannel;
- int block_parsed;
- uint8_t extra[WV_EXTRA_SIZE];
- int64_t pos;
-
- int64_t apetag_start;
-} WVContext;
+#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
-static int wv_probe(AVProbeData *p)
-{
- /* check file header */
- if (p->buf_size <= 32)
- return 0;
- if (p->buf[0] == 'w' && p->buf[1] == 'v' &&
- p->buf[2] == 'p' && p->buf[3] == 'k')
- return AVPROBE_SCORE_MAX;
- else
- return 0;
-}
+#include "wv.h"
-static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb,
- int append)
+int ff_wv_parse_header(WvHeader *wv, const uint8_t *data)
{
- WVContext *wc = ctx->priv_data;
- uint32_t tag, ver;
- int size;
- int rate, bpp, chan;
- uint32_t chmask;
-
- wc->pos = avio_tell(pb);
-
- /* don't return bogus packets with the ape tag data */
- if (wc->apetag_start && wc->pos >= wc->apetag_start)
- return AVERROR_EOF;
+ memset(wv, 0, sizeof(*wv));
- if (!append) {
- tag = avio_rl32(pb);
- if (tag != MKTAG('w', 'v', 'p', 'k'))
- return AVERROR_INVALIDDATA;
- size = avio_rl32(pb);
- if (size < 24 || size > WV_BLOCK_LIMIT) {
- av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
- return AVERROR_INVALIDDATA;
- }
- wc->blksize = size;
- ver = avio_rl16(pb);
- if (ver < 0x402 || ver > 0x410) {
- av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
- return AVERROR_PATCHWELCOME;
- }
- avio_r8(pb); // track no
- avio_r8(pb); // track sub index
- wc->samples = avio_rl32(pb); // total samples in file
- wc->soff = avio_rl32(pb); // offset in samples of current block
- avio_read(pb, wc->extra, WV_EXTRA_SIZE);
- } else {
- size = wc->blksize;
- }
- wc->flags = AV_RL32(wc->extra + 4);
- /* Blocks with zero samples don't contain actual audio information
- * and should be ignored */
- if (!AV_RN32(wc->extra))
- return 0;
- // parse flags
- bpp = ((wc->flags & 3) + 1) << 3;
- chan = 1 + !(wc->flags & WV_MONO);
- chmask = wc->flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
- rate = wv_rates[(wc->flags >> 23) & 0xF];
- wc->multichannel = !!((wc->flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK);
- if (wc->multichannel) {
- chan = wc->chan;
- chmask = wc->chmask;
- }
- if ((rate == -1 || !chan) && !wc->block_parsed) {
- int64_t block_end = avio_tell(pb) + wc->blksize - 24;
- if (!pb->seekable) {
- av_log(ctx, AV_LOG_ERROR,
- "Cannot determine additional parameters\n");
- return AVERROR_INVALIDDATA;
- }
- while (avio_tell(pb) < block_end) {
- int id, size;
- id = avio_r8(pb);
- size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb);
- size <<= 1;
- if (id & 0x40)
- size--;
- switch (id & 0x3F) {
- case 0xD:
- if (size <= 1) {
- av_log(ctx, AV_LOG_ERROR,
- "Insufficient channel information\n");
- return AVERROR_INVALIDDATA;
- }
- chan = avio_r8(pb);
- switch (size - 2) {
- case 0:
- chmask = avio_r8(pb);
- break;
- case 1:
- chmask = avio_rl16(pb);
- break;
- case 2:
- chmask = avio_rl24(pb);
- break;
- case 3:
- chmask = avio_rl32(pb);
- break;
- case 5:
- avio_skip(pb, 1);
- chan |= (avio_r8(pb) & 0xF) << 8;
- chmask = avio_rl24(pb);
- break;
- default:
- av_log(ctx, AV_LOG_ERROR,
- "Invalid channel info size %d\n", size);
- return AVERROR_INVALIDDATA;
- }
- break;
- case 0x27:
- rate = avio_rl24(pb);
- break;
- default:
- avio_skip(pb, size);
- }
- if (id & 0x40)
- avio_skip(pb, 1);
- }
- if (rate == -1) {
- av_log(ctx, AV_LOG_ERROR,
- "Cannot determine custom sampling rate\n");
- return AVERROR_INVALIDDATA;
- }
- avio_seek(pb, block_end - wc->blksize + 24, SEEK_SET);
- }
- if (!wc->bpp)
- wc->bpp = bpp;
- if (!wc->chan)
- wc->chan = chan;
- if (!wc->chmask)
- wc->chmask = chmask;
- if (!wc->rate)
- wc->rate = rate;
-
- if (wc->flags && bpp != wc->bpp) {
- av_log(ctx, AV_LOG_ERROR,
- "Bits per sample differ, this block: %i, header block: %i\n",
- bpp, wc->bpp);
- return AVERROR_INVALIDDATA;
- }
- if (wc->flags && !wc->multichannel && chan != wc->chan) {
- av_log(ctx, AV_LOG_ERROR,
- "Channels differ, this block: %i, header block: %i\n",
- chan, wc->chan);
+ if (AV_RL32(data) != MKTAG('w', 'v', 'p', 'k'))
return AVERROR_INVALIDDATA;
- }
- if (wc->flags && rate != -1 && rate != wc->rate) {
- av_log(ctx, AV_LOG_ERROR,
- "Sampling rate differ, this block: %i, header block: %i\n",
- rate, wc->rate);
- return AVERROR_INVALIDDATA;
- }
- wc->blksize = size - 24;
- return 0;
-}
-static int wv_read_header(AVFormatContext *s)
-{
- AVIOContext *pb = s->pb;
- WVContext *wc = s->priv_data;
- AVStream *st;
- int ret;
-
- wc->block_parsed = 0;
- for (;;) {
- if ((ret = wv_read_block_header(s, pb, 0)) < 0)
- return ret;
- if (!AV_RN32(wc->extra))
- avio_skip(pb, wc->blksize - 24);
- else
- break;
- }
-
- /* now we are ready: build format streams */
- st = avformat_new_stream(s, NULL);
- if (!st)
- return AVERROR(ENOMEM);
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_WAVPACK;
- st->codec->channels = wc->chan;
- st->codec->channel_layout = wc->chmask;
- st->codec->sample_rate = wc->rate;
- st->codec->bits_per_coded_sample = wc->bpp;
- avpriv_set_pts_info(st, 64, 1, wc->rate);
- st->start_time = 0;
- if (wc->samples != 0xFFFFFFFFu)
- st->duration = wc->samples;
-
- if (s->pb->seekable) {
- int64_t cur = avio_tell(s->pb);
- wc->apetag_start = ff_ape_parse_tag(s);
- if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
- ff_id3v1_read(s);
- avio_seek(s->pb, cur, SEEK_SET);
- }
-
- return 0;
-}
-
-static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- WVContext *wc = s->priv_data;
- int ret;
- int size, ver, off;
- int64_t pos;
- uint32_t block_samples;
-
- if (url_feof(s->pb))
- return AVERROR_EOF;
- if (wc->block_parsed) {
- if ((ret = wv_read_block_header(s, s->pb, 0)) < 0)
- return ret;
- }
-
- pos = wc->pos;
- off = wc->multichannel ? 4 : 0;
- if (av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE + off) < 0)
- return AVERROR(ENOMEM);
- if (wc->multichannel)
- AV_WL32(pkt->data, wc->blksize + WV_EXTRA_SIZE + 12);
- memcpy(pkt->data + off, wc->extra, WV_EXTRA_SIZE);
- ret = avio_read(s->pb, pkt->data + WV_EXTRA_SIZE + off, wc->blksize);
- if (ret != wc->blksize) {
- av_free_packet(pkt);
- return AVERROR(EIO);
- }
- while (!(wc->flags & WV_END_BLOCK)) {
- if (avio_rl32(s->pb) != MKTAG('w', 'v', 'p', 'k')) {
- av_free_packet(pkt);
- return AVERROR_INVALIDDATA;
- }
- if ((ret = av_append_packet(s->pb, pkt, 4)) < 0) {
- av_free_packet(pkt);
- return ret;
- }
- size = AV_RL32(pkt->data + pkt->size - 4);
- if (size < 24 || size > WV_BLOCK_LIMIT) {
- av_free_packet(pkt);
- av_log(s, AV_LOG_ERROR, "Incorrect block size %d\n", size);
- return AVERROR_INVALIDDATA;
- }
- wc->blksize = size;
- ver = avio_rl16(s->pb);
- if (ver < 0x402 || ver > 0x410) {
- av_free_packet(pkt);
- av_log(s, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
- return AVERROR_PATCHWELCOME;
- }
- avio_r8(s->pb); // track no
- avio_r8(s->pb); // track sub index
- wc->samples = avio_rl32(s->pb); // total samples in file
- wc->soff = avio_rl32(s->pb); // offset in samples of current block
- if ((ret = av_append_packet(s->pb, pkt, WV_EXTRA_SIZE)) < 0) {
- av_free_packet(pkt);
- return ret;
- }
- memcpy(wc->extra, pkt->data + pkt->size - WV_EXTRA_SIZE, WV_EXTRA_SIZE);
-
- if ((ret = wv_read_block_header(s, s->pb, 1)) < 0) {
- av_free_packet(pkt);
- return ret;
- }
- ret = av_append_packet(s->pb, pkt, wc->blksize);
- if (ret < 0) {
- av_free_packet(pkt);
- return ret;
- }
- }
- pkt->stream_index = 0;
- wc->block_parsed = 1;
- pkt->pts = wc->soff;
- block_samples = AV_RL32(wc->extra);
- if (block_samples > INT32_MAX)
- av_log(s, AV_LOG_WARNING,
- "Too many samples in block: %"PRIu32"\n", block_samples);
- else
- pkt->duration = block_samples;
-
- av_add_index_entry(s->streams[0], pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME);
- return 0;
-}
+ wv->blocksize = AV_RL32(data + 4);
+ if (wv->blocksize < 24 || wv->blocksize > WV_BLOCK_LIMIT)
+ return AVERROR_INVALIDDATA;
+ wv->blocksize -= 24;
-static int wv_read_seek(AVFormatContext *s, int stream_index,
- int64_t timestamp, int flags)
-{
- AVStream *st = s->streams[stream_index];
- WVContext *wc = s->priv_data;
- AVPacket pkt1, *pkt = &pkt1;
- int ret;
- int index = av_index_search_timestamp(st, timestamp, flags);
- int64_t pos, pts;
+ wv->version = AV_RL16(data + 8);
+ wv->total_samples = AV_RL32(data + 12);
+ wv->block_idx = AV_RL32(data + 16);
+ wv->samples = AV_RL32(data + 20);
+ wv->flags = AV_RL32(data + 24);
+ wv->crc = AV_RL32(data + 28);
- /* if found, seek there */
- if (index >= 0 &&
- timestamp <= st->index_entries[st->nb_index_entries - 1].timestamp) {
- wc->block_parsed = 1;
- avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
- return 0;
- }
- /* if timestamp is out of bounds, return error */
- if (timestamp < 0 || timestamp >= s->duration)
- return AVERROR(EINVAL);
+ wv->initial = !!(wv->flags & WV_FLAG_INITIAL_BLOCK);
+ wv->final = !!(wv->flags & WV_FLAG_FINAL_BLOCK);
- pos = avio_tell(s->pb);
- do {
- ret = av_read_frame(s, pkt);
- if (ret < 0) {
- avio_seek(s->pb, pos, SEEK_SET);
- return ret;
- }
- pts = pkt->pts;
- av_free_packet(pkt);
- } while(pts < timestamp);
return 0;
}
-
-AVInputFormat ff_wv_demuxer = {
- .name = "wv",
- .long_name = NULL_IF_CONFIG_SMALL("WavPack"),
- .priv_data_size = sizeof(WVContext),
- .read_probe = wv_probe,
- .read_header = wv_read_header,
- .read_packet = wv_read_packet,
- .read_seek = wv_read_seek,
-};
diff --git a/ffmpeg/libavformat/wvenc.c b/ffmpeg/libavformat/wvenc.c
index 03d471e..b0d74ca 100644
--- a/ffmpeg/libavformat/wvenc.c
+++ b/ffmpeg/libavformat/wvenc.c
@@ -1,5 +1,6 @@
/*
* WavPack muxer
+ * Copyright (c) 2013 Konstantin Shishkov <kostya.shishkov@gmail.com>
* Copyright (c) 2012 Paul B Mahol
*
* This file is part of FFmpeg.
@@ -19,126 +20,72 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/intreadwrite.h"
-#include "avformat.h"
-#include "internal.h"
-#include "avio_internal.h"
-#include "apetag.h"
+#include "libavutil/attributes.h"
-#define WV_EXTRA_SIZE 12
-#define WV_END_BLOCK 0x1000
+#include "apetag.h"
+#include "avformat.h"
+#include "wv.h"
-typedef struct{
- uint32_t duration;
-} WVMuxContext;
+typedef struct WvMuxContext {
+ int64_t samples;
+} WvMuxContext;
-static int write_header(AVFormatContext *s)
+static av_cold int wv_write_header(AVFormatContext *ctx)
{
- AVCodecContext *codec = s->streams[0]->codec;
-
- if (s->nb_streams > 1) {
- av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
- return AVERROR(EINVAL);
- }
- if (codec->codec_id != AV_CODEC_ID_WAVPACK) {
- av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ if (ctx->nb_streams > 1 ||
+ ctx->streams[0]->codec->codec_id != AV_CODEC_ID_WAVPACK) {
+ av_log(ctx, AV_LOG_ERROR, "This muxer only supports a single WavPack stream.\n");
return AVERROR(EINVAL);
}
- if (codec->extradata_size > 0) {
- avpriv_report_missing_feature(s, "remuxing from matroska container");
- return AVERROR_PATCHWELCOME;
- }
- avpriv_set_pts_info(s->streams[0], 64, 1, codec->sample_rate);
return 0;
}
-static int write_packet(AVFormatContext *s, AVPacket *pkt)
+static int wv_write_packet(AVFormatContext *ctx, AVPacket *pkt)
{
- WVMuxContext *wc = s->priv_data;
- AVCodecContext *codec = s->streams[0]->codec;
- AVIOContext *pb = s->pb;
- uint64_t size;
- uint32_t flags;
- uint32_t left = pkt->size;
- uint8_t *ptr = pkt->data;
- int off = codec->channels > 2 ? 4 : 0;
+ WvMuxContext *s = ctx->priv_data;
+ WvHeader header;
+ int ret;
- /* FIXME: Simplify decoder/demuxer so bellow code can support midstream
- * change of stream parameters */
- wc->duration += pkt->duration;
- ffio_wfourcc(pb, "wvpk");
- if (off) {
- size = AV_RL32(pkt->data);
- if (size <= 12)
- return AVERROR_INVALIDDATA;
- size -= 12;
- } else {
- size = pkt->size;
+ if (pkt->size < WV_HEADER_SIZE ||
+ (ret = ff_wv_parse_header(&header, pkt->data)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid WavPack packet.\n");
+ return AVERROR(EINVAL);
}
+ s->samples += header.samples;
- if (size + off > left)
- return AVERROR_INVALIDDATA;
-
- avio_wl32(pb, size + 12);
- avio_wl16(pb, 0x410);
- avio_w8(pb, 0);
- avio_w8(pb, 0);
- avio_wl32(pb, -1);
- avio_wl32(pb, pkt->pts);
- ptr += off; left -= off;
- flags = AV_RL32(ptr + 4);
- avio_write(pb, ptr, size);
- ptr += size; left -= size;
-
- while (!(flags & WV_END_BLOCK) &&
- (left >= 4 + WV_EXTRA_SIZE)) {
- ffio_wfourcc(pb, "wvpk");
- size = AV_RL32(ptr);
- ptr += 4; left -= 4;
- if (size < 24 || size - 24 > left)
- return AVERROR_INVALIDDATA;
- avio_wl32(pb, size);
- avio_wl16(pb, 0x410);
- avio_w8(pb, 0);
- avio_w8(pb, 0);
- avio_wl32(pb, -1);
- avio_wl32(pb, pkt->pts);
- flags = AV_RL32(ptr + 4);
- avio_write(pb, ptr, WV_EXTRA_SIZE);
- ptr += WV_EXTRA_SIZE; left -= WV_EXTRA_SIZE;
- avio_write(pb, ptr, size - 24);
- ptr += size - 24; left -= size - 24;
- }
- avio_flush(pb);
+ avio_write(ctx->pb, pkt->data, pkt->size);
return 0;
}
-static int write_trailer(AVFormatContext *s)
+static av_cold int wv_write_trailer(AVFormatContext *ctx)
{
- WVMuxContext *wc = s->priv_data;
- AVIOContext *pb = s->pb;
-
- ff_ape_write(s);
-
- if (pb->seekable) {
- avio_seek(pb, 12, SEEK_SET);
- avio_wl32(pb, wc->duration);
- avio_flush(pb);
+ WvMuxContext *s = ctx->priv_data;
+
+ /* update total number of samples in the first block */
+ if (ctx->pb->seekable && s->samples &&
+ s->samples < UINT32_MAX) {
+ int64_t pos = avio_tell(ctx->pb);
+ avio_seek(ctx->pb, 12, SEEK_SET);
+ avio_wl32(ctx->pb, s->samples);
+ avio_seek(ctx->pb, pos, SEEK_SET);
}
+ ff_ape_write_tag(ctx);
return 0;
}
AVOutputFormat ff_wv_muxer = {
.name = "wv",
- .long_name = NULL_IF_CONFIG_SMALL("WavPack"),
- .priv_data_size = sizeof(WVMuxContext),
+ .long_name = NULL_IF_CONFIG_SMALL("raw WavPack"),
+ .mime_type = "audio/x-wavpack",
.extensions = "wv",
+ .priv_data_size = sizeof(WvMuxContext),
.audio_codec = AV_CODEC_ID_WAVPACK,
.video_codec = AV_CODEC_ID_NONE,
- .write_header = write_header,
- .write_packet = write_packet,
- .write_trailer = write_trailer,
+ .write_header = wv_write_header,
+ .write_packet = wv_write_packet,
+ .write_trailer = wv_write_trailer,
+ .flags = AVFMT_NOTIMESTAMPS,
};
diff --git a/ffmpeg/libavformat/xa.c b/ffmpeg/libavformat/xa.c
index e3d36e6..43661de 100644
--- a/ffmpeg/libavformat/xa.c
+++ b/ffmpeg/libavformat/xa.c
@@ -59,7 +59,7 @@ static int xa_probe(AVProbeData *p)
if (!channels || channels > 8 || !srate || srate > 192000 ||
bits_per_sample < 4 || bits_per_sample > 32)
return 0;
- return AVPROBE_SCORE_MAX/2;
+ return AVPROBE_SCORE_EXTENSION;
}
static int xa_read_header(AVFormatContext *s)
@@ -84,6 +84,9 @@ static int xa_read_header(AVFormatContext *s)
avio_skip(pb, 2); /* Skip block align */
avio_skip(pb, 2); /* Skip bits-per-sample */
+ if (!st->codec->channels || !st->codec->sample_rate)
+ return AVERROR_INVALIDDATA;
+
st->codec->bit_rate = av_clip(15LL * st->codec->channels * 8 *
st->codec->sample_rate / 28, 0, INT_MAX);
diff --git a/ffmpeg/libavformat/xmv.c b/ffmpeg/libavformat/xmv.c
index e970477..20f9bea 100644
--- a/ffmpeg/libavformat/xmv.c
+++ b/ffmpeg/libavformat/xmv.c
@@ -49,6 +49,8 @@
XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \
XMV_AUDIO_ADPCM51_REARLEFTRIGHT)
+#define XMV_BLOCK_ALIGN_SIZE 36
+
/** A video packet with an XMV file. */
typedef struct XMVVideoPacket {
int stream_index; ///< The decoder stream index for this video packet.
@@ -124,6 +126,15 @@ static int xmv_probe(AVProbeData *p)
return 0;
}
+static int xmv_read_close(AVFormatContext *s)
+{
+ XMVDemuxContext *xmv = s->priv_data;
+
+ av_freep(&xmv->audio);
+
+ return 0;
+}
+
static int xmv_read_header(AVFormatContext *s)
{
XMVDemuxContext *xmv = s->priv_data;
@@ -133,6 +144,7 @@ static int xmv_read_header(AVFormatContext *s)
uint32_t file_version;
uint32_t this_packet_size;
uint16_t audio_track;
+ int ret;
avio_skip(pb, 4); /* Next packet size */
@@ -171,8 +183,10 @@ static int xmv_read_header(AVFormatContext *s)
avio_skip(pb, 2); /* Unknown (padding?) */
xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket));
- if (!xmv->audio)
- return AVERROR(ENOMEM);
+ if (!xmv->audio) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
XMVAudioPacket *packet = &xmv->audio[audio_track];
@@ -184,15 +198,10 @@ static int xmv_read_header(AVFormatContext *s)
packet->bits_per_sample = avio_rl16(pb);
packet->flags = avio_rl16(pb);
- if (!packet->channels) {
- av_log(s, AV_LOG_ERROR, "0 channels\n");
- return AVERROR(EINVAL);
- }
-
packet->bit_rate = packet->bits_per_sample *
packet->sample_rate *
packet->channels;
- packet->block_align = 36 * packet->channels;
+ packet->block_align = XMV_BLOCK_ALIGN_SIZE * packet->channels;
packet->block_samples = 64;
packet->codec_id = ff_wav_codec_get_id(packet->compression,
packet->bits_per_sample);
@@ -208,9 +217,19 @@ static int xmv_read_header(AVFormatContext *s)
av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream "
"(0x%04X)\n", packet->flags);
+ 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",
+ audio_track);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
ast = avformat_new_stream(s, NULL);
- if (!ast)
- return AVERROR(ENOMEM);
+ if (!ast) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
ast->codec->codec_id = packet->codec_id;
@@ -236,6 +255,10 @@ static int xmv_read_header(AVFormatContext *s)
xmv->stream_count = xmv->audio_track_count + 1;
return 0;
+
+fail:
+ xmv_read_close(s);
+ return ret;
}
static void xmv_read_extradata(uint8_t *extradata, AVIOContext *pb)
@@ -360,9 +383,7 @@ static int xmv_process_packet_header(AVFormatContext *s)
if (vst->codec->extradata_size < 4) {
av_free(vst->codec->extradata);
- vst->codec->extradata =
- av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- vst->codec->extradata_size = 4;
+ ff_alloc_extradata(vst->codec, 4);
}
memcpy(vst->codec->extradata, xmv->video.extradata, 4);
@@ -546,15 +567,6 @@ static int xmv_read_packet(AVFormatContext *s,
return 0;
}
-static int xmv_read_close(AVFormatContext *s)
-{
- XMVDemuxContext *xmv = s->priv_data;
-
- av_freep(&xmv->audio);
-
- return 0;
-}
-
AVInputFormat ff_xmv_demuxer = {
.name = "xmv",
.long_name = NULL_IF_CONFIG_SMALL("Microsoft XMV"),
diff --git a/ffmpeg/libavformat/xwma.c b/ffmpeg/libavformat/xwma.c
index 0d40bd7..e629b3f 100644
--- a/ffmpeg/libavformat/xwma.c
+++ b/ffmpeg/libavformat/xwma.c
@@ -20,6 +20,7 @@
*/
#include <inttypes.h>
+#include <stdint.h>
#include "avformat.h"
#include "internal.h"
@@ -199,8 +200,10 @@ static int xwma_read_header(AVFormatContext *s)
/* Estimate the duration from the total number of output bytes. */
const uint64_t total_decoded_bytes = dpds_table[dpds_table_size - 1];
- if(!bytes_per_sample) {
- av_log(s, AV_LOG_ERROR, "bytes_per_sample is 0\n");
+ if (!bytes_per_sample) {
+ 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;
}
diff --git a/ffmpeg/libavformat/yop.c b/ffmpeg/libavformat/yop.c
index d1c0129..07086d5 100644
--- a/ffmpeg/libavformat/yop.c
+++ b/ffmpeg/libavformat/yop.c
@@ -69,12 +69,7 @@ static int yop_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
// Extra data that will be passed to the decoder
- video_stream->codec->extradata_size = 8;
-
- video_stream->codec->extradata = av_mallocz(video_stream->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
-
- if (!video_stream->codec->extradata)
+ if (ff_alloc_extradata(video_stream->codec, 8))
return AVERROR(ENOMEM);
// Audio
@@ -136,6 +131,12 @@ static int yop_read_packet(AVFormatContext *s, AVPacket *pkt)
if (yop->video_packet.data) {
*pkt = yop->video_packet;
yop->video_packet.data = NULL;
+ yop->video_packet.buf = NULL;
+#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ yop->video_packet.destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
yop->video_packet.size = 0;
pkt->data[0] = yop->odd_frame;
pkt->flags |= AV_PKT_FLAG_KEY;
diff --git a/ffmpeg/libavformat/yuv4mpeg.c b/ffmpeg/libavformat/yuv4mpeg.c
index f34a4af..1999c73 100644
--- a/ffmpeg/libavformat/yuv4mpeg.c
+++ b/ffmpeg/libavformat/yuv4mpeg.c
@@ -22,7 +22,6 @@
#include "libavutil/pixdesc.h"
#include "avformat.h"
#include "internal.h"
-#include "libavutil/pixdesc.h"
#define Y4M_MAGIC "YUV4MPEG2"
#define Y4M_FRAME_MAGIC "FRAME"
@@ -217,8 +216,8 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
// Adjust for smaller Cb and Cr planes
av_pix_fmt_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift,
&v_chroma_shift);
- width >>= h_chroma_shift;
- height >>= v_chroma_shift;
+ width = FF_CEIL_RSHIFT(width, h_chroma_shift);
+ height = FF_CEIL_RSHIFT(height, v_chroma_shift);
ptr1 = picture->data[1];
ptr2 = picture->data[2];
@@ -232,7 +231,6 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
}
}
- avio_flush(pb);
return 0;
}