[FFmpeg-cvslog] Merge commit '83548fe894cdb455cc127f754d09905b6d23c173'
James Almer
git at videolan.org
Tue Mar 21 22:03:43 EET 2017
ffmpeg | branch: master | James Almer <jamrial at gmail.com> | Tue Mar 21 17:02:30 2017 -0300| [4de591e6fb7361bd417dcd9563672ed0ad8b361b] | committer: James Almer
Merge commit '83548fe894cdb455cc127f754d09905b6d23c173'
* commit '83548fe894cdb455cc127f754d09905b6d23c173':
lavf: fix usage of AVIOContext.seekable
Merged-by: James Almer <jamrial at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4de591e6fb7361bd417dcd9563672ed0ad8b361b
---
libavformat/aacdec.c | 2 +-
libavformat/adp.c | 2 +-
libavformat/aiffdec.c | 4 ++--
libavformat/aiffenc.c | 4 ++--
libavformat/ape.c | 2 +-
libavformat/apngenc.c | 2 +-
libavformat/asfdec_o.c | 8 +++++---
libavformat/asfenc.c | 6 +++---
libavformat/astenc.c | 2 +-
libavformat/au.c | 2 +-
libavformat/avidec.c | 4 ++--
libavformat/avienc.c | 24 ++++++++++++------------
libavformat/aviobuf.c | 2 +-
libavformat/bink.c | 2 +-
libavformat/bintext.c | 8 ++++----
libavformat/cafdec.c | 4 ++--
libavformat/cafenc.c | 4 ++--
libavformat/cinedec.c | 2 +-
libavformat/dsfdec.c | 2 +-
libavformat/dtshddec.c | 2 +-
libavformat/dv.c | 2 +-
libavformat/ffmdec.c | 4 ++--
libavformat/filmstripdec.c | 2 +-
libavformat/flacenc.c | 2 +-
libavformat/flvdec.c | 7 ++++---
libavformat/gxfenc.c | 2 +-
libavformat/icoenc.c | 2 +-
libavformat/id3v1.c | 2 +-
libavformat/ivfenc.c | 2 +-
libavformat/matroskadec.c | 2 +-
libavformat/matroskaenc.c | 32 ++++++++++++++++----------------
libavformat/mlvdec.c | 2 +-
libavformat/mmf.c | 2 +-
libavformat/mov.c | 16 ++++++++--------
libavformat/movenc.c | 2 +-
libavformat/mp3dec.c | 2 +-
libavformat/mp3enc.c | 2 +-
libavformat/mpc.c | 2 +-
libavformat/mpc8.c | 2 +-
libavformat/mpeg.c | 2 +-
libavformat/mpegts.c | 2 +-
libavformat/mvdec.c | 4 ++--
libavformat/mxfdec.c | 4 ++--
libavformat/mxfenc.c | 2 +-
libavformat/nutdec.c | 2 +-
libavformat/oggdec.c | 6 +++---
libavformat/r3d.c | 2 +-
libavformat/rawenc.c | 2 +-
libavformat/rmdec.c | 3 ++-
libavformat/rmenc.c | 6 +++---
libavformat/rsd.c | 12 ++++++------
libavformat/rsoenc.c | 2 +-
libavformat/smjpegenc.c | 2 +-
libavformat/soxenc.c | 2 +-
libavformat/swfenc.c | 2 +-
libavformat/takdec.c | 2 +-
libavformat/tta.c | 2 +-
libavformat/tty.c | 2 +-
libavformat/utils.c | 2 +-
libavformat/vc1testenc.c | 2 +-
libavformat/voc_packet.c | 2 +-
libavformat/wavdec.c | 6 +++---
libavformat/wavenc.c | 8 ++++----
libavformat/wvdec.c | 4 ++--
libavformat/wvenc.c | 2 +-
65 files changed, 134 insertions(+), 130 deletions(-)
diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
index fecb1e3..5ab5197 100644
--- a/libavformat/aacdec.c
+++ b/libavformat/aacdec.c
@@ -89,7 +89,7 @@ static int adts_aac_read_header(AVFormatContext *s)
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
ff_id3v1_read(s);
- if (s->pb->seekable &&
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
int64_t cur = avio_tell(s->pb);
ff_ape_parse_tag(s);
diff --git a/libavformat/adp.c b/libavformat/adp.c
index 9ab2ec4..7355503 100644
--- a/libavformat/adp.c
+++ b/libavformat/adp.c
@@ -59,7 +59,7 @@ static int adp_read_header(AVFormatContext *s)
st->codecpar->channels = 2;
st->codecpar->sample_rate = 48000;
st->start_time = 0;
- if (s->pb->seekable)
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = av_get_audio_frame_duration2(st->codecpar, avio_size(s->pb));
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c
index 3bbe4a0..7dcc85f 100644
--- a/libavformat/aiffdec.c
+++ b/libavformat/aiffdec.c
@@ -288,9 +288,9 @@ static int aiff_read_header(AVFormatContext *s)
offset = avio_rb32(pb); /* Offset of sound data */
avio_rb32(pb); /* BlockSize... don't care */
offset += avio_tell(pb); /* Compute absolute data offset */
- if (st->codecpar->block_align && !pb->seekable) /* Assume COMM already parsed */
+ if (st->codecpar->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) /* Assume COMM already parsed */
goto got_sound;
- if (!pb->seekable) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "file is not seekable\n");
return -1;
}
diff --git a/libavformat/aiffenc.c b/libavformat/aiffenc.c
index 74b778b..fcadf14 100644
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@ -49,7 +49,7 @@ static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
AVIOContext *pb = s->pb;
AVPacketList *pict_list = aiff->pict_list;
- if (!pb->seekable)
+ if (!pb->seekable & AVIO_SEEKABLE_NORMAL)
return 0;
if (!s->metadata && !aiff->pict_list)
@@ -267,7 +267,7 @@ static int aiff_write_trailer(AVFormatContext *s)
end_size++;
}
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* Number of sample frames */
avio_seek(pb, aiff->frames, SEEK_SET);
avio_wb32(pb, (file_size - aiff->ssnd - 12) / par->block_align);
diff --git a/libavformat/ape.c b/libavformat/ape.c
index 061f328..50a1aa1 100644
--- a/libavformat/ape.c
+++ b/libavformat/ape.c
@@ -374,7 +374,7 @@ static int ape_read_header(AVFormatContext * s)
}
/* try to read APE tags */
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
ff_ape_parse_tag(s);
avio_seek(pb, 0, SEEK_SET);
}
diff --git a/libavformat/apngenc.c b/libavformat/apngenc.c
index 0c40be2..378a9b3 100644
--- a/libavformat/apngenc.c
+++ b/libavformat/apngenc.c
@@ -258,7 +258,7 @@ static int apng_write_trailer(AVFormatContext *format_context)
apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
- if (apng->acTL_offset && io_context->seekable) {
+ if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
avio_seek(io_context, apng->acTL_offset, SEEK_SET);
AV_WB32(buf, apng->frame_number);
diff --git a/libavformat/asfdec_o.c b/libavformat/asfdec_o.c
index 56f8446..f7000b0 100644
--- a/libavformat/asfdec_o.c
+++ b/libavformat/asfdec_o.c
@@ -960,7 +960,7 @@ static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g)
size, asf->nb_packets);
avio_skip(pb, 2); // skip reserved field
asf->first_packet_offset = avio_tell(pb);
- if (pb->seekable && !(asf->b_flags & ASF_FLAG_BROADCAST))
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !(asf->b_flags & ASF_FLAG_BROADCAST))
align_position(pb, asf->offset, asf->data_size);
return 0;
@@ -1738,7 +1738,9 @@ static int asf_read_header(AVFormatContext *s)
size = avio_rl64(pb);
align_position(pb, asf->offset, size);
}
- if (asf->data_reached && (!pb->seekable || (asf->b_flags & ASF_FLAG_BROADCAST)))
+ if (asf->data_reached &&
+ (!(pb->seekable & AVIO_SEEKABLE_NORMAL) ||
+ (asf->b_flags & ASF_FLAG_BROADCAST)))
break;
}
@@ -1747,7 +1749,7 @@ static int asf_read_header(AVFormatContext *s)
ret = AVERROR_INVALIDDATA;
goto failed;
}
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
avio_seek(pb, asf->first_packet_offset, SEEK_SET);
for (i = 0; i < asf->nb_streams; i++) {
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index 19dee3d..1b67143 100644
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@ -473,7 +473,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avio_wl64(pb, duration); /* end time stamp (in 100ns units) */
avio_wl64(pb, asf->duration); /* duration (in 100ns units) */
avio_wl64(pb, PREROLL_TIME); /* start time stamp */
- avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2); /* ??? */
+ avio_wl32(pb, (asf->is_streamed || !(pb->seekable & AVIO_SEEKABLE_NORMAL)) ? 3 : 2); /* ??? */
avio_wl32(pb, s->packet_size); /* packet size */
avio_wl32(pb, s->packet_size); /* packet size */
avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */
@@ -530,7 +530,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avio_wl32(pb, 5000); /* maximum buffer size ms */
avio_wl32(pb, 0); /* max initial buffer fullness */
avio_wl32(pb, 0); /* max object size */
- avio_wl32(pb, (!asf->is_streamed && pb->seekable) << 1); /* flags - seekable */
+ avio_wl32(pb, (!asf->is_streamed && (pb->seekable & AVIO_SEEKABLE_NORMAL)) << 1); /* flags - seekable */
avio_wl16(pb, n + 1); /* stream number */
avio_wl16(pb, asf->streams[n].stream_language_index); /* language id index */
avio_wl64(pb, 0); /* avg time per frame */
@@ -1135,7 +1135,7 @@ static int asf_write_trailer(AVFormatContext *s)
}
avio_flush(s->pb);
- if (asf->is_streamed || !s->pb->seekable) {
+ if (asf->is_streamed || !(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
put_chunk(s, 0x4524, 0, 0); /* end of stream */
} else {
/* rewrite an updated header */
diff --git a/libavformat/astenc.c b/libavformat/astenc.c
index 11f8717..578e658 100644
--- a/libavformat/astenc.c
+++ b/libavformat/astenc.c
@@ -139,7 +139,7 @@ static int ast_write_trailer(AVFormatContext *s)
av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* Number of samples */
avio_seek(pb, ast->samples, SEEK_SET);
avio_wb32(pb, samples);
diff --git a/libavformat/au.c b/libavformat/au.c
index f70f827..520824f 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -321,7 +321,7 @@ static int au_write_trailer(AVFormatContext *s)
AUContext *au = s->priv_data;
int64_t file_size = avio_tell(pb);
- if (s->pb->seekable && file_size < INT32_MAX) {
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && file_size < INT32_MAX) {
/* update file size */
avio_seek(pb, 8, SEEK_SET);
avio_wb32(pb, (uint32_t)(file_size - au->header_size));
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index abe8c98..e2527a1 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -948,7 +948,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
break;
case MKTAG('i', 'n', 'd', 'x'):
pos = avio_tell(pb);
- if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !(s->flags & AVFMT_FLAG_IGNIDX) &&
avi->use_odml &&
read_odml_index(s, 0) < 0 &&
(s->error_recognition & AV_EF_EXPLODE))
@@ -1022,7 +1022,7 @@ fail:
return AVERROR_INVALIDDATA;
}
- if (!avi->index_loaded && pb->seekable)
+ if (!avi->index_loaded && (pb->seekable & AVIO_SEEKABLE_NORMAL))
avi_load_index(s);
calculate_bitrate(s);
avi->index_loaded |= 1;
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index 4b042a9..91b8c40 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -332,7 +332,7 @@ static int avi_write_header(AVFormatContext *s)
avio_wl32(pb, 0);
avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
avio_wl32(pb, 0); /* padding */
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */
else
avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
@@ -414,7 +414,7 @@ static int avi_write_header(AVFormatContext *s)
avio_wl32(pb, 0); /* start */
/* remember this offset to fill later */
avist->frames_hdr_strm = avio_tell(pb);
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
/* FIXME: this may be broken, but who cares */
avio_wl32(pb, AVI_MAX_RIFF_SIZE);
else
@@ -493,7 +493,7 @@ static int avi_write_header(AVFormatContext *s)
}
}
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
write_odml_master(s, i);
}
@@ -534,7 +534,7 @@ static int avi_write_header(AVFormatContext *s)
ff_end_tag(pb, list2);
}
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* AVI could become an OpenDML one, if it grows beyond 2Gb range */
avi->odml_list = ff_start_tag(pb, "JUNK");
ffio_wfourcc(pb, "odml");
@@ -611,7 +611,7 @@ static int avi_write_ix(AVFormatContext *s)
char ix_tag[] = "ix00";
int i, j;
- av_assert0(pb->seekable);
+ av_assert0(pb->seekable & AVIO_SEEKABLE_NORMAL);
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
@@ -669,7 +669,7 @@ static int avi_write_idx1(AVFormatContext *s)
int i;
char tag[5];
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
AVIStream *avist;
AVIIentry *ie = 0, *tie;
int empty, stream_id = -1;
@@ -783,7 +783,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
av_assert0(par->bits_per_coded_sample >= 0 && par->bits_per_coded_sample <= 8);
- if (pb->seekable && avist->pal_offset) {
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && avist->pal_offset) {
int64_t cur_offset = avio_tell(pb);
avio_seek(pb, avist->pal_offset, SEEK_SET);
for (i = 0; i < pal_size; i++) {
@@ -798,7 +798,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
unsigned char tag[5];
avi_stream2fourcc(tag, stream_index, par->codec_type);
tag[2] = 'p'; tag[3] = 'c';
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (avist->strh_flags_offset) {
int64_t cur_offset = avio_tell(pb);
avio_seek(pb, avist->strh_flags_offset, SEEK_SET);
@@ -854,7 +854,7 @@ static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
avist->packet_count++;
// Make sure to put an OpenDML chunk when the file size exceeds the limits
- if (pb->seekable &&
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) &&
(avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
avi_write_ix(s);
ff_end_tag(pb, avi->movi_list);
@@ -872,7 +872,7 @@ static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
if (par->codec_type == AVMEDIA_TYPE_AUDIO)
avist->audio_strm_length += size;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
int ret;
ret = avi_add_ientry(s, stream_index, NULL, flags, size);
if (ret < 0)
@@ -901,7 +901,7 @@ static int avi_write_trailer(AVFormatContext *s)
write_skip_frames(s, i, avist->last_dts);
}
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (avi->riff_id == 1) {
ff_end_tag(pb, avi->movi_list);
res = avi_write_idx1(s);
@@ -950,7 +950,7 @@ static int avi_write_trailer(AVFormatContext *s)
av_freep(&avist->indexes.cluster[j]);
av_freep(&avist->indexes.cluster);
avist->indexes.ents_allocated = avist->indexes.entry = 0;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
avio_seek(pb, avist->frames_hdr_strm + 4, SEEK_SET);
avio_wl32(pb, avist->max_size);
}
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 4ade4d0..5f58ab0 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -269,7 +269,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
offset1 >= 0 && offset1 <= buffer_size - s->write_flag) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
- } else if ((!s->seekable ||
+ } else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) ||
offset1 <= buffer_size + short_seek) &&
!s->write_flag && offset1 >= 0 &&
(!s->direct || !s->seek) &&
diff --git a/libavformat/bink.c b/libavformat/bink.c
index e6f0cb7..20dba67 100644
--- a/libavformat/bink.c
+++ b/libavformat/bink.c
@@ -292,7 +292,7 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, in
BinkDemuxContext *bink = s->priv_data;
AVStream *vst = s->streams[0];
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return -1;
/* seek to the first frame */
diff --git a/libavformat/bintext.c b/libavformat/bintext.c
index a264fd1..12e3bfd 100644
--- a/libavformat/bintext.c
+++ b/libavformat/bintext.c
@@ -141,7 +141,7 @@ static int bintext_read_header(AVFormatContext *s)
st->codecpar->extradata[0] = 16;
st->codecpar->extradata[1] = 0;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int got_width = 0;
bin->fsize = avio_size(pb);
if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
@@ -199,7 +199,7 @@ static int xbin_read_header(AVFormatContext *s)
if (avio_read(pb, st->codecpar->extradata + 2, st->codecpar->extradata_size - 2) < 0)
return AVERROR(EIO);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
bin->fsize = avio_size(pb) - 9 - st->codecpar->extradata_size;
ff_sauce_read(s, &bin->fsize, NULL, 0);
avio_seek(pb, 9 + st->codecpar->extradata_size, SEEK_SET);
@@ -237,7 +237,7 @@ static int adf_read_header(AVFormatContext *s)
if (avio_read(pb, st->codecpar->extradata + 2 + 48, 4096) < 0)
return AVERROR(EIO);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int got_width = 0;
bin->fsize = avio_size(pb) - 1 - 192 - 4096;
st->codecpar->width = 80<<3;
@@ -271,7 +271,7 @@ static int idf_read_header(AVFormatContext *s)
AVStream *st;
int got_width = 0;
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
st = init_stream(s);
diff --git a/libavformat/cafdec.c b/libavformat/cafdec.c
index 0e6179a..fc85fd9 100644
--- a/libavformat/cafdec.c
+++ b/libavformat/cafdec.c
@@ -257,7 +257,7 @@ static int read_header(AVFormatContext *s)
/* stop at data chunk if seeking is not supported or
data chunk size is unknown */
- if (found_data && (caf->data_size < 0 || !pb->seekable))
+ if (found_data && (caf->data_size < 0 || !(pb->seekable & AVIO_SEEKABLE_NORMAL)))
break;
tag = avio_rb32(pb);
@@ -271,7 +271,7 @@ static int read_header(AVFormatContext *s)
avio_skip(pb, 4); /* edit count */
caf->data_start = avio_tell(pb);
caf->data_size = size < 0 ? -1 : size - 4;
- if (caf->data_size > 0 && pb->seekable)
+ if (caf->data_size > 0 && (pb->seekable & AVIO_SEEKABLE_NORMAL))
avio_skip(pb, caf->data_size);
found_data = 1;
break;
diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c
index 5ea8e69..7aa9e8c 100644
--- a/libavformat/cafenc.c
+++ b/libavformat/cafenc.c
@@ -126,7 +126,7 @@ static int caf_write_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- if (!par->block_align && !pb->seekable) {
+ if (!par->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n");
return AVERROR_INVALIDDATA;
}
@@ -236,7 +236,7 @@ static int caf_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVCodecParameters *par = s->streams[0]->codecpar;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t file_size = avio_tell(pb);
avio_seek(pb, caf->data, SEEK_SET);
diff --git a/libavformat/cinedec.c b/libavformat/cinedec.c
index 32cccf5..763b93b 100644
--- a/libavformat/cinedec.c
+++ b/libavformat/cinedec.c
@@ -307,7 +307,7 @@ static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t time
if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
return AVERROR(ENOSYS);
- if (!avctx->pb->seekable)
+ if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
cine->pts = timestamp;
diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c
index f16b397..49ca336 100644
--- a/libavformat/dsfdec.c
+++ b/libavformat/dsfdec.c
@@ -77,7 +77,7 @@ static int dsf_read_header(AVFormatContext *s)
avio_skip(pb, 8);
id3pos = avio_rl64(pb);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
read_id3(s, id3pos);
avio_seek(pb, 28, SEEK_SET);
}
diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c
index f5f0407..1bd403c 100644
--- a/libavformat/dtshddec.c
+++ b/libavformat/dtshddec.c
@@ -89,7 +89,7 @@ static int dtshd_read_header(AVFormatContext *s)
dtshd->data_end = data_start + chunk_size;
if (dtshd->data_end <= chunk_size)
return AVERROR_INVALIDDATA;
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
goto break_loop;
goto skip;
break;
diff --git a/libavformat/dv.c b/libavformat/dv.c
index 89a9e10..06de044 100644
--- a/libavformat/dv.c
+++ b/libavformat/dv.c
@@ -534,7 +534,7 @@ static int dv_read_header(AVFormatContext *s)
(AVRational) { 8, 1 },
c->dv_demux->sys->time_base);
- if (s->pb->seekable)
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
dv_read_timecode(s);
return 0;
diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c
index f863bf7..de6ac27 100644
--- a/libavformat/ffmdec.c
+++ b/libavformat/ffmdec.c
@@ -300,7 +300,7 @@ static int ffm2_read_header(AVFormatContext *s)
ffm->write_index = avio_rb64(pb);
/* get also filesize */
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
ffm->file_size = avio_size(pb);
if (ffm->write_index && 0)
adjust_write_index(s);
@@ -559,7 +559,7 @@ static int ffm_read_header(AVFormatContext *s)
}
ffm->write_index = avio_rb64(pb);
/* get also filesize */
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
ffm->file_size = avio_size(pb);
if (ffm->write_index && 0)
adjust_write_index(s);
diff --git a/libavformat/filmstripdec.c b/libavformat/filmstripdec.c
index 0aeb594..0bf5a80 100644
--- a/libavformat/filmstripdec.c
+++ b/libavformat/filmstripdec.c
@@ -41,7 +41,7 @@ static int read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVStream *st;
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
avio_seek(pb, avio_size(pb) - 36, SEEK_SET);
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index 89b21e9..b894f9e 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -147,7 +147,7 @@ static int flac_write_trailer(struct AVFormatContext *s)
if (!c->write_header || !streaminfo)
return 0;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* rewrite the STREAMINFO header block data */
file_size = avio_tell(pb);
avio_seek(pb, 8, SEEK_SET);
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 3959a36..cdcfb9c 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -484,7 +484,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
break;
case AMF_DATA_TYPE_OBJECT:
if (key &&
- ioc->seekable &&
+ (ioc->seekable & AVIO_SEEKABLE_NORMAL) &&
!strcmp(KEYFRAMES_TAG, key) && depth == 1)
if (parse_keyframes_index(s, ioc,
max_pos) < 0)
@@ -1040,7 +1040,7 @@ skip:
}
av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard);
- if (s->pb->seekable &&
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
((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);
@@ -1056,7 +1056,8 @@ skip:
// 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) &&
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
+ (!s->duration || s->duration == AV_NOPTS_VALUE) &&
!flv->searched_for_end) {
int size;
const int64_t pos = avio_tell(s->pb);
diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c
index 79951b5..0e0772b 100644
--- a/libavformat/gxfenc.c
+++ b/libavformat/gxfenc.c
@@ -709,7 +709,7 @@ static int gxf_write_header(AVFormatContext *s)
int ret;
AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
- if (!pb->seekable) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome\n");
return -1;
}
diff --git a/libavformat/icoenc.c b/libavformat/icoenc.c
index a7ada19..e641f7b 100644
--- a/libavformat/icoenc.c
+++ b/libavformat/icoenc.c
@@ -82,7 +82,7 @@ static int ico_write_header(AVFormatContext *s)
int ret;
int i;
- if (!pb->seekable) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "Output is not seekable\n");
return AVERROR(EINVAL);
}
diff --git a/libavformat/id3v1.c b/libavformat/id3v1.c
index 218ed73..19be421 100644
--- a/libavformat/id3v1.c
+++ b/libavformat/id3v1.c
@@ -238,7 +238,7 @@ void ff_id3v1_read(AVFormatContext *s)
uint8_t buf[ID3v1_TAG_SIZE];
int64_t filesize, position = avio_tell(s->pb);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* XXX: change that */
filesize = avio_size(s->pb);
if (filesize > 128) {
diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
index f3ae4dc..fdc0ee0 100644
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@ -75,7 +75,7 @@ static int ivf_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
IVFEncContext *ctx = s->priv_data;
- if (pb->seekable && ctx->frame_cnt > 1) {
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && ctx->frame_cnt > 1) {
size_t end = avio_tell(pb);
avio_seek(pb, 24, SEEK_SET);
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index bad034b..2e3c9bf 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1616,7 +1616,7 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
int i;
// we should not do any seeking in the streaming case
- if (!matroska->ctx->pb->seekable)
+ if (!(matroska->ctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
return;
for (i = 0; i < seekhead_list->nb_elem; i++) {
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index df77313..af941ce 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -333,7 +333,7 @@ static int start_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matros
if ((ret = avio_open_dyn_buf(dyn_cp)) < 0)
return ret;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
*master = start_ebml_master(pb, elementid, expectedsize);
if (mkv->write_crc && mkv->mode != MODE_WEBM)
put_ebml_void(*dyn_cp, 6); /* Reserve space for CRC32 so position/size calculations using avio_tell() take it into account */
@@ -349,7 +349,7 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matrosk
uint8_t *buf, crc[4];
int size, skip = 0;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
size = avio_close_dyn_buf(*dyn_cp, &buf);
if (mkv->write_crc && mkv->mode != MODE_WEBM) {
skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */
@@ -373,7 +373,7 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matrosk
static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv,
ebml_master master)
{
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
uint8_t *buf;
int size = avio_get_dyn_buf(*dyn_cp, &buf);
@@ -1419,7 +1419,7 @@ static int mkv_write_tracks(AVFormatContext *s)
return ret;
}
- if (pb->seekable && !mkv->is_live)
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
else
end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
@@ -1614,7 +1614,7 @@ static int mkv_write_tags(AVFormatContext *s)
if (ret < 0) return ret;
}
- if (s->pb->seekable && !mkv->is_live) {
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {
for (i = 0; i < s->nb_streams; i++) {
AVIOContext *pb;
AVStream *st = s->streams[i];
@@ -1664,7 +1664,7 @@ static int mkv_write_tags(AVFormatContext *s)
}
if (mkv->tags.pos) {
- if (s->pb->seekable && !mkv->is_live)
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, mkv->tags);
else
end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags);
@@ -1921,7 +1921,7 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_void(pb, 11); // assumes double-precision float to be written
}
}
- if (s->pb->seekable && !mkv->is_live)
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, mkv->info);
else
end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, mkv->info);
@@ -1952,7 +1952,7 @@ static int mkv_write_header(AVFormatContext *s)
goto fail;
}
- if (!s->pb->seekable && !mkv->is_live)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
mkv_write_seekhead(pb, mkv);
mkv->cues = mkv_start_cues(mkv->segment_offset);
@@ -1960,7 +1960,7 @@ static int mkv_write_header(AVFormatContext *s)
ret = AVERROR(ENOMEM);
goto fail;
}
- if (pb->seekable && mkv->reserve_cues_space) {
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mkv->reserve_cues_space) {
mkv->cues_pos = avio_tell(pb);
put_ebml_void(pb, mkv->reserve_cues_space);
}
@@ -1973,7 +1973,7 @@ static int mkv_write_header(AVFormatContext *s)
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
// after 4k and on a keyframe
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (mkv->cluster_time_limit < 0)
mkv->cluster_time_limit = 5000;
if (mkv->cluster_size_limit < 0)
@@ -2198,7 +2198,7 @@ static void mkv_start_new_cluster(AVFormatContext *s, AVPacket *pkt)
end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster);
mkv->cluster_pos = -1;
- if (s->pb->seekable)
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
av_log(s, AV_LOG_DEBUG,
"Starting new cluster at offset %" PRIu64 " bytes, "
"pts %" PRIu64 "dts %" PRIu64 "\n",
@@ -2223,7 +2223,7 @@ static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt)
switch (par->codec_id) {
case AV_CODEC_ID_FLAC:
- if (side_data_size && s->pb->seekable) {
+ if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
AVCodecParameters *codecpriv_par;
int64_t curpos;
if (side_data_size != par->extradata_size) {
@@ -2296,7 +2296,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_
if (par->codec_type != AVMEDIA_TYPE_SUBTITLE) {
mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
- if (s->pb->seekable && (par->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue)) {
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && (par->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue)) {
ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, mkv->cluster_pos, relative_packet_pos, -1);
if (ret < 0) return ret;
}
@@ -2321,7 +2321,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
end_ebml_master(pb, blockgroup);
}
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts,
mkv->cluster_pos, relative_packet_pos, duration);
if (ret < 0)
@@ -2421,7 +2421,7 @@ static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt)
if (mkv->cluster_pos != -1) {
end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster);
mkv->cluster_pos = -1;
- if (s->pb->seekable)
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
av_log(s, AV_LOG_DEBUG,
"Flushing cluster at offset %" PRIu64 " bytes\n",
avio_tell(s->pb));
@@ -2462,7 +2462,7 @@ static int mkv_write_trailer(AVFormatContext *s)
return ret;
}
- if (pb->seekable && !mkv->is_live) {
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {
if (mkv->cues->num_entries) {
if (mkv->reserve_cues_space) {
int64_t cues_end;
diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c
index 665b28d..90c3779 100644
--- a/libavformat/mlvdec.c
+++ b/libavformat/mlvdec.c
@@ -449,7 +449,7 @@ static int read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp
if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
return AVERROR(ENOSYS);
- if (!avctx->pb->seekable)
+ if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
mlv->pts = timestamp;
diff --git a/libavformat/mmf.c b/libavformat/mmf.c
index b8a9cad..1393627 100644
--- a/libavformat/mmf.c
+++ b/libavformat/mmf.c
@@ -147,7 +147,7 @@ static int mmf_write_trailer(AVFormatContext *s)
int64_t pos, size;
int gatetime;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* Fill in length fields */
end_tag_be(pb, mmf->awapos);
end_tag_be(pb, mmf->atrpos);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index f7dd250..3754346 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1166,7 +1166,7 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
if (!c->has_looked_for_mfra && c->use_mfra_for > 0) {
c->has_looked_for_mfra = 1;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int ret;
av_log(c->fc, AV_LOG_VERBOSE, "stream has moof boxes, will look "
"for a mfra\n");
@@ -5421,9 +5421,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return err;
}
if (c->found_moov && c->found_mdat &&
- ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) ||
+ ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) ||
start_pos + a.size == avio_size(pb))) {
- if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete)
c->next_root_atom = start_pos + a.size;
c->atom_depth --;
return 0;
@@ -5935,7 +5935,7 @@ static int mov_read_header(AVFormatContext *s)
mov->fc = s;
mov->trak_index = -1;
/* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
atom.size = avio_size(pb);
else
atom.size = INT64_MAX;
@@ -5949,7 +5949,7 @@ static int mov_read_header(AVFormatContext *s)
mov_read_close(s);
return err;
}
- } while (pb->seekable && !mov->found_moov && !mov->moov_retry++);
+ } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++);
if (!mov->found_moov) {
av_log(s, AV_LOG_ERROR, "moov atom not found\n");
mov_read_close(s);
@@ -5957,7 +5957,7 @@ static int mov_read_header(AVFormatContext *s)
}
av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (mov->nb_chapter_tracks > 0 && !mov->ignore_chapters)
mov_read_chapters(s);
for (i = 0; i < s->nb_streams; i++)
@@ -6118,8 +6118,8 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
AVIndexEntry *current_sample = &avst->index_entries[msc->current_sample];
int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale);
av_log(s, AV_LOG_TRACE, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts);
- if (!sample || (!s->pb->seekable && current_sample->pos < sample->pos) ||
- (s->pb->seekable &&
+ if (!sample || (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && current_sample->pos < sample->pos) ||
+ ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb &&
((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) ||
(FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) {
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index a286210..11b2670 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -5616,7 +5616,7 @@ static int mov_init(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 &&
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
(!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead)) {
av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
return AVERROR(EINVAL);
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index b45a066..0924a57 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -370,7 +370,7 @@ static int mp3_read_header(AVFormatContext *s)
if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
ff_id3v1_read(s);
- if(s->pb->seekable)
+ if(s->pb->seekable & AVIO_SEEKABLE_NORMAL)
mp3->filesize = avio_size(s->pb);
if (mp3_parse_vbr_tags(s, st, off) < 0)
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 49f3742..0348622 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -144,7 +144,7 @@ static int mp3_write_xing(AVFormatContext *s)
int ver = 0;
int bytes_needed;
- if (!s->pb->seekable || !mp3->write_xing)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) || !mp3->write_xing)
return 0;
for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) {
diff --git a/libavformat/mpc.c b/libavformat/mpc.c
index 4bd1f50..af33374 100644
--- a/libavformat/mpc.c
+++ b/libavformat/mpc.c
@@ -104,7 +104,7 @@ static int mpc_read_header(AVFormatContext *s)
st->duration = c->fcount;
/* try to read APE tags */
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t pos = avio_tell(s->pb);
ff_ape_parse_tag(s);
if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c
index 05d0c1a..180c554 100644
--- a/libavformat/mpc8.c
+++ b/libavformat/mpc8.c
@@ -264,7 +264,7 @@ static int mpc8_read_header(AVFormatContext *s)
if (size > 0)
avio_skip(pb, size);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t pos = avio_tell(s->pb);
c->apetag_start = ff_ape_parse_tag(s);
avio_seek(s->pb, pos, SEEK_SET);
diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c
index a651cb3..68a848a 100644
--- a/libavformat/mpeg.c
+++ b/libavformat/mpeg.c
@@ -451,7 +451,7 @@ redo:
int i;
for (i = 0; i < s->nb_streams; i++) {
if (startcode == s->streams[i]->id &&
- s->pb->seekable /* index useless on streams anyway */) {
+ (s->pb->seekable & AVIO_SEEKABLE_NORMAL) /* index useless on streams anyway */) {
ff_reduce_index(s, i);
av_add_index_entry(s->streams[i], *ppos, dts, 0, 0,
AVINDEX_KEYFRAME /* FIXME keyframe? */);
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 590abb0..3eff152 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -2605,7 +2605,7 @@ static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) {
* 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");
+ av_log(s, (pb->seekable & AVIO_SEEKABLE_NORMAL) ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
}
static int mpegts_read_header(AVFormatContext *s)
diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c
index f0a29eb..0e12c8c 100644
--- a/libavformat/mvdec.c
+++ b/libavformat/mvdec.c
@@ -421,7 +421,7 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
if (index->pos > pos)
avio_skip(pb, index->pos - pos);
else if (index->pos < pos) {
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
ret = avio_seek(pb, index->pos, SEEK_SET);
if (ret < 0)
@@ -463,7 +463,7 @@ static int mv_read_seek(AVFormatContext *avctx, int stream_index,
if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
return AVERROR(ENOSYS);
- if (!avctx->pb->seekable)
+ if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
frame = av_index_search_timestamp(st, timestamp, flags);
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 2ad0c28..f8d0f9e 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -2590,7 +2590,7 @@ static int mxf_parse_handle_essence(MXFContext *mxf)
/* 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) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing FooterPartition\n");
return -1;
}
@@ -2777,7 +2777,7 @@ static void mxf_read_random_index_pack(AVFormatContext *s)
int64_t file_size, max_rip_length, min_rip_length;
KLVPacket klv;
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return;
file_size = avio_size(s->pb);
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index afea117..12fc9ab 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -2549,7 +2549,7 @@ static int mxf_write_footer(AVFormatContext *s)
mxf_write_klv_fill(s);
mxf_write_random_index_pack(s);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (s->oformat == &ff_mxf_opatom_muxer){
/* rewrite body partition to update lengths */
avio_seek(pb, mxf->body_partition_offset[0], SEEK_SET);
diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c
index 2e309bc..ca34e35 100644
--- a/libavformat/nutdec.c
+++ b/libavformat/nutdec.c
@@ -876,7 +876,7 @@ static int nut_read_header(AVFormatContext *s)
s->internal->data_offset = pos - 8;
- if (bc->seekable) {
+ if (bc->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t orig_pos = avio_tell(bc);
find_and_decode_index(nut);
avio_seek(bc, orig_pos, SEEK_SET);
diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index edeae2b..97ad1a2 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -209,7 +209,7 @@ static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
const struct ogg_codec *codec;
int i = 0;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
uint8_t magic[8];
int64_t pos = avio_tell(s->pb);
avio_skip(s->pb, nsegs);
@@ -355,7 +355,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid)
sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
break;
- if(!i && bc->seekable && ogg->page_pos > 0) {
+ if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
memset(sync, 0, 4);
avio_seek(bc, ogg->page_pos+4, SEEK_SET);
ogg->page_pos = -1;
@@ -613,7 +613,7 @@ static int ogg_get_length(AVFormatContext *s)
int64_t size, end;
int streams_left=0;
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return 0;
// already set
diff --git a/libavformat/r3d.c b/libavformat/r3d.c
index b609488..1f53d84 100644
--- a/libavformat/r3d.c
+++ b/libavformat/r3d.c
@@ -186,7 +186,7 @@ static int r3d_read_header(AVFormatContext *s)
s->internal->data_offset = avio_tell(s->pb);
av_log(s, AV_LOG_TRACE, "data offset %#"PRIx64"\n", s->internal->data_offset);
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return 0;
// find REOB/REOF/REOS to load index
avio_seek(s->pb, avio_size(s->pb)-48-8, SEEK_SET);
diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
index 0edcd1c..26baa85 100644
--- a/libavformat/rawenc.c
+++ b/libavformat/rawenc.c
@@ -65,7 +65,7 @@ static int adx_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVCodecParameters *par = s->streams[0]->codecpar;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t file_size = avio_tell(pb);
uint64_t sample_count = (file_size - 36) / par->channels / 18 * 32;
if (sample_count <= UINT32_MAX) {
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index 222c433..e6a1fe8 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -651,7 +651,8 @@ static int rm_read_header(AVFormatContext *s)
if (!data_off)
data_off = avio_tell(pb) - 18;
- if (indx_off && pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
+ if (indx_off && (pb->seekable & AVIO_SEEKABLE_NORMAL) &&
+ !(s->flags & AVFMT_FLAG_IGNIDX) &&
avio_seek(pb, indx_off, SEEK_SET) >= 0) {
rm_read_index(s);
avio_seek(pb, data_off + 18, SEEK_SET);
diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c
index 0bc5bfd..f9821d1 100644
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@ -123,7 +123,7 @@ static int rv10_write_header(AVFormatContext *ctx,
avio_wb32(s, 0); /* data offset : will be patched after */
avio_wb16(s, ctx->nb_streams); /* num streams */
flags = 1 | 2; /* save allowed & perfect play */
- if (!s->seekable)
+ if (!(s->seekable & AVIO_SEEKABLE_NORMAL))
flags |= 4; /* live broadcast */
avio_wb16(s, flags);
@@ -175,7 +175,7 @@ static int rv10_write_header(AVFormatContext *ctx,
avio_wb32(s, 0); /* start time */
avio_wb32(s, BUFFER_DURATION); /* preroll */
/* duration */
- if (!s->seekable || !stream->total_frames)
+ if (!(s->seekable & AVIO_SEEKABLE_NORMAL) || !stream->total_frames)
avio_wb32(s, (int)(3600 * 1000));
else
avio_wb32(s, av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO));
@@ -444,7 +444,7 @@ static int rm_write_trailer(AVFormatContext *s)
int data_size, index_pos, i;
AVIOContext *pb = s->pb;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* end of file: finish to write header */
index_pos = avio_tell(pb);
data_size = index_pos - rm->data_pos;
diff --git a/libavformat/rsd.c b/libavformat/rsd.c
index 5a56e72..27a3d73 100644
--- a/libavformat/rsd.c
+++ b/libavformat/rsd.c
@@ -106,12 +106,12 @@ static int rsd_read_header(AVFormatContext *s)
break;
case AV_CODEC_ID_ADPCM_PSX:
par->block_align = 16 * par->channels;
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
break;
case AV_CODEC_ID_ADPCM_IMA_RAD:
par->block_align = 20 * par->channels;
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
break;
case AV_CODEC_ID_ADPCM_IMA_WAV:
@@ -120,7 +120,7 @@ static int rsd_read_header(AVFormatContext *s)
par->bits_per_coded_sample = 4;
par->block_align = 36 * par->channels;
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
break;
case AV_CODEC_ID_ADPCM_THP_LE:
@@ -131,7 +131,7 @@ static int rsd_read_header(AVFormatContext *s)
if ((ret = ff_get_extradata(s, par, s->pb, 32)) < 0)
return ret;
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
break;
case AV_CODEC_ID_ADPCM_THP:
@@ -145,7 +145,7 @@ static int rsd_read_header(AVFormatContext *s)
avio_read(s->pb, st->codecpar->extradata + 32 * i, 32);
avio_skip(s->pb, 8);
}
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = (avio_size(pb) - start) / (8 * par->channels) * 14;
break;
case AV_CODEC_ID_PCM_S16LE:
@@ -153,7 +153,7 @@ static int rsd_read_header(AVFormatContext *s)
if (version != 4)
start = avio_rl32(pb);
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
st->duration = (avio_size(pb) - start) / 2 / par->channels;
break;
}
diff --git a/libavformat/rsoenc.c b/libavformat/rsoenc.c
index 3c5c118..60ebac8 100644
--- a/libavformat/rsoenc.c
+++ b/libavformat/rsoenc.c
@@ -38,7 +38,7 @@ static int rso_write_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- if (!s->pb->seekable) {
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
return AVERROR_INVALIDDATA;
}
diff --git a/libavformat/smjpegenc.c b/libavformat/smjpegenc.c
index 314593a..68a1286 100644
--- a/libavformat/smjpegenc.c
+++ b/libavformat/smjpegenc.c
@@ -121,7 +121,7 @@ static int smjpeg_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t currentpos;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
currentpos = avio_tell(pb);
avio_seek(pb, 12, SEEK_SET);
avio_wb32(pb, smc->duration);
diff --git a/libavformat/soxenc.c b/libavformat/soxenc.c
index b307157..7b37bd4 100644
--- a/libavformat/soxenc.c
+++ b/libavformat/soxenc.c
@@ -91,7 +91,7 @@ static int sox_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVCodecParameters *par = s->streams[0]->codecpar;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
/* update number of samples */
int64_t file_size = avio_tell(pb);
int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL;
diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c
index 3733a04..cada45e 100644
--- a/libavformat/swfenc.c
+++ b/libavformat/swfenc.c
@@ -500,7 +500,7 @@ static int swf_write_trailer(AVFormatContext *s)
put_swf_end_tag(s);
/* patch file size and number of frames if not streamed */
- if (s->pb->seekable && video_par) {
+ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && video_par) {
file_size = avio_tell(pb);
avio_seek(pb, 4, SEEK_SET);
avio_wl32(pb, file_size);
diff --git a/libavformat/takdec.c b/libavformat/takdec.c
index a8fb363..1535bec 100644
--- a/libavformat/takdec.c
+++ b/libavformat/takdec.c
@@ -128,7 +128,7 @@ static int tak_read_header(AVFormatContext *s)
case TAK_METADATA_END: {
int64_t curpos = avio_tell(pb);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
ff_ape_parse_tag(s);
avio_seek(pb, curpos, SEEK_SET);
}
diff --git a/libavformat/tta.c b/libavformat/tta.c
index 1447eff..ae90a85 100644
--- a/libavformat/tta.c
+++ b/libavformat/tta.c
@@ -136,7 +136,7 @@ static int tta_read_header(AVFormatContext *s)
st->codecpar->sample_rate = samplerate;
st->codecpar->bits_per_coded_sample = bps;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t pos = avio_tell(s->pb);
ff_ape_parse_tag(s);
avio_seek(s->pb, pos, SEEK_SET);
diff --git a/libavformat/tty.c b/libavformat/tty.c
index b407645..8d48f2c 100644
--- a/libavformat/tty.c
+++ b/libavformat/tty.c
@@ -94,7 +94,7 @@ static int read_header(AVFormatContext *avctx)
/* simulate tty display speed */
s->chars_per_frame = FFMAX(av_q2d(st->time_base)*s->chars_per_frame, 1);
- if (avctx->pb->seekable) {
+ if (avctx->pb->seekable & AVIO_SEEKABLE_NORMAL) {
s->fsize = avio_size(avctx->pb);
st->duration = (s->fsize + s->chars_per_frame - 1) / s->chars_per_frame;
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 8227d1b..a059046 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -2857,7 +2857,7 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
if ((!strcmp(ic->iformat->name, "mpeg") ||
!strcmp(ic->iformat->name, "mpegts")) &&
- file_size && ic->pb->seekable) {
+ file_size && (ic->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
/* get accurate estimate from the PTSes */
estimate_timings_from_pts(ic, old_offset);
ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
diff --git a/libavformat/vc1testenc.c b/libavformat/vc1testenc.c
index 60fb894..cf95d1d 100644
--- a/libavformat/vc1testenc.c
+++ b/libavformat/vc1testenc.c
@@ -73,7 +73,7 @@ static int vc1test_write_trailer(AVFormatContext *s)
RCVContext *ctx = s->priv_data;
AVIOContext *pb = s->pb;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
avio_seek(pb, 0, SEEK_SET);
avio_wl24(pb, ctx->frames);
avio_flush(pb);
diff --git a/libavformat/voc_packet.c b/libavformat/voc_packet.c
index 4f60467..1e2e19e 100644
--- a/libavformat/voc_packet.c
+++ b/libavformat/voc_packet.c
@@ -49,7 +49,7 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
return AVERROR_EOF;
voc->remaining_size = avio_rl24(pb);
if (!voc->remaining_size) {
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
voc->remaining_size = avio_size(pb) - avio_tell(pb);
}
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index 0ca1ef4..a3cd4ff 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -410,7 +410,7 @@ static int wav_read_header(AVFormatContext *s)
got_xma2 = 1;
break;
case MKTAG('d', 'a', 't', 'a'):
- if (!pb->seekable && !got_fmt && !got_xma2) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) && !got_fmt && !got_xma2) {
av_log(s, AV_LOG_ERROR,
"found no 'fmt ' tag before the 'data' tag\n");
return AVERROR_INVALIDDATA;
@@ -433,7 +433,7 @@ static int wav_read_header(AVFormatContext *s)
/* don't look for footer metadata if we can't seek or if we don't
* know where the data tag ends
*/
- if (!pb->seekable || (!rf64 && !size))
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || (!rf64 && !size))
goto break_loop;
break;
case MKTAG('f', 'a', 'c', 't'):
@@ -821,7 +821,7 @@ static int w64_read_header(AVFormatContext *s)
wav->data_end = avio_tell(pb) + size - 24;
data_ofs = avio_tell(pb);
- if (!pb->seekable)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
break;
avio_skip(pb, size - 24);
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index a21d4c5..7f3059e 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -344,7 +344,7 @@ static int wav_write_header(AVFormatContext *s)
}
if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */
- && s->pb->seekable) {
+ && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
wav->fact_pos = ff_start_tag(pb, "fact");
avio_wl32(pb, 0);
ff_end_tag(pb, wav->fact_pos);
@@ -425,7 +425,7 @@ static int wav_write_trailer(AVFormatContext *s)
avio_flush(pb);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (wav->write_peak != 2 && avio_tell(pb) - wav->data < UINT32_MAX) {
ff_end_tag(pb, wav->data);
avio_flush(pb);
@@ -584,7 +584,7 @@ static int w64_write_header(AVFormatContext *s)
end_guid(pb, start);
if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */
- && s->pb->seekable) {
+ && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
start_guid(pb, ff_w64_guid_fact, &wav->fact_pos);
avio_wl64(pb, 0);
end_guid(pb, wav->fact_pos);
@@ -601,7 +601,7 @@ static int w64_write_trailer(AVFormatContext *s)
WAVMuxContext *wav = s->priv_data;
int64_t file_size;
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
end_guid(pb, wav->data);
file_size = avio_tell(pb);
diff --git a/libavformat/wvdec.c b/libavformat/wvdec.c
index 1ec52f6..261fcaf 100644
--- a/libavformat/wvdec.c
+++ b/libavformat/wvdec.c
@@ -119,7 +119,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb)
}
if ((rate == -1 || !chan) && !wc->block_parsed) {
int64_t block_end = avio_tell(pb) + wc->header.blocksize;
- if (!pb->seekable) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(ctx, AV_LOG_ERROR,
"Cannot determine additional parameters\n");
return AVERROR_INVALIDDATA;
@@ -241,7 +241,7 @@ static int wv_read_header(AVFormatContext *s)
if (wc->header.total_samples != 0xFFFFFFFFu)
st->duration = wc->header.total_samples;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
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))
diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c
index 48e371a..8743739 100644
--- a/libavformat/wvenc.c
+++ b/libavformat/wvenc.c
@@ -64,7 +64,7 @@ static av_cold int wv_write_trailer(AVFormatContext *ctx)
WvMuxContext *s = ctx->priv_data;
/* update total number of samples in the first block */
- if (ctx->pb->seekable && s->samples &&
+ if ((ctx->pb->seekable & AVIO_SEEKABLE_NORMAL) && s->samples &&
s->samples < UINT32_MAX) {
int64_t pos = avio_tell(ctx->pb);
avio_seek(ctx->pb, 12, SEEK_SET);
======================================================================
diff --cc libavformat/aacdec.c
index fecb1e3,2f20792..5ab5197
--- a/libavformat/aacdec.c
+++ b/libavformat/aacdec.c
@@@ -86,15 -84,9 +86,15 @@@ static int adts_aac_read_header(AVForma
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
st->codecpar->codec_id = s->iformat->raw_codec_id;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
ff_id3v1_read(s);
- if (s->pb->seekable &&
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
+ !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 --cc libavformat/adp.c
index 9ab2ec4,0000000..7355503
mode 100644,000000..100644
--- a/libavformat/adp.c
+++ b/libavformat/adp.c
@@@ -1,98 -1,0 +1,98 @@@
+/*
+ * ADP demuxer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+
+static int adp_probe(AVProbeData *p)
+{
+ int i, changes = 0;
+ char last = 0;
+
+ if (p->buf_size < 32)
+ return 0;
+
+ for (i = 0; i < p->buf_size - 3; i+=32) {
+ if (p->buf[i] != p->buf[i+2] || p->buf[i+1] != p->buf[i+3])
+ return 0;
+ if (p->buf[i] != last)
+ changes++;
+ last = p->buf[i];
+ }
+ if (changes <= 1)
+ return 0;
+
+ return p->buf_size < 260 ? 1 : AVPROBE_SCORE_MAX / 4;
+}
+
+static int adp_read_header(AVFormatContext *s)
+{
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->codec_id = AV_CODEC_ID_ADPCM_DTK;
+ st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
+ st->codecpar->channels = 2;
+ st->codecpar->sample_rate = 48000;
+ st->start_time = 0;
- if (s->pb->seekable)
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = av_get_audio_frame_duration2(st->codecpar, avio_size(s->pb));
+
+ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+
+ return 0;
+}
+
+static int adp_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int ret, size = 1024;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+
+ if (ret != size) {
+ if (ret < 0) {
+ av_packet_unref(pkt);
+ return ret;
+ }
+ av_shrink_packet(pkt, ret);
+ }
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_adp_demuxer = {
+ .name = "adp",
+ .long_name = NULL_IF_CONFIG_SMALL("ADP"),
+ .read_probe = adp_probe,
+ .read_header = adp_read_header,
+ .read_packet = adp_read_packet,
+ .extensions = "adp,dtk",
+};
diff --cc libavformat/aiffdec.c
index 3bbe4a0,481a92d..7dcc85f
--- a/libavformat/aiffdec.c
+++ b/libavformat/aiffdec.c
@@@ -288,9 -249,9 +288,9 @@@ static int aiff_read_header(AVFormatCon
offset = avio_rb32(pb); /* Offset of sound data */
avio_rb32(pb); /* BlockSize... don't care */
offset += avio_tell(pb); /* Compute absolute data offset */
- if (st->codecpar->block_align && !pb->seekable) /* Assume COMM already parsed */
- if (st->codecpar->block_align) /* Assume COMM already parsed */
++ if (st->codecpar->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) /* Assume COMM already parsed */
goto got_sound;
- if (!pb->seekable) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
av_log(s, AV_LOG_ERROR, "file is not seekable\n");
return -1;
}
diff --cc libavformat/aiffenc.c
index 74b778b,191e746..fcadf14
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@@ -35,69 -31,8 +35,69 @@@ typedef struct AIFFOutputContext
int64_t form;
int64_t frames;
int64_t ssnd;
+ int audio_stream_idx;
+ AVPacketList *pict_list;
+ int write_id3v2;
+ int id3v2_version;
} AIFFOutputContext;
+static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
+{
+ int ret;
+ uint64_t pos, end, size;
+ ID3v2EncContext id3v2 = { 0 };
+ AVIOContext *pb = s->pb;
+ AVPacketList *pict_list = aiff->pict_list;
+
- if (!pb->seekable)
++ if (!pb->seekable & AVIO_SEEKABLE_NORMAL)
+ return 0;
+
+ if (!s->metadata && !aiff->pict_list)
+ return 0;
+
+ avio_wl32(pb, MKTAG('I', 'D', '3', ' '));
+ avio_wb32(pb, 0);
+ pos = avio_tell(pb);
+
+ ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC);
+ ff_id3v2_write_metadata(s, &id3v2);
+ while (pict_list) {
+ if ((ret = ff_id3v2_write_apic(s, &id3v2, &pict_list->pkt)) < 0)
+ return ret;
+ pict_list = pict_list->next;
+ }
+ ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding);
+
+ end = avio_tell(pb);
+ size = end - pos;
+
+ /* Update chunk size */
+ avio_seek(pb, pos - 4, SEEK_SET);
+ avio_wb32(pb, size);
+ avio_seek(pb, end, SEEK_SET);
+
+ if (size & 1)
+ avio_w8(pb, 0);
+
+ return 0;
+}
+
+static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
+{
+ AVDictionaryEntry *tag;
+ AVIOContext *pb = s->pb;
+
+ if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
+ int size = strlen(tag->value);
+
+ avio_wl32(pb, id);
+ avio_wb32(pb, FFALIGN(size, 2));
+ avio_write(pb, tag->value, size);
+ if (size & 1)
+ avio_w8(pb, 0);
+ }
+}
+
static int aiff_write_header(AVFormatContext *s)
{
AIFFOutputContext *aiff = s->priv_data;
@@@ -267,7 -129,11 +267,7 @@@ static int aiff_write_trailer(AVFormatC
end_size++;
}
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
- /* File length */
- avio_seek(pb, aiff->form, SEEK_SET);
- avio_wb32(pb, file_size - aiff->form - 4);
-
/* Number of sample frames */
avio_seek(pb, aiff->frames, SEEK_SET);
avio_wb32(pb, (file_size - aiff->ssnd - 12) / par->block_align);
diff --cc libavformat/apngenc.c
index 0c40be2,0000000..378a9b3
mode 100644,000000..100644
--- a/libavformat/apngenc.c
+++ b/libavformat/apngenc.c
@@@ -1,305 -1,0 +1,305 @@@
+/*
+ * APNG muxer
+ * Copyright (c) 2015 Donny Yang
+ *
+ * first version by Donny Yang <work at kota.moe>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavcodec/png.h"
+#include "libavcodec/apng.h"
+
+typedef struct APNGMuxContext {
+ AVClass *class;
+
+ uint32_t plays;
+ AVRational last_delay;
+
+ uint64_t acTL_offset;
+ uint32_t frame_number;
+
+ AVPacket *prev_packet;
+ AVRational prev_delay;
+
+ int framerate_warned;
+
+ uint8_t *extra_data;
+ int extra_data_size;
+} APNGMuxContext;
+
+static uint8_t *apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
+{
+ size_t b;
+ for (b = 0; b < length; b += AV_RB32(buf + b) + 12)
+ if (AV_RB32(&buf[b + 4]) == tag)
+ return &buf[b];
+ return NULL;
+}
+
+static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
+ uint8_t *buf, size_t length)
+{
+ const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+ uint32_t crc = ~0U;
+ uint8_t tagbuf[4];
+
+ av_assert0(crc_table);
+
+ avio_wb32(io_context, length);
+ AV_WB32(tagbuf, tag);
+ crc = av_crc(crc_table, crc, tagbuf, 4);
+ avio_wb32(io_context, tag);
+ if (length > 0) {
+ crc = av_crc(crc_table, crc, buf, length);
+ avio_write(io_context, buf, length);
+ }
+ avio_wb32(io_context, ~crc);
+}
+
+static int apng_write_header(AVFormatContext *format_context)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ AVCodecParameters *par = format_context->streams[0]->codecpar;
+
+ if (format_context->nb_streams != 1 ||
+ format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
+ format_context->streams[0]->codecpar->codec_id != AV_CODEC_ID_APNG) {
+ av_log(format_context, AV_LOG_ERROR,
+ "APNG muxer supports only a single video APNG stream.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
+ av_reduce(&apng->last_delay.num, &apng->last_delay.den,
+ apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
+ av_log(format_context, AV_LOG_WARNING,
+ "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
+ apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
+ }
+
+ avio_wb64(format_context->pb, PNGSIG);
+ // Remaining headers are written when they are copied from the encoder
+
+ if (par->extradata_size) {
+ apng->extra_data = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!apng->extra_data)
+ return AVERROR(ENOMEM);
+ apng->extra_data_size = par->extradata_size;
+ memcpy(apng->extra_data, par->extradata, par->extradata_size);
+ }
+
+ return 0;
+}
+
+static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ AVIOContext *io_context = format_context->pb;
+ AVStream *codec_stream = format_context->streams[0];
+ uint8_t *side_data = NULL;
+ int side_data_size = 0;
+
+ av_assert0(apng->prev_packet);
+
+ side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
+
+ if (side_data_size) {
+ av_freep(&apng->extra_data);
+ apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!apng->extra_data)
+ return AVERROR(ENOMEM);
+ apng->extra_data_size = side_data_size;
+ memcpy(apng->extra_data, side_data, apng->extra_data_size);
+ }
+
+ if (apng->frame_number == 0 && !packet) {
+ uint8_t *existing_acTL_chunk;
+ uint8_t *existing_fcTL_chunk;
+
+ av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
+
+ // Write normal PNG headers without acTL chunk
+ existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
+ if (existing_acTL_chunk) {
+ uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
+ avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
+ avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
+ } else {
+ avio_write(io_context, apng->extra_data, apng->extra_data_size);
+ }
+
+ // Write frame data without fcTL chunk
+ existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
+ if (existing_fcTL_chunk) {
+ uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
+ avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
+ avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
+ } else {
+ avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
+ }
+ } else {
+ uint8_t *existing_fcTL_chunk;
+
+ if (apng->frame_number == 0) {
+ uint8_t *existing_acTL_chunk;
+
+ // Write normal PNG headers
+ avio_write(io_context, apng->extra_data, apng->extra_data_size);
+
+ existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
+ if (!existing_acTL_chunk) {
+ uint8_t buf[8];
+ // Write animation control header
+ apng->acTL_offset = avio_tell(io_context);
+ AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
+ AV_WB32(buf + 4, apng->plays);
+ apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
+ }
+ }
+
+ existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
+ if (existing_fcTL_chunk) {
+ AVRational delay;
+
+ existing_fcTL_chunk += 8;
+ delay.num = AV_RB16(existing_fcTL_chunk + 20);
+ delay.den = AV_RB16(existing_fcTL_chunk + 22);
+
+ if (delay.num == 0 && delay.den == 0) {
+ if (packet) {
+ int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
+ int64_t delay_den_raw = codec_stream->time_base.den;
+ if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
+ !apng->framerate_warned) {
+ av_log(format_context, AV_LOG_WARNING,
+ "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
+ apng->framerate_warned = 1;
+ }
+ } else if (apng->last_delay.num > 0) {
+ delay = apng->last_delay;
+ } else {
+ delay = apng->prev_delay;
+ }
+
+ // Update frame control header with new delay
+ AV_WB16(existing_fcTL_chunk + 20, delay.num);
+ AV_WB16(existing_fcTL_chunk + 22, delay.den);
+ AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
+ }
+ apng->prev_delay = delay;
+ }
+
+ // Write frame data
+ avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
+ }
+ ++apng->frame_number;
+
+ av_packet_unref(apng->prev_packet);
+ if (packet)
+ av_copy_packet(apng->prev_packet, packet);
+ return 0;
+}
+
+static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ int ret;
+
+ if (!apng->prev_packet) {
+ apng->prev_packet = av_malloc(sizeof(*apng->prev_packet));
+ if (!apng->prev_packet)
+ return AVERROR(ENOMEM);
+
+ av_copy_packet(apng->prev_packet, packet);
+ } else {
+ ret = flush_packet(format_context, packet);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int apng_write_trailer(AVFormatContext *format_context)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ AVIOContext *io_context = format_context->pb;
+ uint8_t buf[8];
+ int ret;
+
+ if (apng->prev_packet) {
+ ret = flush_packet(format_context, NULL);
+ av_freep(&apng->prev_packet);
+ if (ret < 0)
+ return ret;
+ }
+
+ apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
+
- if (apng->acTL_offset && io_context->seekable) {
++ if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
+ avio_seek(io_context, apng->acTL_offset, SEEK_SET);
+
+ AV_WB32(buf, apng->frame_number);
+ AV_WB32(buf + 4, apng->plays);
+ apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
+ }
+
+ av_freep(&apng->extra_data);
+ apng->extra_data = 0;
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(APNGMuxContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
+ { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
+ AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
+ { NULL },
+};
+
+static const AVClass apng_muxer_class = {
+ .class_name = "APNG muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .option = options,
+};
+
+AVOutputFormat ff_apng_muxer = {
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
+ .mime_type = "image/png",
+ .extensions = "apng",
+ .priv_data_size = sizeof(APNGMuxContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_APNG,
+ .write_header = apng_write_header,
+ .write_packet = apng_write_packet,
+ .write_trailer = apng_write_trailer,
+ .priv_class = &apng_muxer_class,
+ .flags = AVFMT_VARIABLE_FPS,
+};
diff --cc libavformat/asfdec_o.c
index 56f8446,0000000..f7000b0
mode 100644,000000..100644
--- a/libavformat/asfdec_o.c
+++ b/libavformat/asfdec_o.c
@@@ -1,1790 -1,0 +1,1792 @@@
+/*
+ * Microsoft Advanced Streaming Format demuxer
+ * Copyright (c) 2014 Alexandra Hájková
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bswap.h"
+#include "libavutil/common.h"
+#include "libavutil/dict.h"
+#include "libavutil/internal.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/time_internal.h"
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "avlanguage.h"
+#include "id3v2.h"
+#include "internal.h"
+#include "riff.h"
+#include "asf.h"
+#include "asfcrypt.h"
+
+#define ASF_BOOL 0x2
+#define ASF_WORD 0x5
+#define ASF_GUID 0x6
+#define ASF_DWORD 0x3
+#define ASF_QWORD 0x4
+#define ASF_UNICODE 0x0
+#define ASF_FLAG_BROADCAST 0x1
+#define ASF_BYTE_ARRAY 0x1
+#define ASF_TYPE_AUDIO 0x2
+#define ASF_TYPE_VIDEO 0x1
+#define ASF_STREAM_NUM 0x7F
+#define ASF_MAX_STREAMS 128
+#define BMP_HEADER_SIZE 40
+#define ASF_NUM_OF_PAYLOADS 0x3F
+#define ASF_ERROR_CORRECTION_LENGTH_TYPE 0x60
+#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
+
+typedef struct GUIDParseTable {
+ const char *name;
+ ff_asf_guid guid;
+ int (*read_object)(AVFormatContext *, const struct GUIDParseTable *);
+ int is_subobject;
+} GUIDParseTable;
+
+typedef struct ASFPacket {
+ AVPacket avpkt;
+ int64_t dts;
+ uint32_t frame_num; // ASF payloads with the same number are parts of the same frame
+ int flags;
+ int data_size;
+ int duration;
+ int size_left;
+ uint8_t stream_index;
+} ASFPacket;
+
+typedef struct ASFStream {
+ uint8_t stream_index; // from packet header
+ int index; // stream index in AVFormatContext, set in asf_read_stream_properties
+ int type;
+ int indexed; // added index entries from the Simple Index Object or not
+ int8_t span; // for deinterleaving
+ uint16_t virtual_pkt_len;
+ uint16_t virtual_chunk_len;
+ int16_t lang_idx;
+ ASFPacket pkt;
+} ASFStream;
+
+typedef struct ASFStreamData{
+ char langs[32];
+ AVDictionary *asf_met; // for storing per-stream metadata
+ AVRational aspect_ratio;
+} ASFStreamData;
+
+typedef struct ASFContext {
+ int data_reached;
+ int is_simple_index; // is simple index present or not 1/0
+ int is_header;
+
+ uint64_t preroll;
+ uint64_t nb_packets; // ASF packets
+ uint32_t packet_size;
+ int64_t send_time;
+ int duration;
+
+ uint32_t b_flags; // flags with broadcast flag
+ uint32_t prop_flags; // file properties object flags
+
+ uint64_t data_size; // data object size
+ uint64_t unknown_size; // size of the unknown object
+
+ int64_t offset; // offset of the current object
+
+ int64_t data_offset;
+ int64_t first_packet_offset; // packet offset
+ int64_t unknown_offset; // for top level header objects or subobjects without specified behavior
+
+ // ASF file must not contain more than 128 streams according to the specification
+ ASFStream *asf_st[ASF_MAX_STREAMS];
+ ASFStreamData asf_sd[ASF_MAX_STREAMS];
+ int nb_streams;
+
+ int stream_index; // from packet header, for the subpayload case
+
+ // packet parameters
+ uint64_t sub_header_offset; // offset of subpayload header
+ int64_t sub_dts;
+ uint8_t dts_delta; // for subpayloads
+ uint32_t packet_size_internal; // packet size stored inside ASFPacket, can be 0
+ int64_t packet_offset; // offset of the current packet inside Data Object
+ uint32_t pad_len; // padding after payload
+ uint32_t rep_data_len;
+
+ // packet state
+ uint64_t sub_left; // subpayloads left or not
+ unsigned int nb_sub; // number of subpayloads read so far from the current ASF packet
+ uint16_t mult_sub_len; // total length of subpayloads array inside multiple payload
+ uint64_t nb_mult_left; // multiple payloads left
+ int return_subpayload;
+ enum {
+ PARSE_PACKET_HEADER,
+ READ_SINGLE,
+ READ_MULTI,
+ READ_MULTI_SUB
+ } state;
+} ASFContext;
+
+static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size);
+static const GUIDParseTable *find_guid(ff_asf_guid guid);
+
+static int asf_probe(AVProbeData *pd)
+{
+ /* check file header */
+ if (!ff_guidcmp(pd->buf, &ff_asf_header))
+ return AVPROBE_SCORE_MAX/2;
+ else
+ return 0;
+}
+
+static void swap_guid(ff_asf_guid guid)
+{
+ FFSWAP(unsigned char, guid[0], guid[3]);
+ FFSWAP(unsigned char, guid[1], guid[2]);
+ FFSWAP(unsigned char, guid[4], guid[5]);
+ FFSWAP(unsigned char, guid[6], guid[7]);
+}
+
+static void align_position(AVIOContext *pb, int64_t offset, uint64_t size)
+{
+ if (size < INT64_MAX - offset && avio_tell(pb) != offset + size)
+ avio_seek(pb, offset + size, SEEK_SET);
+}
+
+static int asf_read_unknown(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size = avio_rl64(pb);
+ int ret;
+
+ if (size > INT64_MAX)
+ return AVERROR_INVALIDDATA;
+
+ if (asf->is_header)
+ asf->unknown_size = size;
+ asf->is_header = 0;
+ if (!g->is_subobject) {
+ if (!(ret = strcmp(g->name, "Header Extension")))
+ avio_skip(pb, 22); // skip reserved fields and Data Size
+ if ((ret = detect_unknown_subobject(s, asf->unknown_offset,
+ asf->unknown_size)) < 0)
+ return ret;
+ } else {
+ if (size < 24) {
+ av_log(s, AV_LOG_ERROR, "Too small size %"PRIu64" (< 24).\n", size);
+ return AVERROR_INVALIDDATA;
+ }
+ avio_skip(pb, size - 24);
+ }
+
+ return 0;
+}
+
+static int get_asf_string(AVIOContext *pb, int maxlen, char *buf, int buflen)
+{
+ char *q = buf;
+ int ret = 0;
+ if (buflen <= 0)
+ return AVERROR(EINVAL);
+ while (ret + 1 < maxlen) {
+ uint8_t tmp;
+ uint32_t ch;
+ GET_UTF16(ch, (ret += 2) <= maxlen ? avio_rl16(pb) : 0, break;);
+ PUT_UTF8(ch, tmp, if (q - buf < buflen - 1) *q++ = tmp;)
+ }
+ *q = 0;
+
+ return ret;
+}
+
+static int asf_read_marker(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size = avio_rl64(pb);
+ int i, nb_markers, ret;
+ size_t len;
+ char name[1024];
+
+ avio_skip(pb, 8);
+ avio_skip(pb, 8); // skip reserved GUID
+ nb_markers = avio_rl32(pb);
+ avio_skip(pb, 2); // skip reserved field
+ len = avio_rl16(pb);
+ for (i = 0; i < len; i++)
+ avio_skip(pb, 1);
+
+ for (i = 0; i < nb_markers; i++) {
+ int64_t pts;
+
+ avio_skip(pb, 8);
+ pts = avio_rl64(pb);
+ pts -= asf->preroll * 10000;
+ avio_skip(pb, 2); // entry length
+ avio_skip(pb, 4); // send time
+ avio_skip(pb, 4); // flags
+ len = avio_rl32(pb);
+
+ if ((ret = avio_get_str16le(pb, len, name,
+ sizeof(name))) < len)
+ avio_skip(pb, len - ret);
+ avpriv_new_chapter(s, i, (AVRational) { 1, 10000000 }, pts,
+ AV_NOPTS_VALUE, name);
+ }
+ align_position(pb, asf->offset, size);
+
+ return 0;
+}
+
+static int asf_read_metadata(AVFormatContext *s, const char *title, uint16_t len,
+ unsigned char *ch, uint16_t buflen)
+{
+ AVIOContext *pb = s->pb;
+
+ avio_get_str16le(pb, len, ch, buflen);
+ if (ch[0]) {
+ if (av_dict_set(&s->metadata, title, ch, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ }
+
+ return 0;
+}
+
+static int asf_read_value(AVFormatContext *s, const uint8_t *name,
+ uint16_t val_len, int type, AVDictionary **met)
+{
+ int ret;
+ uint8_t *value;
+ uint16_t buflen = 2 * val_len + 1;
+ AVIOContext *pb = s->pb;
+
+ value = av_malloc(buflen);
+ if (!value)
+ return AVERROR(ENOMEM);
+ if (type == ASF_UNICODE) {
+ // get_asf_string reads UTF-16 and converts it to UTF-8 which needs longer buffer
+ if ((ret = get_asf_string(pb, val_len, value, buflen)) < 0)
+ goto failed;
+ if (av_dict_set(met, name, value, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ } else {
+ char buf[256];
+ if (val_len > sizeof(buf)) {
+ ret = AVERROR_INVALIDDATA;
+ goto failed;
+ }
+ if ((ret = avio_read(pb, value, val_len)) < 0)
+ goto failed;
+ if (ret < 2 * val_len)
+ value[ret] = '\0';
+ else
+ value[2 * val_len - 1] = '\0';
+ snprintf(buf, sizeof(buf), "%s", value);
+ if (av_dict_set(met, name, buf, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ }
+ av_freep(&value);
+
+ return 0;
+
+failed:
+ av_freep(&value);
+ return ret;
+}
+static int asf_read_generic_value(AVIOContext *pb, int type, uint64_t *value)
+{
+
+ switch (type) {
+ case ASF_BOOL:
+ *value = avio_rl16(pb);
+ break;
+ case ASF_DWORD:
+ *value = avio_rl32(pb);
+ break;
+ case ASF_QWORD:
+ *value = avio_rl64(pb);
+ break;
+ case ASF_WORD:
+ *value = avio_rl16(pb);
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
+static int asf_set_metadata(AVFormatContext *s, const uint8_t *name,
+ int type, AVDictionary **met)
+{
+ AVIOContext *pb = s->pb;
+ uint64_t value;
+ char buf[32];
+ int ret;
+
+ ret = asf_read_generic_value(pb, type, &value);
+ if (ret < 0)
+ return ret;
+
+ snprintf(buf, sizeof(buf), "%"PRIu64, value);
+ if (av_dict_set(met, name, buf, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+
+ return 0;
+}
+
+/* MSDN claims that this should be "compatible with the ID3 frame, APIC",
+ * but in reality this is only loosely similar */
+static int asf_read_picture(AVFormatContext *s, int len)
+{
+ ASFContext *asf = s->priv_data;
+ AVPacket pkt = { 0 };
+ const CodecMime *mime = ff_id3v2_mime_tags;
+ enum AVCodecID id = AV_CODEC_ID_NONE;
+ char mimetype[64];
+ uint8_t *desc = NULL;
+ AVStream *st = NULL;
+ int ret, type, picsize, desc_len;
+ ASFStream *asf_st;
+
+ /* type + picsize + mime + desc */
+ if (len < 1 + 4 + 2 + 2) {
+ av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* picture type */
+ type = avio_r8(s->pb);
+ len--;
+ if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) {
+ av_log(s, AV_LOG_WARNING, "Unknown attached picture type: %d.\n", type);
+ type = 0;
+ }
+
+ /* picture data size */
+ picsize = avio_rl32(s->pb);
+ len -= 4;
+
+ /* picture MIME type */
+ len -= avio_get_str16le(s->pb, len, mimetype, sizeof(mimetype));
+ while (mime->id != AV_CODEC_ID_NONE) {
+ if (!strncmp(mime->str, mimetype, sizeof(mimetype))) {
+ id = mime->id;
+ break;
+ }
+ mime++;
+ }
+ if (id == AV_CODEC_ID_NONE) {
+ av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n",
+ mimetype);
+ return 0;
+ }
+
+ if (picsize >= len) {
+ av_log(s, AV_LOG_ERROR, "Invalid attached picture data size: %d >= %d.\n",
+ picsize, len);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* picture description */
+ desc_len = (len - picsize) * 2 + 1;
+ desc = av_malloc(desc_len);
+ if (!desc)
+ return AVERROR(ENOMEM);
+ len -= avio_get_str16le(s->pb, len - picsize, desc, desc_len);
+
+ ret = av_get_packet(s->pb, &pkt, picsize);
+ if (ret < 0)
+ goto fail;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st));
+ asf_st = asf->asf_st[asf->nb_streams];
+ if (!asf_st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
+ st->codecpar->codec_type = asf_st->type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_id = id;
+ st->attached_pic = pkt;
+ st->attached_pic.stream_index = asf_st->index = st->index;
+ st->attached_pic.flags |= AV_PKT_FLAG_KEY;
+
+ asf->nb_streams++;
+
+ if (*desc) {
+ if (av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ } else
+ av_freep(&desc);
+
+ if (av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+
+ return 0;
+
+fail:
+ av_freep(&desc);
+ av_packet_unref(&pkt);
+ return ret;
+}
+
+static void get_id3_tag(AVFormatContext *s, int len)
+{
+ ID3v2ExtraMeta *id3v2_extra_meta = NULL;
+
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len);
+ if (id3v2_extra_meta)
+ ff_id3v2_parse_apic(s, &id3v2_extra_meta);
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+}
+
+static int process_metadata(AVFormatContext *s, const uint8_t *name, uint16_t name_len,
+ uint16_t val_len, uint16_t type, AVDictionary **met)
+{
+ int ret;
+ ff_asf_guid guid;
+
+ if (val_len) {
+ switch (type) {
+ case ASF_UNICODE:
+ asf_read_value(s, name, val_len, type, met);
+ break;
+ case ASF_BYTE_ARRAY:
+ if (!strcmp(name, "WM/Picture")) // handle cover art
+ asf_read_picture(s, val_len);
+ else if (!strcmp(name, "ID3")) // handle ID3 tag
+ get_id3_tag(s, val_len);
+ else
+ asf_read_value(s, name, val_len, type, met);
+ break;
+ case ASF_GUID:
+ ff_get_guid(s->pb, &guid);
+ break;
+ default:
+ if ((ret = asf_set_metadata(s, name, type, met)) < 0)
+ return ret;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int asf_read_ext_content(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size = avio_rl64(pb);
+ uint16_t nb_desc = avio_rl16(pb);
+ int i, ret;
+
+ for (i = 0; i < nb_desc; i++) {
+ uint16_t name_len, type, val_len;
+ uint8_t *name = NULL;
+
+ name_len = avio_rl16(pb);
+ if (!name_len)
+ return AVERROR_INVALIDDATA;
+ name = av_malloc(name_len);
+ if (!name)
+ return AVERROR(ENOMEM);
+ avio_get_str16le(pb, name_len, name,
+ name_len);
+ type = avio_rl16(pb);
+ // BOOL values are 16 bits long in the Metadata Object
+ // but 32 bits long in the Extended Content Description Object
+ if (type == ASF_BOOL)
+ type = ASF_DWORD;
+ val_len = avio_rl16(pb);
+
+ ret = process_metadata(s, name, name_len, val_len, type, &s->metadata);
+ av_freep(&name);
+ if (ret < 0)
+ return ret;
+ }
+
+ align_position(pb, asf->offset, size);
+ return 0;
+}
+
+static AVStream *find_stream(AVFormatContext *s, uint16_t st_num)
+{
+ AVStream *st = NULL;
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ for (i = 0; i < asf->nb_streams; i++) {
+ if (asf->asf_st[i]->stream_index == st_num) {
+ st = s->streams[asf->asf_st[i]->index];
+ break;
+ }
+ }
+
+ return st;
+}
+
+static int asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t *name, int type)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t value = 0;
+ int ret;
+
+ ret = asf_read_generic_value(pb, type, &value);
+ if (ret < 0)
+ return ret;
+
+ if (st_num < ASF_MAX_STREAMS) {
+ if (!strcmp(name, "AspectRatioX"))
+ asf->asf_sd[st_num].aspect_ratio.num = value;
+ else
+ asf->asf_sd[st_num].aspect_ratio.den = value;
+ }
+ return 0;
+}
+
+static int asf_read_metadata_obj(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size = avio_rl64(pb);
+ uint16_t nb_recs = avio_rl16(pb); // number of records in the Description Records list
+ int i, ret;
+
+ for (i = 0; i < nb_recs; i++) {
+ uint16_t name_len, buflen, type, val_len, st_num;
+ uint8_t *name = NULL;
+
+ avio_skip(pb, 2); // skip reserved field
+ st_num = avio_rl16(pb);
+ name_len = avio_rl16(pb);
+ buflen = 2 * name_len + 1;
+ if (!name_len)
+ break;
+ type = avio_rl16(pb);
+ val_len = avio_rl32(pb);
+ name = av_malloc(buflen);
+ if (!name)
+ return AVERROR(ENOMEM);
+ avio_get_str16le(pb, name_len, name,
+ buflen);
+ if (!strcmp(name, "AspectRatioX") || !strcmp(name, "AspectRatioY")) {
+ ret = asf_store_aspect_ratio(s, st_num, name, type);
+ if (ret < 0) {
+ av_freep(&name);
+ break;
+ }
+ } else {
+ if (st_num < ASF_MAX_STREAMS) {
+ if ((ret = process_metadata(s, name, name_len, val_len, type,
+ &asf->asf_sd[st_num].asf_met)) < 0) {
+ av_freep(&name);
+ break;
+ }
+ }
+ }
+ av_freep(&name);
+ }
+
+ align_position(pb, asf->offset, size);
+ return 0;
+}
+
+static int asf_read_content_desc(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i;
+ static const char *const titles[] =
+ { "Title", "Author", "Copyright", "Description", "Rate" };
+ uint16_t len[5], buflen[5] = { 0 };
+ uint8_t *ch;
+ uint64_t size = avio_rl64(pb);
+
+ for (i = 0; i < 5; i++) {
+ len[i] = avio_rl16(pb);
+ // utf8 string should be <= 2 * utf16 string, extra byte for the terminator
+ buflen[i] = 2 * len[i] + 1;
+ }
+
+ for (i = 0; i < 5; i++) {
+ ch = av_malloc(buflen[i]);
+ if (!ch)
+ return(AVERROR(ENOMEM));
+ asf_read_metadata(s, titles[i], len[i], ch, buflen[i]);
+ av_freep(&ch);
+ }
+ align_position(pb, asf->offset, size);
+
+ return 0;
+}
+
+static int asf_read_properties(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ time_t creation_time;
+
+ avio_rl64(pb); // read object size
+ avio_skip(pb, 16); // skip File ID
+ avio_skip(pb, 8); // skip File size
+ creation_time = avio_rl64(pb);
+ if (!(asf->b_flags & ASF_FLAG_BROADCAST)) {
+ struct tm tmbuf;
+ struct tm *tm;
+ char buf[64];
+
+ // creation date is in 100 ns units from 1 Jan 1601, conversion to s
+ creation_time /= 10000000;
+ // there are 11644473600 seconds between 1 Jan 1601 and 1 Jan 1970
+ creation_time -= 11644473600;
+ tm = gmtime_r(&creation_time, &tmbuf);
+ if (tm) {
+ if (!strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
+ buf[0] = '\0';
+ } else
+ buf[0] = '\0';
+ if (buf[0]) {
+ if (av_dict_set(&s->metadata, "creation_time", buf, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ }
+ }
+ asf->nb_packets = avio_rl64(pb);
+ asf->duration = avio_rl64(pb) / 10000; // stream duration
+ avio_skip(pb, 8); // skip send duration
+ asf->preroll = avio_rl64(pb);
+ asf->duration -= asf->preroll;
+ asf->b_flags = avio_rl32(pb);
+ avio_skip(pb, 4); // skip minimal packet size
+ asf->packet_size = avio_rl32(pb);
+ avio_skip(pb, 4); // skip max_bitrate
+
+ return 0;
+}
+
+static int parse_video_info(AVIOContext *pb, AVStream *st)
+{
+ uint16_t size;
+ unsigned int tag;
+
+ st->codecpar->width = avio_rl32(pb);
+ st->codecpar->height = avio_rl32(pb);
+ avio_skip(pb, 1); // skip reserved flags
+ size = avio_rl16(pb); // size of the Format Data
+ tag = ff_get_bmp_header(pb, st, NULL);
+ st->codecpar->codec_tag = tag;
+ st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
+
+ if (size > BMP_HEADER_SIZE) {
+ int ret;
+ st->codecpar->extradata_size = size - BMP_HEADER_SIZE;
+ if (!(st->codecpar->extradata = av_malloc(st->codecpar->extradata_size +
+ AV_INPUT_BUFFER_PADDING_SIZE))) {
+ st->codecpar->extradata_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ memset(st->codecpar->extradata + st->codecpar->extradata_size , 0,
+ AV_INPUT_BUFFER_PADDING_SIZE);
+ if ((ret = avio_read(pb, st->codecpar->extradata,
+ st->codecpar->extradata_size)) < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size;
+ uint32_t err_data_len, ts_data_len; // type specific data length
+ uint16_t flags;
+ ff_asf_guid stream_type;
+ enum AVMediaType type;
+ int i, ret;
+ uint8_t stream_index;
+ AVStream *st;
+ ASFStream *asf_st;
+
+ // ASF file must not contain more than 128 streams according to the specification
+ if (asf->nb_streams >= ASF_MAX_STREAMS)
+ return AVERROR_INVALIDDATA;
+
+ size = avio_rl64(pb);
+ ff_get_guid(pb, &stream_type);
+ if (!ff_guidcmp(&stream_type, &ff_asf_audio_stream))
+ type = AVMEDIA_TYPE_AUDIO;
+ else if (!ff_guidcmp(&stream_type, &ff_asf_video_stream))
+ type = AVMEDIA_TYPE_VIDEO;
+ else if (!ff_guidcmp(&stream_type, &ff_asf_jfif_media))
+ type = AVMEDIA_TYPE_VIDEO;
+ else if (!ff_guidcmp(&stream_type, &ff_asf_command_stream))
+ type = AVMEDIA_TYPE_DATA;
+ else if (!ff_guidcmp(&stream_type,
+ &ff_asf_ext_stream_embed_stream_header))
+ type = AVMEDIA_TYPE_UNKNOWN;
+ else
+ return AVERROR_INVALIDDATA;
+
+ ff_get_guid(pb, &stream_type); // error correction type
+ avio_skip(pb, 8); // skip the time offset
+ ts_data_len = avio_rl32(pb);
+ err_data_len = avio_rl32(pb);
+ flags = avio_rl16(pb); // bit 15 - Encrypted Content
+
+ stream_index = flags & ASF_STREAM_NUM;
+ for (i = 0; i < asf->nb_streams; i++)
+ if (stream_index == asf->asf_st[i]->stream_index) {
+ av_log(s, AV_LOG_WARNING,
+ "Duplicate stream found, this stream will be ignored.\n");
+ align_position(pb, asf->offset, size);
+ return 0;
+ }
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 32, 1, 1000); // pts should be dword, in milliseconds
+ st->codecpar->codec_type = type;
+ asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st));
+ if (!asf->asf_st[asf->nb_streams])
+ return AVERROR(ENOMEM);
+ asf_st = asf->asf_st[asf->nb_streams];
+ asf->nb_streams++;
+ asf_st->stream_index = stream_index;
+ asf_st->index = st->index;
+ asf_st->indexed = 0;
+ st->id = flags & ASF_STREAM_NUM;
+ av_init_packet(&asf_st->pkt.avpkt);
+ asf_st->pkt.data_size = 0;
+ avio_skip(pb, 4); // skip reserved field
+
+ switch (type) {
+ case AVMEDIA_TYPE_AUDIO:
+ asf_st->type = AVMEDIA_TYPE_AUDIO;
+ if ((ret = ff_get_wav_header(s, pb, st->codecpar, ts_data_len, 0)) < 0)
+ return ret;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ asf_st->type = AVMEDIA_TYPE_VIDEO;
+ if ((ret = parse_video_info(pb, st)) < 0)
+ return ret;
+ break;
+ default:
+ avio_skip(pb, ts_data_len);
+ break;
+ }
+
+ if (err_data_len) {
+ if (type == AVMEDIA_TYPE_AUDIO) {
+ uint8_t span = avio_r8(pb);
+ if (span > 1) {
+ asf_st->span = span;
+ asf_st->virtual_pkt_len = avio_rl16(pb);
+ asf_st->virtual_chunk_len = avio_rl16(pb);
+ if (!asf_st->virtual_chunk_len || !asf_st->virtual_pkt_len)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, err_data_len - 5);
+ } else
+ avio_skip(pb, err_data_len - 1);
+ } else
+ avio_skip(pb, err_data_len);
+ }
+
+ align_position(pb, asf->offset, size);
+
+ return 0;
+}
+
+static void set_language(AVFormatContext *s, const char *rfc1766, AVDictionary **met)
+{
+ // language abbr should contain at least 2 chars
+ if (rfc1766 && strlen(rfc1766) > 1) {
+ const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any
+ const char *iso6392 = ff_convert_lang_to(primary_tag,
+ AV_LANG_ISO639_2_BIBL);
+ if (iso6392)
+ if (av_dict_set(met, "language", iso6392, 0) < 0)
+ av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
+ }
+}
+
+static int asf_read_ext_stream_properties(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = NULL;
+ ff_asf_guid guid;
+ uint16_t nb_st_name, nb_pay_exts, st_num, lang_idx;
+ int i, ret;
+ uint32_t bitrate;
+ uint64_t start_time, end_time, time_per_frame;
+ uint64_t size = avio_rl64(pb);
+
+ start_time = avio_rl64(pb);
+ end_time = avio_rl64(pb);
+ bitrate = avio_rl32(pb);
+ avio_skip(pb, 28); // skip some unused values
+ st_num = avio_rl16(pb);
+ st_num &= ASF_STREAM_NUM;
+ lang_idx = avio_rl16(pb); // Stream Language ID Index
+ for (i = 0; i < asf->nb_streams; i++) {
+ if (st_num == asf->asf_st[i]->stream_index) {
+ st = s->streams[asf->asf_st[i]->index];
+ asf->asf_st[i]->lang_idx = lang_idx;
+ break;
+ }
+ }
+ time_per_frame = avio_rl64(pb); // average time per frame
+ if (st) {
+ st->start_time = start_time;
+ st->duration = end_time - start_time;
+ st->codecpar->bit_rate = bitrate;
+ st->avg_frame_rate.num = 10000000;
+ st->avg_frame_rate.den = time_per_frame;
+ }
+ nb_st_name = avio_rl16(pb);
+ nb_pay_exts = avio_rl16(pb);
+ for (i = 0; i < nb_st_name; i++) {
+ uint16_t len;
+
+ avio_rl16(pb); // Language ID Index
+ len = avio_rl16(pb);
+ avio_skip(pb, len);
+ }
+
+ for (i = 0; i < nb_pay_exts; i++) {
+ uint32_t len;
+ avio_skip(pb, 16); // Extension System ID
+ avio_skip(pb, 2); // Extension Data Size
+ len = avio_rl32(pb);
+ avio_skip(pb, len);
+ }
+
+ if ((ret = ff_get_guid(pb, &guid)) < 0) {
+ align_position(pb, asf->offset, size);
+
+ return 0;
+ }
+
+ g = find_guid(guid);
+ if (g && !(strcmp(g->name, "Stream Properties"))) {
+ if ((ret = g->read_object(s, g)) < 0)
+ return ret;
+ }
+
+ align_position(pb, asf->offset, size);
+ return 0;
+}
+
+static int asf_read_language_list(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i, ret;
+ uint64_t size = avio_rl64(pb);
+ uint16_t nb_langs = avio_rl16(pb);
+
+ if (nb_langs < ASF_MAX_STREAMS) {
+ for (i = 0; i < nb_langs; i++) {
+ size_t len;
+ len = avio_r8(pb);
+ if (!len)
+ len = 6;
+ if ((ret = get_asf_string(pb, len, asf->asf_sd[i].langs,
+ sizeof(asf->asf_sd[i].langs))) < 0) {
+ return ret;
+ }
+ }
+ }
+
+ align_position(pb, asf->offset, size);
+ return 0;
+}
+
+// returns data object offset when reading this object for the first time
+static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size = asf->data_size = avio_rl64(pb);
+ int i;
+
+ if (!asf->data_reached) {
+ asf->data_reached = 1;
+ asf->data_offset = asf->offset;
+ }
+
+ for (i = 0; i < asf->nb_streams; i++) {
+ if (!(asf->b_flags & ASF_FLAG_BROADCAST))
+ s->streams[i]->duration = asf->duration;
+ }
+ asf->nb_mult_left = 0;
+ asf->sub_left = 0;
+ asf->state = PARSE_PACKET_HEADER;
+ asf->return_subpayload = 0;
+ asf->packet_size_internal = 0;
+ avio_skip(pb, 16); // skip File ID
+ size = avio_rl64(pb); // Total Data Packets
+ if (size != asf->nb_packets)
+ av_log(s, AV_LOG_WARNING,
+ "Number of Packets from File Properties Object is not equal to Total"
+ "Datapackets value! num of packets %"PRIu64" total num %"PRIu64".\n",
+ size, asf->nb_packets);
+ avio_skip(pb, 2); // skip reserved field
+ asf->first_packet_offset = avio_tell(pb);
- if (pb->seekable && !(asf->b_flags & ASF_FLAG_BROADCAST))
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !(asf->b_flags & ASF_FLAG_BROADCAST))
+ align_position(pb, asf->offset, asf->data_size);
+
+ return 0;
+}
+
+static int asf_read_simple_index(AVFormatContext *s, const GUIDParseTable *g)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = NULL;
+ uint64_t interval; // index entry time interval in 100 ns units, usually it's 1s
+ uint32_t pkt_num, nb_entries;
+ int32_t prev_pkt_num = -1;
+ int i, ret;
+ uint64_t size = avio_rl64(pb);
+
+ // simple index objects should be ordered by stream number, this loop tries to find
+ // the first not indexed video stream
+ for (i = 0; i < asf->nb_streams; i++) {
+ if ((asf->asf_st[i]->type == AVMEDIA_TYPE_VIDEO) && !asf->asf_st[i]->indexed) {
+ asf->asf_st[i]->indexed = 1;
+ st = s->streams[asf->asf_st[i]->index];
+ break;
+ }
+ }
+ if (!st) {
+ avio_skip(pb, size - 24); // if there's no video stream, skip index object
+ return 0;
+ }
+ avio_skip(pb, 16); // skip File ID
+ interval = avio_rl64(pb);
+ avio_skip(pb, 4);
+ nb_entries = avio_rl32(pb);
+ for (i = 0; i < nb_entries; i++) {
+ pkt_num = avio_rl32(pb);
+ ret = avio_skip(pb, 2);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Skipping failed in asf_read_simple_index.\n");
+ return ret;
+ }
+ if (prev_pkt_num != pkt_num) {
+ av_add_index_entry(st, asf->first_packet_offset + asf->packet_size *
+ pkt_num, av_rescale(interval, i, 10000),
+ asf->packet_size, 0, AVINDEX_KEYFRAME);
+ prev_pkt_num = pkt_num;
+ }
+ }
+ asf->is_simple_index = 1;
+ align_position(pb, asf->offset, size);
+
+ return 0;
+}
+
+static const GUIDParseTable gdef[] = {
+ { "Data", { 0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_data, 1 },
+ { "Simple Index", { 0x33, 0x00, 0x08, 0x90, 0xE5, 0xB1, 0x11, 0xCF, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }, asf_read_simple_index, 1 },
+ { "Content Description", { 0x75, 0xB2, 0x26, 0x33, 0x66 ,0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_content_desc, 1 },
+ { "Extended Content Description", { 0xD2, 0xD0, 0xA4, 0x40, 0xE3, 0x07, 0x11, 0xD2, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5e, 0xA8, 0x50 }, asf_read_ext_content, 1 },
+ { "Stream Bitrate Properties", { 0x7B, 0xF8, 0x75, 0xCE, 0x46, 0x8D, 0x11, 0xD1, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }, asf_read_unknown, 1 },
+ { "File Properties", { 0x8C, 0xAB, 0xDC, 0xA1, 0xA9, 0x47, 0x11, 0xCF, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_properties, 1 },
+ { "Header Extension", { 0x5F, 0xBF, 0x03, 0xB5, 0xA9, 0x2E, 0x11, 0xCF, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_unknown, 0 },
+ { "Stream Properties", { 0xB7, 0xDC, 0x07, 0x91, 0xA9, 0xB7, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_stream_properties, 1 },
+ { "Codec List", { 0x86, 0xD1, 0x52, 0x40, 0x31, 0x1D, 0x11, 0xD0, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 },
+ { "Marker", { 0xF4, 0x87, 0xCD, 0x01, 0xA9, 0x51, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_marker, 1 },
+ { "Script Command", { 0x1E, 0xFB, 0x1A, 0x30, 0x0B, 0x62, 0x11, 0xD0, 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 },
+ { "Language List", { 0x7C, 0x43, 0x46, 0xa9, 0xef, 0xe0, 0x4B, 0xFC, 0xB2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 }, asf_read_language_list, 1},
+ { "Padding", { 0x18, 0x06, 0xD4, 0x74, 0xCA, 0xDF, 0x45, 0x09, 0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8 }, asf_read_unknown, 1 },
+ { "DRMv1 Header", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 },
+ { "DRMv2 Header", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9c }, asf_read_unknown, 1 },
+ { "Index", { 0xD6, 0xE2, 0x29, 0xD3, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Media Object Index", { 0xFE, 0xB1, 0x03, 0xF8, 0x12, 0xAD, 0x4C, 0x64, 0x84, 0x0F, 0x2A, 0x1D, 0x2F, 0x7A, 0xD4, 0x8C }, asf_read_unknown, 1 },
+ { "Timecode Index", { 0x3C, 0xB7, 0x3F, 0xD0, 0x0C, 0x4A, 0x48, 0x03, 0x95, 0x3D, 0xED, 0xF7, 0xB6, 0x22, 0x8F, 0x0C }, asf_read_unknown, 0 },
+ { "Bitrate_Mutual_Exclusion", { 0xD6, 0xE2, 0x29, 0xDC, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Error Correction", { 0x75, 0xB2, 0x26, 0x35, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_unknown, 1 },
+ { "Content Branding", { 0x22, 0x11, 0xB3, 0xFA, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 },
+ { "Content Encryption", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 },
+ { "Extended Content Encryption", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C }, asf_read_unknown, 1 },
+ { "Digital Signature", { 0x22, 0x11, 0xB3, 0xFC, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 },
+ { "Extended Stream Properties", { 0x14, 0xE6, 0xA5, 0xCB, 0xC6, 0x72, 0x43, 0x32, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A }, asf_read_ext_stream_properties, 1 },
+ { "Advanced Mutual Exclusion", { 0xA0, 0x86, 0x49, 0xCF, 0x47, 0x75, 0x46, 0x70, 0x8A, 0x16, 0x6E, 0x35, 0x35, 0x75, 0x66, 0xCD }, asf_read_unknown, 1 },
+ { "Group Mutual Exclusion", { 0xD1, 0x46, 0x5A, 0x40, 0x5A, 0x79, 0x43, 0x38, 0xB7, 0x1B, 0xE3, 0x6B, 0x8F, 0xD6, 0xC2, 0x49 }, asf_read_unknown, 1},
+ { "Stream Prioritization", { 0xD4, 0xFE, 0xD1, 0x5B, 0x88, 0xD3, 0x45, 0x4F, 0x81, 0xF0, 0xED, 0x5C, 0x45, 0x99, 0x9E, 0x24 }, asf_read_unknown, 1 },
+ { "Bandwidth Sharing Object", { 0xA6, 0x96, 0x09, 0xE6, 0x51, 0x7B, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 },
+ { "Metadata", { 0xC5, 0xF8, 0xCB, 0xEA, 0x5B, 0xAF, 0x48, 0x77, 0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA }, asf_read_metadata_obj, 1 },
+ { "Metadata Library", { 0x44, 0x23, 0x1C, 0x94, 0x94, 0x98, 0x49, 0xD1, 0xA1, 0x41, 0x1D, 0x13, 0x4E, 0x45, 0x70, 0x54 }, asf_read_metadata_obj, 1 },
+ { "Audio Spread", { 0xBF, 0xC3, 0xCD, 0x50, 0x61, 0x8F, 0x11, 0xCF, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20 }, asf_read_unknown, 1 },
+ { "Index Parameters", { 0xD6, 0xE2, 0x29, 0xDF, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Content Encryption System Windows Media DRM Network Devices",
+ { 0x7A, 0x07, 0x9B, 0xB6, 0xDA, 0XA4, 0x4e, 0x12, 0xA5, 0xCA, 0x91, 0xD3, 0x8D, 0xC1, 0x1A, 0x8D }, asf_read_unknown, 1 },
+ { "Mutex Language", { 0xD6, 0xE2, 0x2A, 0x00, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Mutex Bitrate", { 0xD6, 0xE2, 0x2A, 0x01, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Mutex Unknown", { 0xD6, 0xE2, 0x2A, 0x02, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 },
+ { "Bandwidth Sharing Exclusive", { 0xAF, 0x60, 0x60, 0xAA, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 },
+ { "Bandwidth Sharing Partial", { 0xAF, 0x60, 0x60, 0xAB, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 },
+ { "Payload Extension System Timecode", { 0x39, 0x95, 0x95, 0xEC, 0x86, 0x67, 0x4E, 0x2D, 0x8F, 0xDB, 0x98, 0x81, 0x4C, 0xE7, 0x6C, 0x1E }, asf_read_unknown, 1 },
+ { "Payload Extension System File Name", { 0xE1, 0x65, 0xEC, 0x0E, 0x19, 0xED, 0x45, 0xD7, 0xB4, 0xA7, 0x25, 0xCB, 0xD1, 0xE2, 0x8E, 0x9B }, asf_read_unknown, 1 },
+ { "Payload Extension System Content Type", { 0xD5, 0x90, 0xDC, 0x20, 0x07, 0xBC, 0x43, 0x6C, 0x9C, 0xF7, 0xF3, 0xBB, 0xFB, 0xF1, 0xA4, 0xDC }, asf_read_unknown, 1 },
+ { "Payload Extension System Pixel Aspect Ratio", { 0x1, 0x1E, 0xE5, 0x54, 0xF9, 0xEA, 0x4B, 0xC8, 0x82, 0x1A, 0x37, 0x6B, 0x74, 0xE4, 0xC4, 0xB8 }, asf_read_unknown, 1 },
+ { "Payload Extension System Sample Duration", { 0xC6, 0xBD, 0x94, 0x50, 0x86, 0x7F, 0x49, 0x07, 0x83, 0xA3, 0xC7, 0x79, 0x21, 0xB7, 0x33, 0xAD }, asf_read_unknown, 1 },
+ { "Payload Extension System Encryption Sample ID", { 0x66, 0x98, 0xB8, 0x4E, 0x0A, 0xFA, 0x43, 0x30, 0xAE, 0xB2, 0x1C, 0x0A, 0x98, 0xD7, 0xA4, 0x4D }, asf_read_unknown, 1 },
+ { "Payload Extension System Degradable JPEG", { 0x00, 0xE1, 0xAF, 0x06, 0x7B, 0xEC, 0x11, 0xD1, 0xA5, 0x82, 0x00, 0xC0, 0x4F, 0xC2, 0x9C, 0xFB }, asf_read_unknown, 1 },
+};
+
+#define READ_LEN(flag, name, len) \
+ do { \
+ if ((flag) == name ## IS_BYTE) \
+ len = avio_r8(pb); \
+ else if ((flag) == name ## IS_WORD) \
+ len = avio_rl16(pb); \
+ else if ((flag) == name ## IS_DWORD) \
+ len = avio_rl32(pb); \
+ else \
+ len = 0; \
+ } while(0)
+
+static int asf_read_subpayload(AVFormatContext *s, AVPacket *pkt, int is_header)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint8_t sub_len;
+ int ret, i;
+
+ if (is_header) {
+ asf->dts_delta = avio_r8(pb);
+ if (asf->nb_mult_left) {
+ asf->mult_sub_len = avio_rl16(pb); // total
+ }
+ asf->sub_header_offset = avio_tell(pb);
+ asf->nb_sub = 0;
+ asf->sub_left = 1;
+ }
+ sub_len = avio_r8(pb);
+ if ((ret = av_get_packet(pb, pkt, sub_len)) < 0) // each subpayload is entire frame
+ return ret;
+ for (i = 0; i < asf->nb_streams; i++) {
+ if (asf->stream_index == asf->asf_st[i]->stream_index) {
+ pkt->stream_index = asf->asf_st[i]->index;
+ break;
+ }
+ }
+ asf->return_subpayload = 1;
+ if (!sub_len)
+ asf->return_subpayload = 0;
+
+ if (sub_len)
+ asf->nb_sub++;
+ pkt->dts = asf->sub_dts + (asf->nb_sub - 1) * asf->dts_delta - asf->preroll;
+ if (asf->nb_mult_left && (avio_tell(pb) >=
+ (asf->sub_header_offset + asf->mult_sub_len))) {
+ asf->sub_left = 0;
+ asf->nb_mult_left--;
+ }
+ if (avio_tell(pb) >= asf->packet_offset + asf->packet_size - asf->pad_len) {
+ asf->sub_left = 0;
+ if (!asf->nb_mult_left) {
+ avio_skip(pb, asf->pad_len);
+ if (avio_tell(pb) != asf->packet_offset + asf->packet_size) {
+ if (!asf->packet_size)
+ return AVERROR_INVALIDDATA;
+ av_log(s, AV_LOG_WARNING,
+ "Position %"PRId64" wrong, should be %"PRId64"\n",
+ avio_tell(pb), asf->packet_offset + asf->packet_size);
+ avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void reset_packet(ASFPacket *asf_pkt)
+{
+ asf_pkt->size_left = 0;
+ asf_pkt->data_size = 0;
+ asf_pkt->duration = 0;
+ asf_pkt->flags = 0;
+ asf_pkt->dts = 0;
+ asf_pkt->duration = 0;
+ av_packet_unref(&asf_pkt->avpkt);
+ av_init_packet(&asf_pkt->avpkt);
+}
+
+static int asf_read_replicated_data(AVFormatContext *s, ASFPacket *asf_pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret, data_size;
+
+ if (!asf_pkt->data_size) {
+ data_size = avio_rl32(pb); // read media object size
+ if (data_size <= 0)
+ return AVERROR_INVALIDDATA;
+ if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0)
+ return ret;
+ asf_pkt->data_size = asf_pkt->size_left = data_size;
+ } else
+ avio_skip(pb, 4); // reading of media object size is already done
+ asf_pkt->dts = avio_rl32(pb); // read presentation time
+ if (asf->rep_data_len && (asf->rep_data_len >= 8))
+ avio_skip(pb, asf->rep_data_len - 8); // skip replicated data
+
+ return 0;
+}
+
+static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt,
+ ASFPacket *asf_pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint16_t pay_len;
+ unsigned char *p;
+ int ret;
+ int skip = 0;
+
+ // if replicated length is 1, subpayloads are present
+ if (asf->rep_data_len == 1) {
+ asf->sub_left = 1;
+ asf->state = READ_MULTI_SUB;
+ pkt->flags = asf_pkt->flags;
+ if ((ret = asf_read_subpayload(s, pkt, 1)) < 0)
+ return ret;
+ } else {
+ if (asf->rep_data_len)
+ if ((ret = asf_read_replicated_data(s, asf_pkt)) < 0)
+ return ret;
+ pay_len = avio_rl16(pb); // payload length should be WORD
+ if (pay_len > asf->packet_size) {
+ av_log(s, AV_LOG_ERROR,
+ "Error: invalid data packet size, pay_len %"PRIu16", "
+ "asf->packet_size %"PRIu32", offset %"PRId64".\n",
+ pay_len, asf->packet_size, avio_tell(pb));
+ return AVERROR_INVALIDDATA;
+ }
+ p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left;
+ if (pay_len > asf_pkt->size_left) {
+ av_log(s, AV_LOG_ERROR,
+ "Error: invalid buffer size, pay_len %d, data size left %d.\n",
+ pay_len, asf_pkt->size_left);
+ skip = pay_len - asf_pkt->size_left;
+ pay_len = asf_pkt->size_left;
+ }
+ if (asf_pkt->size_left <= 0)
+ return AVERROR_INVALIDDATA;
+ if ((ret = avio_read(pb, p, pay_len)) < 0)
+ return ret;
+ if (s->key && s->keylen == 20)
+ ff_asfcrypt_dec(s->key, p, ret);
+ avio_skip(pb, skip);
+ asf_pkt->size_left -= pay_len;
+ asf->nb_mult_left--;
+ }
+
+ return 0;
+}
+
+static int asf_read_single_payload(AVFormatContext *s, ASFPacket *asf_pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t offset;
+ uint64_t size;
+ unsigned char *p;
+ int ret, data_size;
+
+ if (!asf_pkt->data_size) {
+ data_size = avio_rl32(pb); // read media object size
+ if (data_size <= 0)
+ return AVERROR_EOF;
+ if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0)
+ return ret;
+ asf_pkt->data_size = asf_pkt->size_left = data_size;
+ } else
+ avio_skip(pb, 4); // skip media object size
+ asf_pkt->dts = avio_rl32(pb); // read presentation time
+ if (asf->rep_data_len >= 8)
+ avio_skip(pb, asf->rep_data_len - 8); // skip replicated data
+ offset = avio_tell(pb);
+
+ // size of the payload - size of the packet without header and padding
+ if (asf->packet_size_internal)
+ size = asf->packet_size_internal - offset + asf->packet_offset - asf->pad_len;
+ else
+ size = asf->packet_size - offset + asf->packet_offset - asf->pad_len;
+ if (size > asf->packet_size) {
+ av_log(s, AV_LOG_ERROR,
+ "Error: invalid data packet size, offset %"PRId64".\n",
+ avio_tell(pb));
+ return AVERROR_INVALIDDATA;
+ }
+ p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left;
+ if (size > asf_pkt->size_left || asf_pkt->size_left <= 0)
+ return AVERROR_INVALIDDATA;
+ if (asf_pkt->size_left > size)
+ asf_pkt->size_left -= size;
+ else
+ asf_pkt->size_left = 0;
+ if ((ret = avio_read(pb, p, size)) < 0)
+ return ret;
+ if (s->key && s->keylen == 20)
+ ff_asfcrypt_dec(s->key, p, ret);
+ if (asf->packet_size_internal)
+ avio_skip(pb, asf->packet_size - asf->packet_size_internal);
+ avio_skip(pb, asf->pad_len); // skip padding
+
+ return 0;
+}
+
+static int asf_read_payload(AVFormatContext *s, AVPacket *pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret, i;
+ ASFPacket *asf_pkt = NULL;
+
+ if (!asf->sub_left) {
+ uint32_t off_len, media_len;
+ uint8_t stream_num;
+
+ stream_num = avio_r8(pb);
+ asf->stream_index = stream_num & ASF_STREAM_NUM;
+ for (i = 0; i < asf->nb_streams; i++) {
+ if (asf->stream_index == asf->asf_st[i]->stream_index) {
+ asf_pkt = &asf->asf_st[i]->pkt;
+ asf_pkt->stream_index = asf->asf_st[i]->index;
+ break;
+ }
+ }
+ if (!asf_pkt) {
+ if (asf->packet_offset + asf->packet_size <= asf->data_offset + asf->data_size) {
+ if (!asf->packet_size) {
+ av_log(s, AV_LOG_ERROR, "Invalid packet size 0.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET);
+ av_log(s, AV_LOG_WARNING, "Skipping the stream with the invalid stream index %d.\n",
+ asf->stream_index);
+ return AVERROR(EAGAIN);
+ } else
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (stream_num >> 7)
+ asf_pkt->flags |= AV_PKT_FLAG_KEY;
+ READ_LEN(asf->prop_flags & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE,
+ ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_, media_len);
+ READ_LEN(asf->prop_flags & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE,
+ ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_, off_len);
+ READ_LEN(asf->prop_flags & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE,
+ ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_, asf->rep_data_len);
+ if (asf_pkt->size_left && (asf_pkt->frame_num != media_len)) {
+ av_log(s, AV_LOG_WARNING, "Unfinished frame will be ignored\n");
+ reset_packet(asf_pkt);
+ }
+ asf_pkt->frame_num = media_len;
+ asf->sub_dts = off_len;
+ if (asf->nb_mult_left) {
+ if ((ret = asf_read_multiple_payload(s, pkt, asf_pkt)) < 0)
+ return ret;
+ } else if (asf->rep_data_len == 1) {
+ asf->sub_left = 1;
+ asf->state = READ_SINGLE;
+ pkt->flags = asf_pkt->flags;
+ if ((ret = asf_read_subpayload(s, pkt, 1)) < 0)
+ return ret;
+ } else {
+ if ((ret = asf_read_single_payload(s, asf_pkt)) < 0)
+ return ret;
+ }
+ } else {
+ for (i = 0; i <= asf->nb_streams; i++) {
+ if (asf->stream_index == asf->asf_st[i]->stream_index) {
+ asf_pkt = &asf->asf_st[i]->pkt;
+ break;
+ }
+ }
+ if (!asf_pkt)
+ return AVERROR_INVALIDDATA;
+ pkt->flags = asf_pkt->flags;
+ pkt->dts = asf_pkt->dts;
+ pkt->stream_index = asf->asf_st[i]->index;
+ if ((ret = asf_read_subpayload(s, pkt, 0)) < 0) // read subpayload without its header
+ return ret;
+ }
+
+ return 0;
+}
+
+static int asf_read_packet_header(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t size;
+ uint32_t av_unused seq;
+ unsigned char error_flags, len_flags, pay_flags;
+
+ asf->packet_offset = avio_tell(pb);
+ error_flags = avio_r8(pb); // read Error Correction Flags
+ if (error_flags & ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT) {
+ if (!(error_flags & ASF_ERROR_CORRECTION_LENGTH_TYPE)) {
+ size = error_flags & ASF_PACKET_ERROR_CORRECTION_DATA_SIZE;
+ avio_skip(pb, size);
+ }
+ len_flags = avio_r8(pb);
+ } else
+ len_flags = error_flags;
+ asf->prop_flags = avio_r8(pb);
+ READ_LEN(len_flags & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE,
+ ASF_PPI_FLAG_PACKET_LENGTH_FIELD_, asf->packet_size_internal);
+ READ_LEN(len_flags & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE,
+ ASF_PPI_FLAG_SEQUENCE_FIELD_, seq);
+ READ_LEN(len_flags & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE,
+ ASF_PPI_FLAG_PADDING_LENGTH_FIELD_, asf->pad_len );
+ asf->send_time = avio_rl32(pb); // send time
+ avio_skip(pb, 2); // skip duration
+ if (len_flags & ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT) { // Multiple Payloads present
+ pay_flags = avio_r8(pb);
+ asf->nb_mult_left = (pay_flags & ASF_NUM_OF_PAYLOADS);
+ }
+
+ return 0;
+}
+
+static int asf_deinterleave(AVFormatContext *s, ASFPacket *asf_pkt, int st_num)
+{
+ ASFContext *asf = s->priv_data;
+ ASFStream *asf_st = asf->asf_st[st_num];
+ unsigned char *p = asf_pkt->avpkt.data;
+ uint16_t pkt_len = asf->asf_st[st_num]->virtual_pkt_len;
+ uint16_t chunk_len = asf->asf_st[st_num]->virtual_chunk_len;
+ int nchunks = pkt_len / chunk_len;
+ AVPacket pkt;
+ int pos = 0, j, l, ret;
+
+
+ if ((ret = av_new_packet(&pkt, asf_pkt->data_size)) < 0)
+ return ret;
+
+ while (asf_pkt->data_size >= asf_st->span * pkt_len + pos) {
+ if (pos >= asf_pkt->data_size) {
+ break;
+ }
+ for (l = 0; l < pkt_len; l++) {
+ if (pos >= asf_pkt->data_size) {
+ break;
+ }
+ for (j = 0; j < asf_st->span; j++) {
+ if ((pos + chunk_len) >= asf_pkt->data_size)
+ break;
+ memcpy(pkt.data + pos,
+ p + (j * nchunks + l) * chunk_len,
+ chunk_len);
+ pos += chunk_len;
+ }
+ }
+ p += asf_st->span * pkt_len;
+ if (p > asf_pkt->avpkt.data + asf_pkt->data_size)
+ break;
+ }
+ av_packet_unref(&asf_pkt->avpkt);
+ asf_pkt->avpkt = pkt;
+
+ return 0;
+}
+
+static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret, i;
+
+ if ((avio_tell(pb) >= asf->data_offset + asf->data_size) &&
+ !(asf->b_flags & ASF_FLAG_BROADCAST))
+ return AVERROR_EOF;
+ while (!pb->eof_reached) {
+ if (asf->state == PARSE_PACKET_HEADER) {
+ asf_read_packet_header(s);
+ if (pb->eof_reached)
+ break;
+ if (!asf->nb_mult_left)
+ asf->state = READ_SINGLE;
+ else
+ asf->state = READ_MULTI;
+ }
+ ret = asf_read_payload(s, pkt);
+ if (ret == AVERROR(EAGAIN)) {
+ asf->state = PARSE_PACKET_HEADER;
+ continue;
+ }
+ else if (ret < 0)
+ return ret;
+
+ switch (asf->state) {
+ case READ_SINGLE:
+ if (!asf->sub_left)
+ asf->state = PARSE_PACKET_HEADER;
+ break;
+ case READ_MULTI_SUB:
+ if (!asf->sub_left && !asf->nb_mult_left) {
+ asf->state = PARSE_PACKET_HEADER;
+ if (!asf->return_subpayload &&
+ (avio_tell(pb) <= asf->packet_offset +
+ asf->packet_size - asf->pad_len))
+ avio_skip(pb, asf->pad_len); // skip padding
+ if (asf->packet_offset + asf->packet_size > avio_tell(pb))
+ avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET);
+ } else if (!asf->sub_left)
+ asf->state = READ_MULTI;
+ break;
+ case READ_MULTI:
+ if (!asf->nb_mult_left) {
+ asf->state = PARSE_PACKET_HEADER;
+ if (!asf->return_subpayload &&
+ (avio_tell(pb) <= asf->packet_offset +
+ asf->packet_size - asf->pad_len))
+ avio_skip(pb, asf->pad_len); // skip padding
+ if (asf->packet_offset + asf->packet_size > avio_tell(pb))
+ avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET);
+ }
+ break;
+ }
+ if (asf->return_subpayload) {
+ asf->return_subpayload = 0;
+ return 0;
+ }
+ for (i = 0; i < s->nb_streams; i++) {
+ ASFPacket *asf_pkt = &asf->asf_st[i]->pkt;
+ if (asf_pkt && !asf_pkt->size_left && asf_pkt->data_size) {
+ if (asf->asf_st[i]->span > 1 &&
+ asf->asf_st[i]->type == AVMEDIA_TYPE_AUDIO)
+ if ((ret = asf_deinterleave(s, asf_pkt, i)) < 0)
+ return ret;
+ av_packet_move_ref(pkt, &asf_pkt->avpkt);
+ pkt->stream_index = asf->asf_st[i]->index;
+ pkt->flags = asf_pkt->flags;
+ pkt->dts = asf_pkt->dts - asf->preroll;
+ asf_pkt->data_size = 0;
+ asf_pkt->frame_num = 0;
+ return 0;
+ }
+ }
+ }
+
+ if (pb->eof_reached)
+ return AVERROR_EOF;
+
+ return 0;
+}
+
+static int asf_read_close(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ for (i = 0; i < ASF_MAX_STREAMS; i++) {
+ av_dict_free(&asf->asf_sd[i].asf_met);
+ if (i < asf->nb_streams) {
+ av_packet_unref(&asf->asf_st[i]->pkt.avpkt);
+ av_freep(&asf->asf_st[i]);
+ }
+ }
+
+ asf->nb_streams = 0;
+ return 0;
+}
+
+static void reset_packet_state(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ asf->state = PARSE_PACKET_HEADER;
+ asf->offset = 0;
+ asf->return_subpayload = 0;
+ asf->sub_left = 0;
+ asf->sub_header_offset = 0;
+ asf->packet_offset = asf->first_packet_offset;
+ asf->pad_len = 0;
+ asf->rep_data_len = 0;
+ asf->dts_delta = 0;
+ asf->mult_sub_len = 0;
+ asf->nb_mult_left = 0;
+ asf->nb_sub = 0;
+ asf->prop_flags = 0;
+ asf->sub_dts = 0;
+ for (i = 0; i < asf->nb_streams; i++) {
+ ASFPacket *pkt = &asf->asf_st[i]->pkt;
+ pkt->size_left = 0;
+ pkt->data_size = 0;
+ pkt->duration = 0;
+ pkt->flags = 0;
+ pkt->dts = 0;
+ pkt->duration = 0;
+ av_packet_unref(&pkt->avpkt);
+ av_init_packet(&pkt->avpkt);
+ }
+}
+
+/*
+ * Find a timestamp for the requested position within the payload
+ * where the pos (position) is the offset inside the Data Object.
+ * When position is not on the packet boundary, asf_read_timestamp tries
+ * to find the closest packet offset after this position. If this packet
+ * is a key frame, this packet timestamp is read and an index entry is created
+ * for the packet. If this packet belongs to the requested stream,
+ * asf_read_timestamp upgrades pos to the packet beginning offset and
+ * returns this packet's dts. So returned dts is the dts of the first key frame with
+ * matching stream number after given position.
+ */
+static int64_t asf_read_timestamp(AVFormatContext *s, int stream_index,
+ int64_t *pos, int64_t pos_limit)
+{
+ ASFContext *asf = s->priv_data;
+ int64_t pkt_pos = *pos, pkt_offset, dts = AV_NOPTS_VALUE, data_end;
+ AVPacket pkt;
+ int n;
+
+ data_end = asf->data_offset + asf->data_size;
+
+ n = (pkt_pos - asf->first_packet_offset + asf->packet_size - 1) /
+ asf->packet_size;
+ n = av_clip(n, 0, ((data_end - asf->first_packet_offset) / asf->packet_size - 1));
+ pkt_pos = asf->first_packet_offset + n * asf->packet_size;
+
+ avio_seek(s->pb, pkt_pos, SEEK_SET);
+ pkt_offset = pkt_pos;
+
+ reset_packet_state(s);
+ while (avio_tell(s->pb) < data_end) {
+
+ int i, ret, st_found;
+
+ av_init_packet(&pkt);
+ pkt_offset = avio_tell(s->pb);
+ if ((ret = asf_read_packet(s, &pkt)) < 0) {
+ dts = AV_NOPTS_VALUE;
+ return ret;
+ }
+ // ASFPacket may contain fragments of packets belonging to different streams,
+ // pkt_offset is the offset of the first fragment within it.
+ if ((pkt_offset >= (pkt_pos + asf->packet_size)))
+ pkt_pos += asf->packet_size;
+ for (i = 0; i < asf->nb_streams; i++) {
+ ASFStream *st = asf->asf_st[i];
+
+ st_found = 0;
+ if (pkt.flags & AV_PKT_FLAG_KEY) {
+ dts = pkt.dts;
+ if (dts) {
+ av_add_index_entry(s->streams[pkt.stream_index], pkt_pos,
+ dts, pkt.size, 0, AVINDEX_KEYFRAME);
+ if (stream_index == st->index) {
+ st_found = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (st_found)
+ break;
+ av_packet_unref(&pkt);
+ }
+ *pos = pkt_pos;
+
+ av_packet_unref(&pkt);
+ return dts;
+}
+
+static int asf_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
+ ASFContext *asf = s->priv_data;
+ int idx, ret;
+
+ if (s->streams[stream_index]->nb_index_entries && asf->is_simple_index) {
+ idx = av_index_search_timestamp(s->streams[stream_index], timestamp, flags);
+ if (idx < 0 || idx >= s->streams[stream_index]->nb_index_entries)
+ return AVERROR_INVALIDDATA;
+ avio_seek(s->pb, s->streams[stream_index]->index_entries[idx].pos, SEEK_SET);
+ } else {
+ if ((ret = ff_seek_frame_binary(s, stream_index, timestamp, flags)) < 0)
+ return ret;
+ }
+
+ reset_packet_state(s);
+
+ return 0;
+}
+
+static const GUIDParseTable *find_guid(ff_asf_guid guid)
+{
+ int j, ret;
+ const GUIDParseTable *g;
+
+ swap_guid(guid);
+ g = gdef;
+ for (j = 0; j < FF_ARRAY_ELEMS(gdef); j++) {
+ if (!(ret = memcmp(guid, g->guid, sizeof(g->guid))))
+ return g;
+ g++;
+ }
+
+ return NULL;
+}
+
+static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ const GUIDParseTable *g = NULL;
+ ff_asf_guid guid;
+ int ret;
+
+ while (avio_tell(pb) <= offset + size) {
+ if (avio_tell(pb) == asf->offset)
+ break;
+ asf->offset = avio_tell(pb);
+ if ((ret = ff_get_guid(pb, &guid)) < 0)
+ return ret;
+ g = find_guid(guid);
+ if (g) {
+ if ((ret = g->read_object(s, g)) < 0)
+ return ret;
+ } else {
+ GUIDParseTable g2;
+
+ g2.name = "Unknown";
+ g2.is_subobject = 1;
+ asf_read_unknown(s, &g2);
+ }
+ }
+
+ return 0;
+}
+
+static int asf_read_header(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ const GUIDParseTable *g = NULL;
+ ff_asf_guid guid;
+ int i, ret;
+ uint64_t size;
+
+ asf->preroll = 0;
+ asf->is_simple_index = 0;
+ ff_get_guid(pb, &guid);
+ if (ff_guidcmp(&guid, &ff_asf_header))
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 8); // skip header object size
+ avio_skip(pb, 6); // skip number of header objects and 2 reserved bytes
+ asf->data_reached = 0;
+
+ /* 1 is here instead of pb->eof_reached because (when not streaming), Data are skipped
+ * for the first time,
+ * Index object is processed and got eof and then seeking back to the Data is performed.
+ */
+ while (1) {
+ // for the cases when object size is invalid
+ if (avio_tell(pb) == asf->offset)
+ break;
+ asf->offset = avio_tell(pb);
+ if ((ret = ff_get_guid(pb, &guid)) < 0) {
+ if (ret == AVERROR_EOF && asf->data_reached)
+ break;
+ else
+ goto failed;
+ }
+ g = find_guid(guid);
+ if (g) {
+ asf->unknown_offset = asf->offset;
+ asf->is_header = 1;
+ if ((ret = g->read_object(s, g)) < 0)
+ goto failed;
+ } else {
+ size = avio_rl64(pb);
+ align_position(pb, asf->offset, size);
+ }
- if (asf->data_reached && (!pb->seekable || (asf->b_flags & ASF_FLAG_BROADCAST)))
++ if (asf->data_reached &&
++ (!(pb->seekable & AVIO_SEEKABLE_NORMAL) ||
++ (asf->b_flags & ASF_FLAG_BROADCAST)))
+ break;
+ }
+
+ if (!asf->data_reached) {
+ av_log(s, AV_LOG_ERROR, "Data Object was not found.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto failed;
+ }
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ avio_seek(pb, asf->first_packet_offset, SEEK_SET);
+
+ for (i = 0; i < asf->nb_streams; i++) {
+ const char *rfc1766 = asf->asf_sd[asf->asf_st[i]->lang_idx].langs;
+ AVStream *st = s->streams[asf->asf_st[i]->index];
+ set_language(s, rfc1766, &st->metadata);
+ }
+
+ for (i = 0; i < ASF_MAX_STREAMS; i++) {
+ AVStream *st = NULL;
+
+ st = find_stream(s, i);
+ if (st) {
+ av_dict_copy(&st->metadata, asf->asf_sd[i].asf_met, AV_DICT_IGNORE_SUFFIX);
+ if (asf->asf_sd[i].aspect_ratio.num > 0 && asf->asf_sd[i].aspect_ratio.den > 0) {
+ st->sample_aspect_ratio.num = asf->asf_sd[i].aspect_ratio.num;
+ st->sample_aspect_ratio.den = asf->asf_sd[i].aspect_ratio.den;
+ }
+ }
+ }
+
+ return 0;
+
+failed:
+ asf_read_close(s);
+ return ret;
+}
+
+AVInputFormat ff_asf_o_demuxer = {
+ .name = "asf_o",
+ .long_name = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
+ .priv_data_size = sizeof(ASFContext),
+ .read_probe = asf_probe,
+ .read_header = asf_read_header,
+ .read_packet = asf_read_packet,
+ .read_close = asf_read_close,
+ .read_timestamp = asf_read_timestamp,
+ .read_seek = asf_read_seek,
+ .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH,
+};
diff --cc libavformat/asfenc.c
index 19dee3d,a40c02d..1b67143
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@@ -466,116 -425,25 +466,116 @@@ static int asf_write_header1(AVFormatCo
/* file header */
header_offset = avio_tell(pb);
hpos = put_header(pb, &ff_asf_file_header);
- put_guid(pb, &ff_asf_my_guid);
+ ff_put_guid(pb, &ff_asf_my_guid);
avio_wl64(pb, file_size);
- file_time = 0;
- avio_wl64(pb, unix_to_file_time(file_time));
+ avio_wl64(pb, unix_to_file_time(asf->creation_time));
avio_wl64(pb, asf->nb_packets); /* number of packets */
- avio_wl64(pb, play_duration); /* end time stamp (in 100ns units) */
- avio_wl64(pb, send_duration); /* duration (in 100ns units) */
+ avio_wl64(pb, duration); /* end time stamp (in 100ns units) */
+ avio_wl64(pb, asf->duration); /* duration (in 100ns units) */
avio_wl64(pb, PREROLL_TIME); /* start time stamp */
- avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2); /* ??? */
+ avio_wl32(pb, (asf->is_streamed || !(pb->seekable & AVIO_SEEKABLE_NORMAL)) ? 3 : 2); /* ??? */
avio_wl32(pb, s->packet_size); /* packet size */
avio_wl32(pb, s->packet_size); /* packet size */
- avio_wl32(pb, bit_rate); /* Nominal data rate in bps */
+ avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */
end_header(pb, hpos);
- /* unknown headers */
+ /* header_extension */
hpos = put_header(pb, &ff_asf_head1_guid);
- put_guid(pb, &ff_asf_head2_guid);
- avio_wl32(pb, 6);
- avio_wl16(pb, 0);
+ ff_put_guid(pb, &ff_asf_head2_guid);
+ avio_wl16(pb, 6);
+ avio_wl32(pb, 0); /* length, to be filled later */
+ if (asf->nb_languages) {
+ int64_t hpos2;
+ int i;
+ int nb_audio_languages = 0;
+
+ hpos2 = put_header(pb, &ff_asf_language_guid);
+ avio_wl16(pb, asf->nb_languages);
+ for (i = 0; i < asf->nb_languages; i++) {
+ avio_w8(pb, 6);
+ avio_put_str16le(pb, asf->languages[i]);
+ }
+ end_header(pb, hpos2);
+
+ for (i = 0; i < asf->nb_languages; i++)
+ if (audio_language_counts[i])
+ nb_audio_languages++;
+
+ if (nb_audio_languages > 1) {
+ hpos2 = put_header(pb, &ff_asf_group_mutual_exclusion_object);
+ ff_put_guid(pb, &ff_asf_mutex_language);
+ avio_wl16(pb, nb_audio_languages);
+ for (i = 0; i < asf->nb_languages; i++) {
+ if (audio_language_counts[i]) {
+ avio_wl16(pb, audio_language_counts[i]);
+ for (n = 0; n < s->nb_streams; n++)
+ if (asf->streams[n].stream_language_index == i && s->streams[n]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ avio_wl16(pb, n + 1);
+ }
+ }
+ end_header(pb, hpos2);
+ }
+
+ for (n = 0; n < s->nb_streams; n++) {
+ int64_t es_pos;
+ if (asf->streams[n].stream_language_index > 127)
+ continue;
+ es_pos = put_header(pb, &ff_asf_extended_stream_properties_object);
+ avio_wl64(pb, 0); /* start time */
+ avio_wl64(pb, 0); /* end time */
+ avio_wl32(pb, s->streams[n]->codecpar->bit_rate); /* data bitrate bps */
+ avio_wl32(pb, 5000); /* buffer size ms */
+ avio_wl32(pb, 0); /* initial buffer fullness */
+ avio_wl32(pb, s->streams[n]->codecpar->bit_rate); /* peak data bitrate */
+ avio_wl32(pb, 5000); /* maximum buffer size ms */
+ avio_wl32(pb, 0); /* max initial buffer fullness */
+ avio_wl32(pb, 0); /* max object size */
- avio_wl32(pb, (!asf->is_streamed && pb->seekable) << 1); /* flags - seekable */
++ avio_wl32(pb, (!asf->is_streamed && (pb->seekable & AVIO_SEEKABLE_NORMAL)) << 1); /* flags - seekable */
+ avio_wl16(pb, n + 1); /* stream number */
+ avio_wl16(pb, asf->streams[n].stream_language_index); /* language id index */
+ avio_wl64(pb, 0); /* avg time per frame */
+ avio_wl16(pb, 0); /* stream name count */
+ avio_wl16(pb, 0); /* payload extension system count */
+ end_header(pb, es_pos);
+ }
+ }
+ if (has_aspect_ratio) {
+ int64_t hpos2;
+ hpos2 = put_header(pb, &ff_asf_metadata_header);
+ avio_wl16(pb, 2 * has_aspect_ratio);
+ for (n = 0; n < s->nb_streams; n++) {
+ par = s->streams[n]->codecpar;
+ if ( par->codec_type == AVMEDIA_TYPE_VIDEO
+ && par->sample_aspect_ratio.num > 0
+ && par->sample_aspect_ratio.den > 0) {
+ AVRational sar = par->sample_aspect_ratio;
+ avio_wl16(pb, 0);
+ // the stream number is set like this below
+ avio_wl16(pb, n + 1);
+ avio_wl16(pb, 26); // name_len
+ avio_wl16(pb, 3); // value_type
+ avio_wl32(pb, 4); // value_len
+ avio_put_str16le(pb, "AspectRatioX");
+ avio_wl32(pb, sar.num);
+ avio_wl16(pb, 0);
+ // the stream number is set like this below
+ avio_wl16(pb, n + 1);
+ avio_wl16(pb, 26); // name_len
+ avio_wl16(pb, 3); // value_type
+ avio_wl32(pb, 4); // value_len
+ avio_put_str16le(pb, "AspectRatioY");
+ avio_wl32(pb, sar.den);
+ }
+ }
+ end_header(pb, hpos2);
+ }
+ {
+ int64_t pos1;
+ pos1 = avio_tell(pb);
+ avio_seek(pb, hpos + 42, SEEK_SET);
+ avio_wl32(pb, pos1 - hpos - 46);
+ avio_seek(pb, pos1, SEEK_SET);
+ }
end_header(pb, hpos);
/* title and other info */
@@@ -1128,14 -950,11 +1128,14 @@@ static int asf_write_trailer(AVFormatCo
/* write index */
data_size = avio_tell(s->pb);
- if ((!asf->is_streamed) && (asf->nb_index_count != 0))
- asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count);
+ if (!asf->is_streamed && asf->next_start_sec) {
+ 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);
- if (asf->is_streamed || !s->pb->seekable) {
+ if (asf->is_streamed || !(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
put_chunk(s, 0x4524, 0, 0); /* end of stream */
} else {
/* rewrite an updated header */
diff --cc libavformat/astenc.c
index 11f8717,0000000..578e658
mode 100644,000000..100644
--- a/libavformat/astenc.c
+++ b/libavformat/astenc.c
@@@ -1,214 -1,0 +1,214 @@@
+/*
+ * AST muxer
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "ast.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+
+typedef struct ASTMuxContext {
+ AVClass *class;
+ int64_t size;
+ int64_t samples;
+ int64_t loopstart;
+ int64_t loopend;
+ int fbs;
+} ASTMuxContext;
+
+#define CHECK_LOOP(type) \
+ if (ast->loop ## type > 0) { \
+ ast->loop ## type = av_rescale_rnd(ast->loop ## type, par->sample_rate, 1000, AV_ROUND_DOWN); \
+ if (ast->loop ## type < 0 || ast->loop ## type > UINT_MAX) { \
+ av_log(s, AV_LOG_ERROR, "Invalid loop" #type " value\n"); \
+ return AVERROR(EINVAL); \
+ } \
+ }
+
+static int ast_write_header(AVFormatContext *s)
+{
+ ASTMuxContext *ast = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVCodecParameters *par;
+ unsigned int codec_tag;
+
+ if (s->nb_streams == 1) {
+ par = s->streams[0]->codecpar;
+ } else {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (par->codec_id == AV_CODEC_ID_ADPCM_AFC) {
+ av_log(s, AV_LOG_ERROR, "muxing ADPCM AFC is not implemented\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ codec_tag = ff_codec_get_tag(ff_codec_ast_tags, par->codec_id);
+ if (!codec_tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (ast->loopend > 0 && ast->loopstart >= ast->loopend) {
+ av_log(s, AV_LOG_ERROR, "loopend can't be less or equal to loopstart\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Convert milliseconds to samples */
+ CHECK_LOOP(start)
+ CHECK_LOOP(end)
+
+ ffio_wfourcc(pb, "STRM");
+
+ ast->size = avio_tell(pb);
+ avio_wb32(pb, 0); /* File size minus header */
+ avio_wb16(pb, codec_tag);
+ avio_wb16(pb, 16); /* Bit depth */
+ avio_wb16(pb, par->channels);
+ avio_wb16(pb, 0); /* Loop flag */
+ avio_wb32(pb, par->sample_rate);
+
+ ast->samples = avio_tell(pb);
+ avio_wb32(pb, 0); /* Number of samples */
+ avio_wb32(pb, 0); /* Loopstart */
+ avio_wb32(pb, 0); /* Loopend */
+ avio_wb32(pb, 0); /* Size of first block */
+
+ /* Unknown */
+ avio_wb32(pb, 0);
+ avio_wl32(pb, 0x7F);
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+ avio_wb32(pb, 0);
+
+ avio_flush(pb);
+
+ return 0;
+}
+
+static int ast_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ ASTMuxContext *ast = s->priv_data;
+ AVCodecParameters *par = s->streams[0]->codecpar;
+ int size = pkt->size / par->channels;
+
+ if (s->streams[0]->nb_frames == 0)
+ ast->fbs = size;
+
+ ffio_wfourcc(pb, "BLCK");
+ avio_wb32(pb, size); /* Block size */
+
+ /* padding */
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+
+ avio_write(pb, pkt->data, pkt->size);
+
+ return 0;
+}
+
+static int ast_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ ASTMuxContext *ast = s->priv_data;
+ AVCodecParameters *par = s->streams[0]->codecpar;
+ int64_t file_size = avio_tell(pb);
+ int64_t samples = (file_size - 64 - (32 * s->streams[0]->nb_frames)) / par->block_align; /* PCM_S16BE_PLANAR */
+
+ av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
+
- if (s->pb->seekable) {
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ /* Number of samples */
+ avio_seek(pb, ast->samples, SEEK_SET);
+ avio_wb32(pb, samples);
+
+ /* Loopstart if provided */
+ if (ast->loopstart > 0) {
+ if (ast->loopstart >= samples) {
+ av_log(s, AV_LOG_WARNING, "Loopstart value is out of range and will be ignored\n");
+ ast->loopstart = -1;
+ avio_skip(pb, 4);
+ } else
+ avio_wb32(pb, ast->loopstart);
+ } else
+ avio_skip(pb, 4);
+
+ /* Loopend if provided. Otherwise number of samples again */
+ if (ast->loopend && ast->loopstart >= 0) {
+ if (ast->loopend > samples) {
+ av_log(s, AV_LOG_WARNING, "Loopend value is out of range and will be ignored\n");
+ ast->loopend = samples;
+ }
+ avio_wb32(pb, ast->loopend);
+ } else {
+ avio_wb32(pb, samples);
+ }
+
+ /* Size of first block */
+ avio_wb32(pb, ast->fbs);
+
+ /* File size minus header */
+ avio_seek(pb, ast->size, SEEK_SET);
+ avio_wb32(pb, file_size - 64);
+
+ /* Loop flag */
+ if (ast->loopstart >= 0) {
+ avio_skip(pb, 6);
+ avio_wb16(pb, 0xFFFF);
+ }
+
+ avio_seek(pb, file_size, SEEK_SET);
+ avio_flush(pb);
+ }
+ return 0;
+}
+
+#define OFFSET(obj) offsetof(ASTMuxContext, obj)
+static const AVOption options[] = {
+ { "loopstart", "Loopstart position in milliseconds.", OFFSET(loopstart), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "loopend", "Loopend position in milliseconds.", OFFSET(loopend), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass ast_muxer_class = {
+ .class_name = "AST muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_ast_muxer = {
+ .name = "ast",
+ .long_name = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
+ .extensions = "ast",
+ .priv_data_size = sizeof(ASTMuxContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = ast_write_header,
+ .write_packet = ast_write_packet,
+ .write_trailer = ast_write_trailer,
+ .priv_class = &ast_muxer_class,
+ .codec_tag = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
+};
diff --cc libavformat/au.c
index f70f827,20c9d41..520824f
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@@ -318,13 -190,13 +318,13 @@@ static int au_write_header(AVFormatCont
static int au_write_trailer(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
- int64_t file_size;
+ AUContext *au = s->priv_data;
+ int64_t file_size = avio_tell(pb);
- if (s->pb->seekable && file_size < INT32_MAX) {
- if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && file_size < INT32_MAX) {
/* update file size */
- file_size = avio_tell(pb);
avio_seek(pb, 8, SEEK_SET);
- avio_wb32(pb, (uint32_t)(file_size - 24));
+ avio_wb32(pb, (uint32_t)(file_size - au->header_size));
avio_seek(pb, file_size, SEEK_SET);
avio_flush(pb);
}
diff --cc libavformat/avidec.c
index abe8c98,ddc7c2b..e2527a1
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@@ -917,40 -759,11 +917,40 @@@ FF_ENABLE_DEPRECATION_WARNING
}
}
break;
+ case MKTAG('s', 't', 'r', 'd'):
+ if (stream_index >= (unsigned)s->nb_streams
+ || s->streams[stream_index]->codecpar->extradata_size
+ || s->streams[stream_index]->codecpar->codec_tag == MKTAG('H','2','6','4')) {
+ avio_skip(pb, size);
+ } else {
+ uint64_t cur_pos = avio_tell(pb);
+ if (cur_pos < list_end)
+ size = FFMIN(size, list_end - cur_pos);
+ st = s->streams[stream_index];
+
+ if (size<(1<<30)) {
+ if (st->codecpar->extradata) {
+ av_log(s, AV_LOG_WARNING, "New extradata in strd chunk, freeing previous one.\n");
+ av_freep(&st->codecpar->extradata);
+ }
+ if (ff_get_extradata(s, st->codecpar, pb, size) < 0)
+ return AVERROR(ENOMEM);
+ }
+
+ if (st->codecpar->extradata_size & 1) //FIXME check if the encoder really did this correctly
+ avio_r8(pb);
+
+ ret = avi_extract_stream_metadata(s, st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING, "could not decoding EXIF data in stream header.\n");
+ }
+ }
+ break;
case MKTAG('i', 'n', 'd', 'x'):
pos = avio_tell(pb);
- if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
- if ((pb->seekable & AVIO_SEEKABLE_NORMAL) &&
- !(s->flags & AVFMT_FLAG_IGNIDX) &&
- read_braindead_odml_indx(s, 0) < 0 &&
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !(s->flags & AVFMT_FLAG_IGNIDX) &&
+ avi->use_odml &&
+ read_odml_index(s, 0) < 0 &&
(s->error_recognition & AV_EF_EXPLODE))
goto fail;
avio_seek(pb, pos + size, SEEK_SET);
@@@ -1022,10 -829,9 +1022,10 @@@ fail
return AVERROR_INVALIDDATA;
}
- if (!avi->index_loaded && pb->seekable)
+ if (!avi->index_loaded && (pb->seekable & AVIO_SEEKABLE_NORMAL))
avi_load_index(s);
- avi->index_loaded = 1;
+ calculate_bitrate(s);
+ avi->index_loaded |= 1;
if ((ret = guess_ni_flag(s)) < 0)
return ret;
diff --cc libavformat/avienc.c
index 4b042a9,e474398..91b8c40
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@@ -479,22 -304,29 +479,22 @@@ static int avi_write_header(AVFormatCon
ff_riff_write_info_tag(s->pb, "strn", t->value);
t = NULL;
}
+ if (par->codec_id == AV_CODEC_ID_XSUB
+ && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) {
+ const char* langstr = ff_convert_lang_to(t->value, AV_LANG_ISO639_1);
+ t = NULL;
+ if (langstr) {
+ char* str = av_asprintf("Subtitle - %s-xx;02", langstr);
+ if (!str)
+ return AVERROR(ENOMEM);
+ ff_riff_write_info_tag(s->pb, "strn", str);
+ av_free(str);
+ }
+ }
}
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
- unsigned char tag[5];
- int j;
-
- /* Starting to lay out AVI OpenDML master index.
- * We want to make it JUNK entry for now, since we'd
- * like to get away without making AVI an OpenDML one
- * for compatibility reasons. */
- avist->indexes.entry = avist->indexes.ents_allocated = 0;
- avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
- avio_wl16(pb, 4); /* wLongsPerEntry */
- avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
- avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
- avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */
- ffio_wfourcc(pb, avi_stream2fourcc(tag, i, par->codec_type));
- /* dwChunkId */
- avio_wl64(pb, 0); /* dwReserved[3] */
- // avio_wl32(pb, 0); /* Must be 0. */
- for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
- avio_wl64(pb, 0);
- ff_end_tag(pb, avist->indexes.indx_start);
+ write_odml_master(s, i);
}
if (par->codec_type == AVMEDIA_TYPE_VIDEO &&
@@@ -611,22 -403,10 +611,22 @@@ static int avi_write_ix(AVFormatContex
char ix_tag[] = "ix00";
int i, j;
- av_assert0(pb->seekable);
- assert(pb->seekable & AVIO_SEEKABLE_NORMAL);
++ av_assert0(pb->seekable & AVIO_SEEKABLE_NORMAL);
- if (avi->riff_id > AVI_MASTER_INDEX_SIZE)
- return -1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVIStream *avist = s->streams[i]->priv_data;
+ if (avi->riff_id - avist->indexes.master_odml_riff_id_base == avi->master_index_max_size) {
+ int64_t pos;
+ int size = AVI_MASTER_INDEX_PREFIX_SIZE + AVI_MASTER_INDEX_ENTRY_SIZE * avi->master_index_max_size;
+
+ pos = avio_tell(pb);
+ update_odml_entry(s, i, pos, size);
+ write_odml_master(s, i);
+ av_assert1(avio_tell(pb) - pos == size);
+ avist->indexes.master_odml_riff_id_base = avi->riff_id - 1;
+ }
+ av_assert0(avi->riff_id - avist->indexes.master_odml_riff_id_base < avi->master_index_max_size);
+ }
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
@@@ -716,129 -504,8 +716,129 @@@ static int avi_write_idx1(AVFormatConte
return 0;
}
+static int write_skip_frames(AVFormatContext *s, int stream_index, int64_t dts)
+{
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVCodecParameters *par = s->streams[stream_index]->codecpar;
+
+ ff_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(dts), avist->packet_count, stream_index);
+ while (par->block_align == 0 && dts != AV_NOPTS_VALUE &&
+ dts > avist->packet_count && par->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) {
+ AVPacket empty_packet;
+
+ if (dts - avist->packet_count > 60000) {
+ av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", dts - avist->packet_count);
+ return AVERROR(EINVAL);
+ }
+
+ av_init_packet(&empty_packet);
+ empty_packet.size = 0;
+ empty_packet.data = NULL;
+ empty_packet.stream_index = stream_index;
+ avi_write_packet_internal(s, &empty_packet);
+ ff_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count);
+ }
+
+ return 0;
+}
+
static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ const int stream_index = pkt->stream_index;
+ AVCodecParameters *par = s->streams[stream_index]->codecpar;
+ int ret;
+
+ if (par->codec_id == AV_CODEC_ID_H264 && par->codec_tag == MKTAG('H','2','6','4') && pkt->size) {
+ ret = ff_check_h264_startcode(s, s->streams[stream_index], pkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ if ((ret = write_skip_frames(s, stream_index, pkt->dts)) < 0)
+ return ret;
+
+ if (!pkt->size)
+ return avi_write_packet_internal(s, pkt); /* Passthrough */
+
+ if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVIOContext *pb = s->pb;
+ AVPacket *opkt = pkt;
+ int reshuffle_ret;
+ if (par->codec_id == AV_CODEC_ID_RAWVIDEO && par->codec_tag == 0) {
+ int64_t bpc = par->bits_per_coded_sample != 15 ? par->bits_per_coded_sample : 16;
+ int expected_stride = ((par->width * bpc + 31) >> 5)*4;
+ reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, par, expected_stride);
+ if (reshuffle_ret < 0)
+ return reshuffle_ret;
+ } else
+ reshuffle_ret = 0;
+ if (par->format == AV_PIX_FMT_PAL8) {
+ ret = ff_get_packet_palette(s, opkt, reshuffle_ret, avist->palette);
+ if (ret < 0)
+ goto fail;
+ if (ret) {
+ int pal_size = 1 << par->bits_per_coded_sample;
+ int pc_tag, i;
+
+ av_assert0(par->bits_per_coded_sample >= 0 && par->bits_per_coded_sample <= 8);
+
- if (pb->seekable && avist->pal_offset) {
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && avist->pal_offset) {
+ int64_t cur_offset = avio_tell(pb);
+ avio_seek(pb, avist->pal_offset, SEEK_SET);
+ for (i = 0; i < pal_size; i++) {
+ uint32_t v = avist->palette[i];
+ avio_wl32(pb, v & 0xffffff);
+ }
+ avio_seek(pb, cur_offset, SEEK_SET);
+ memcpy(avist->old_palette, avist->palette, pal_size * 4);
+ avist->pal_offset = 0;
+ }
+ if (memcmp(avist->palette, avist->old_palette, pal_size * 4)) {
+ unsigned char tag[5];
+ avi_stream2fourcc(tag, stream_index, par->codec_type);
+ tag[2] = 'p'; tag[3] = 'c';
- if (s->pb->seekable) {
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ if (avist->strh_flags_offset) {
+ int64_t cur_offset = avio_tell(pb);
+ avio_seek(pb, avist->strh_flags_offset, SEEK_SET);
+ avio_wl32(pb, AVISF_VIDEO_PALCHANGES);
+ avio_seek(pb, cur_offset, SEEK_SET);
+ avist->strh_flags_offset = 0;
+ }
+ ret = avi_add_ientry(s, stream_index, tag, AVIIF_NO_TIME,
+ pal_size * 4 + 4);
+ if (ret < 0)
+ goto fail;
+ }
+ pc_tag = ff_start_tag(pb, tag);
+ avio_w8(pb, 0);
+ avio_w8(pb, pal_size & 0xFF);
+ avio_wl16(pb, 0); // reserved
+ for (i = 0; i < pal_size; i++) {
+ uint32_t v = avist->palette[i];
+ avio_wb32(pb, v<<8);
+ }
+ ff_end_tag(pb, pc_tag);
+ memcpy(avist->old_palette, avist->palette, pal_size * 4);
+ }
+ }
+ }
+ if (reshuffle_ret) {
+ ret = avi_write_packet_internal(s, pkt);
+
+fail:
+ if (reshuffle_ret)
+ av_packet_free(&pkt);
+ return ret;
+ }
+ }
+
+ return avi_write_packet_internal(s, pkt);
+}
+
+static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+{
unsigned char tag[5];
unsigned int flags = 0;
const int stream_index = pkt->stream_index;
@@@ -872,11 -546,29 +872,11 @@@
if (par->codec_type == AVMEDIA_TYPE_AUDIO)
avist->audio_strm_length += size;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
- int err;
- AVIIndex *idx = &avist->indexes;
- int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
- int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
- if (idx->ents_allocated <= idx->entry) {
- if ((err = av_reallocp(&idx->cluster,
- (cl + 1) * sizeof(*idx->cluster))) < 0) {
- idx->ents_allocated = 0;
- idx->entry = 0;
- return err;
- }
- idx->cluster[cl] =
- av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry));
- if (!idx->cluster[cl])
- return -1;
- idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
- }
-
- idx->cluster[cl][id].flags = flags;
- idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
- idx->cluster[cl][id].len = size;
- idx->entry++;
+ int ret;
+ ret = avi_add_ientry(s, stream_index, NULL, flags, size);
+ if (ret < 0)
+ return ret;
}
avio_write(pb, tag, 4);
@@@ -896,12 -588,7 +896,12 @@@ static int avi_write_trailer(AVFormatCo
int i, j, n, nb_frames;
int64_t file_size;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVIStream *avist = s->streams[i]->priv_data;
+ write_skip_frames(s, i, avist->last_dts);
+ }
+
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (avi->riff_id == 1) {
ff_end_tag(pb, avi->movi_list);
res = avi_write_idx1(s);
@@@ -947,13 -626,9 +947,13 @@@
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;
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ avio_seek(pb, avist->frames_hdr_strm + 4, SEEK_SET);
+ avio_wl32(pb, avist->max_size);
+ }
}
return res;
diff --cc libavformat/aviobuf.c
index 4ade4d0,39a11e2..5f58ab0
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@@ -253,26 -260,14 +253,26 @@@ int64_t avio_seek(AVIOContext *s, int64
return offset1;
offset += offset1;
}
- offset1 = offset - pos;
- if (!s->must_flush &&
- offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
+ if (offset < 0)
+ return AVERROR(EINVAL);
+
+ if (s->short_seek_get) {
+ short_seek = s->short_seek_get(s->opaque);
+ /* fallback to default short seek */
+ if (short_seek <= 0)
+ short_seek = s->short_seek_threshold;
+ } else
+ short_seek = s->short_seek_threshold;
+
+ offset1 = offset - pos; // "offset1" is the relative offset from the beginning of s->buffer
+ if (!s->must_flush && (!s->direct || !s->seek) &&
+ offset1 >= 0 && offset1 <= buffer_size - s->write_flag) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
- } else if ((!s->seekable ||
+ } else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) ||
- offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
+ offset1 <= buffer_size + short_seek) &&
!s->write_flag && offset1 >= 0 &&
+ (!s->direct || !s->seek) &&
(whence != SEEK_END || force)) {
while(s->pos < offset && !s->eof_reached)
fill_buffer(s);
diff --cc libavformat/bintext.c
index a264fd1,0000000..12e3bfd
mode 100644,000000..100644
--- a/libavformat/bintext.c
+++ b/libavformat/bintext.c
@@@ -1,388 -1,0 +1,388 @@@
+/*
+ * Binary text demuxer
+ * eXtended BINary text (XBIN) demuxer
+ * Artworx Data Format demuxer
+ * iCEDraw File demuxer
+ * Copyright (c) 2010 Peter Ross <pross at xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Binary text demuxer
+ * eXtended BINary text (XBIN) demuxer
+ * Artworx Data Format demuxer
+ * iCEDraw File demuxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avformat.h"
+#include "internal.h"
+#include "sauce.h"
+#include "libavcodec/bintext.h"
+
+typedef struct {
+ const AVClass *class;
+ 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 */
+ 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;
+
+static AVStream * init_stream(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return NULL;
+ st->codecpar->codec_tag = 0;
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ if (!bin->width) {
+ st->codecpar->width = (80<<3);
+ st->codecpar->height = (25<<4);
+ }
+
+ avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num);
+
+ /* simulate tty display speed */
+ bin->chars_per_frame = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX);
+
+ return st;
+}
+
+#if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
+/**
+ * Given filesize and width, calculate height (assume font_height of 16)
+ */
+static void calculate_height(AVCodecParameters *par, uint64_t fsize)
+{
+ par->height = (fsize / ((par->width>>3)*2)) << 4;
+}
+#endif
+
+#if CONFIG_BINTEXT_DEMUXER
+static const uint8_t next_magic[]={
+ 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
+};
+
+static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize)
+{
+ AVIOContext *pb = avctx->pb;
+ char buf[36];
+ int len;
+ uint64_t start_pos = avio_size(pb) - 256;
+
+ avio_seek(pb, start_pos, SEEK_SET);
+ if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic))
+ return -1;
+ if (memcmp(buf, next_magic, sizeof(next_magic)))
+ return -1;
+ if (avio_r8(pb) != 0x01)
+ return -1;
+
+ *fsize -= 256;
+
+#define GET_EFI2_META(name,size) \
+ len = avio_r8(pb); \
+ if (len < 1 || len > size) \
+ return -1; \
+ if (avio_read(pb, buf, size) == size && *buf) { \
+ buf[len] = 0; \
+ av_dict_set(&avctx->metadata, name, buf, 0); \
+ }
+
+ GET_EFI2_META("filename", 12)
+ GET_EFI2_META("author", 20)
+ GET_EFI2_META("publisher", 20)
+ GET_EFI2_META("title", 35)
+
+ return 0;
+}
+
+static void predict_width(AVCodecParameters *par, uint64_t fsize, int got_width)
+{
+ /** attempt to guess width */
+ if (!got_width)
+ par->width = fsize > 4000 ? (160<<3) : (80<<3);
+}
+
+static int bintext_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ AVStream *st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codecpar->codec_id = AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codecpar, 2))
+ return AVERROR(ENOMEM);
+ st->codecpar->extradata[0] = 16;
+ st->codecpar->extradata[1] = 0;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ int got_width = 0;
+ bin->fsize = avio_size(pb);
+ if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
+ next_tag_read(s, &bin->fsize);
+ if (!bin->width) {
+ predict_width(st->codecpar, bin->fsize, got_width);
+ calculate_height(st->codecpar, bin->fsize);
+ }
+ avio_seek(pb, 0, SEEK_SET);
+ }
+ return 0;
+}
+#endif /* CONFIG_BINTEXT_DEMUXER */
+
+#if CONFIG_XBIN_DEMUXER
+static int xbin_probe(AVProbeData *p)
+{
+ const uint8_t *d = p->buf;
+
+ if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A &&
+ AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 &&
+ d[9] > 0 && d[9] <= 32)
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int xbin_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ char fontheight, flags;
+
+ AVStream *st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 5);
+ st->codecpar->width = avio_rl16(pb)<<3;
+ st->codecpar->height = avio_rl16(pb);
+ fontheight = avio_r8(pb);
+ st->codecpar->height *= fontheight;
+ flags = avio_r8(pb);
+
+ st->codecpar->extradata_size = 2;
+ if ((flags & BINTEXT_PALETTE))
+ st->codecpar->extradata_size += 48;
+ if ((flags & BINTEXT_FONT))
+ st->codecpar->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
+ st->codecpar->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codecpar, st->codecpar->extradata_size))
+ return AVERROR(ENOMEM);
+ st->codecpar->extradata[0] = fontheight;
+ st->codecpar->extradata[1] = flags;
+ if (avio_read(pb, st->codecpar->extradata + 2, st->codecpar->extradata_size - 2) < 0)
+ return AVERROR(EIO);
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ bin->fsize = avio_size(pb) - 9 - st->codecpar->extradata_size;
+ ff_sauce_read(s, &bin->fsize, NULL, 0);
+ avio_seek(pb, 9 + st->codecpar->extradata_size, SEEK_SET);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_XBIN_DEMUXER */
+
+#if CONFIG_ADF_DEMUXER
+static int adf_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+
+ if (avio_r8(pb) != 1)
+ return AVERROR_INVALIDDATA;
+
+ st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codecpar->codec_id = AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codecpar, 2 + 48 + 4096))
+ return AVERROR(ENOMEM);
+ st->codecpar->extradata[0] = 16;
+ st->codecpar->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
+
+ if (avio_read(pb, st->codecpar->extradata + 2, 24) < 0)
+ return AVERROR(EIO);
+ avio_skip(pb, 144);
+ if (avio_read(pb, st->codecpar->extradata + 2 + 24, 24) < 0)
+ return AVERROR(EIO);
+ if (avio_read(pb, st->codecpar->extradata + 2 + 48, 4096) < 0)
+ return AVERROR(EIO);
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ int got_width = 0;
+ bin->fsize = avio_size(pb) - 1 - 192 - 4096;
+ st->codecpar->width = 80<<3;
+ ff_sauce_read(s, &bin->fsize, &got_width, 0);
+ if (!bin->width)
+ calculate_height(st->codecpar, bin->fsize);
+ avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
+ }
+ return 0;
+}
+#endif /* CONFIG_ADF_DEMUXER */
+
+#if CONFIG_IDF_DEMUXER
+static const uint8_t idf_magic[] = {
+ 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
+};
+
+static int idf_probe(AVProbeData *p)
+{
+ if (p->buf_size < sizeof(idf_magic))
+ return 0;
+ if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int idf_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ int got_width = 0;
+
- if (!pb->seekable)
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
+ return AVERROR(EIO);
+
+ st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codecpar->codec_id = AV_CODEC_ID_IDF;
+
+ if (ff_alloc_extradata(st->codecpar, 2 + 48 + 4096))
+ return AVERROR(ENOMEM);
+ st->codecpar->extradata[0] = 16;
+ st->codecpar->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
+
+ avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
+
+ if (avio_read(pb, st->codecpar->extradata + 2 + 48, 4096) < 0)
+ return AVERROR(EIO);
+ if (avio_read(pb, st->codecpar->extradata + 2, 48) < 0)
+ return AVERROR(EIO);
+
+ bin->fsize = avio_size(pb) - 12 - 4096 - 48;
+ ff_sauce_read(s, &bin->fsize, &got_width, 0);
+ if (!bin->width)
+ calculate_height(st->codecpar, bin->fsize);
+ avio_seek(pb, 12, SEEK_SET);
+ return 0;
+}
+#endif /* CONFIG_IDF_DEMUXER */
+
+static int read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ BinDemuxContext *bin = s->priv_data;
+
+ if (bin->fsize > 0) {
+ if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
+ return AVERROR(EIO);
+ bin->fsize = -1; /* done */
+ } else if (!bin->fsize) {
+ if (avio_feof(s->pb))
+ return AVERROR(EIO);
+ if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
+ return AVERROR(EIO);
+ } else {
+ return AVERROR(EIO);
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ return 0;
+}
+
+#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(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, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+#define CLASS(name) \
+(const AVClass[1]){{ \
+ .class_name = name, \
+ .item_name = av_default_item_name, \
+ .option = options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+}}
+
+#if CONFIG_BINTEXT_DEMUXER
+AVInputFormat ff_bintext_demuxer = {
+ .name = "bin",
+ .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_header = bintext_read_header,
+ .read_packet = read_packet,
+ .extensions = "bin",
+ .priv_class = CLASS("Binary text demuxer"),
+};
+#endif
+
+#if CONFIG_XBIN_DEMUXER
+AVInputFormat ff_xbin_demuxer = {
+ .name = "xbin",
+ .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_probe = xbin_probe,
+ .read_header = xbin_read_header,
+ .read_packet = read_packet,
+ .priv_class = CLASS("eXtended BINary text (XBIN) demuxer"),
+};
+#endif
+
+#if CONFIG_ADF_DEMUXER
+AVInputFormat ff_adf_demuxer = {
+ .name = "adf",
+ .long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_header = adf_read_header,
+ .read_packet = read_packet,
+ .extensions = "adf",
+ .priv_class = CLASS("Artworx Data Format demuxer"),
+};
+#endif
+
+#if CONFIG_IDF_DEMUXER
+AVInputFormat ff_idf_demuxer = {
+ .name = "idf",
+ .long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_probe = idf_probe,
+ .read_header = idf_read_header,
+ .read_packet = read_packet,
+ .extensions = "idf",
+ .priv_class = CLASS("iCE Draw File demuxer"),
+};
+#endif
diff --cc libavformat/cafenc.c
index 5ea8e69,0000000..7aa9e8c
mode 100644,000000..100644
--- a/libavformat/cafenc.c
+++ b/libavformat/cafenc.c
@@@ -1,273 -1,0 +1,273 @@@
+/*
+ * Core Audio Format muxer
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "caf.h"
+#include "isom.h"
+#include "avio_internal.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/dict.h"
+
+typedef struct {
+ int64_t data;
+ uint8_t *pkt_sizes;
+ int size_buffer_size;
+ int size_entries_used;
+ int packets;
+} CAFContext;
+
+static uint32_t codec_flags(enum AVCodecID codec_id) {
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_F32BE:
+ case AV_CODEC_ID_PCM_F64BE:
+ return 1; //< kCAFLinearPCMFormatFlagIsFloat
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S32LE:
+ return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian
+ case AV_CODEC_ID_PCM_F32LE:
+ case AV_CODEC_ID_PCM_F64LE:
+ return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian
+ default:
+ return 0;
+ }
+}
+
+static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels, int block_align) {
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_S8:
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S24BE:
+ case AV_CODEC_ID_PCM_S32LE:
+ case AV_CODEC_ID_PCM_S32BE:
+ case AV_CODEC_ID_PCM_F32LE:
+ case AV_CODEC_ID_PCM_F32BE:
+ case AV_CODEC_ID_PCM_F64LE:
+ case AV_CODEC_ID_PCM_F64BE:
+ case AV_CODEC_ID_PCM_ALAW:
+ case AV_CODEC_ID_PCM_MULAW:
+ return 1;
+ case AV_CODEC_ID_MACE3:
+ case AV_CODEC_ID_MACE6:
+ return 6;
+ case AV_CODEC_ID_ADPCM_IMA_QT:
+ return 64;
+ case AV_CODEC_ID_AMR_NB:
+ case AV_CODEC_ID_GSM:
+ case AV_CODEC_ID_ILBC:
+ case AV_CODEC_ID_QCELP:
+ return 160;
+ case AV_CODEC_ID_GSM_MS:
+ return 320;
+ case AV_CODEC_ID_MP1:
+ return 384;
+ case AV_CODEC_ID_MP2:
+ case AV_CODEC_ID_MP3:
+ return 1152;
+ case AV_CODEC_ID_AC3:
+ return 1536;
+ case AV_CODEC_ID_QDM2:
+ case AV_CODEC_ID_QDMC:
+ return 2048 * channels;
+ case AV_CODEC_ID_ALAC:
+ return 4096;
+ case AV_CODEC_ID_ADPCM_IMA_WAV:
+ return (block_align - 4 * channels) * 8 / (4 * channels) + 1;
+ case AV_CODEC_ID_ADPCM_MS:
+ return (block_align - 7 * channels) * 2 / channels + 2;
+ default:
+ return 0;
+ }
+}
+
+static int caf_write_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ AVCodecParameters *par = s->streams[0]->codecpar;
+ CAFContext *caf = s->priv_data;
+ AVDictionaryEntry *t = NULL;
+ unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, par->codec_id);
+ int64_t chunk_size = 0;
+ int frame_size = par->frame_size;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ switch (par->codec_id) {
+ case AV_CODEC_ID_AAC:
+ av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (!codec_tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR_INVALIDDATA;
+ }
+
- if (!par->block_align && !pb->seekable) {
++ if (!par->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+ av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (par->codec_id != AV_CODEC_ID_MP3 || frame_size != 576)
+ frame_size = samples_per_packet(par->codec_id, par->channels, par->block_align);
+
+ ffio_wfourcc(pb, "caff"); //< mFileType
+ avio_wb16(pb, 1); //< mFileVersion
+ avio_wb16(pb, 0); //< mFileFlags
+
+ ffio_wfourcc(pb, "desc"); //< Audio Description chunk
+ avio_wb64(pb, 32); //< mChunkSize
+ avio_wb64(pb, av_double2int(par->sample_rate)); //< mSampleRate
+ avio_wl32(pb, codec_tag); //< mFormatID
+ avio_wb32(pb, codec_flags(par->codec_id)); //< mFormatFlags
+ avio_wb32(pb, par->block_align); //< mBytesPerPacket
+ avio_wb32(pb, frame_size); //< mFramesPerPacket
+ avio_wb32(pb, par->channels); //< mChannelsPerFrame
+ avio_wb32(pb, av_get_bits_per_sample(par->codec_id)); //< mBitsPerChannel
+
+ if (par->channel_layout) {
+ ffio_wfourcc(pb, "chan");
+ avio_wb64(pb, 12);
+ ff_mov_write_chan(pb, par->channel_layout);
+ }
+
+ if (par->codec_id == AV_CODEC_ID_ALAC) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, 12 + par->extradata_size);
+ avio_write(pb, "\0\0\0\14frmaalac", 12);
+ avio_write(pb, par->extradata, par->extradata_size);
+ } else if (par->codec_id == AV_CODEC_ID_AMR_NB) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, 29);
+ avio_write(pb, "\0\0\0\14frmasamr", 12);
+ avio_wb32(pb, 0x11); /* size */
+ avio_write(pb, "samrFFMP", 8);
+ avio_w8(pb, 0); /* decoder version */
+
+ avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
+ avio_w8(pb, 0x00); /* Mode change period (no restriction) */
+ avio_w8(pb, 0x01); /* Frames per sample */
+ } else if (par->codec_id == AV_CODEC_ID_QDM2 || par->codec_id == AV_CODEC_ID_QDMC) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, par->extradata_size);
+ avio_write(pb, par->extradata, par->extradata_size);
+ }
+
+ ff_standardize_creation_time(s);
+ if (av_dict_count(s->metadata)) {
+ ffio_wfourcc(pb, "info"); //< Information chunk
+ while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ chunk_size += strlen(t->key) + strlen(t->value) + 2;
+ }
+ avio_wb64(pb, chunk_size + 4);
+ avio_wb32(pb, av_dict_count(s->metadata));
+ t = NULL;
+ while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ avio_put_str(pb, t->key);
+ avio_put_str(pb, t->value);
+ }
+ }
+
+ ffio_wfourcc(pb, "data"); //< Audio Data chunk
+ caf->data = avio_tell(pb);
+ avio_wb64(pb, -1); //< mChunkSize
+ avio_wb32(pb, 0); //< mEditCount
+
+ avio_flush(pb);
+ return 0;
+}
+
+static int caf_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ CAFContext *caf = s->priv_data;
+
+ avio_write(s->pb, pkt->data, pkt->size);
+ if (!s->streams[0]->codecpar->block_align) {
+ void *pkt_sizes = caf->pkt_sizes;
+ int i, alloc_size = caf->size_entries_used + 5;
+ if (alloc_size < 0) {
+ caf->pkt_sizes = NULL;
+ } else {
+ caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes,
+ &caf->size_buffer_size,
+ alloc_size);
+ }
+ if (!caf->pkt_sizes) {
+ av_free(pkt_sizes);
+ return AVERROR(ENOMEM);
+ }
+ for (i = 4; i > 0; i--) {
+ unsigned top = pkt->size >> i * 7;
+ if (top)
+ caf->pkt_sizes[caf->size_entries_used++] = 128 | top;
+ }
+ caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127;
+ caf->packets++;
+ }
+ return 0;
+}
+
+static int caf_write_trailer(AVFormatContext *s)
+{
+ CAFContext *caf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVCodecParameters *par = s->streams[0]->codecpar;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ int64_t file_size = avio_tell(pb);
+
+ avio_seek(pb, caf->data, SEEK_SET);
+ avio_wb64(pb, file_size - caf->data - 8);
+ avio_seek(pb, file_size, SEEK_SET);
+ if (!par->block_align) {
+ ffio_wfourcc(pb, "pakt");
+ avio_wb64(pb, caf->size_entries_used + 24);
+ avio_wb64(pb, caf->packets); ///< mNumberPackets
+ avio_wb64(pb, caf->packets * samples_per_packet(par->codec_id, par->channels, par->block_align)); ///< mNumberValidFrames
+ avio_wb32(pb, 0); ///< mPrimingFrames
+ avio_wb32(pb, 0); ///< mRemainderFrames
+ avio_write(pb, caf->pkt_sizes, caf->size_entries_used);
+ caf->size_buffer_size = 0;
+ }
+ avio_flush(pb);
+ }
+ av_freep(&caf->pkt_sizes);
+ return 0;
+}
+
+AVOutputFormat ff_caf_muxer = {
+ .name = "caf",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple CAF (Core Audio Format)"),
+ .mime_type = "audio/x-caf",
+ .extensions = "caf",
+ .priv_data_size = sizeof(CAFContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16BE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = caf_write_header,
+ .write_packet = caf_write_packet,
+ .write_trailer = caf_write_trailer,
+ .codec_tag = (const AVCodecTag* const []){ff_codec_caf_tags, 0},
+};
diff --cc libavformat/cinedec.c
index 32cccf5,0000000..763b93b
mode 100644,000000..100644
--- a/libavformat/cinedec.c
+++ b/libavformat/cinedec.c
@@@ -1,325 -1,0 +1,325 @@@
+/*
+ * Phantom Cine demuxer
+ * Copyright (c) 2010-2011 Peter Ross <pross at xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Phantom Cine demuxer
+ * @author Peter Ross <pross at xvid.org>
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/bmp.h"
+#include "libavutil/intfloat.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct {
+ uint64_t pts;
+} CineDemuxContext;
+
+/** Compression */
+enum {
+ CC_RGB = 0, /**< Gray */
+ CC_LEAD = 1, /**< LEAD (M)JPEG */
+ CC_UNINT = 2 /**< Uninterpolated color image (CFA field indicates color ordering) */
+};
+
+/** Color Filter Array */
+enum {
+ CFA_NONE = 0, /**< GRAY */
+ CFA_VRI = 1, /**< GBRG/RGGB */
+ CFA_VRIV6 = 2, /**< BGGR/GRBG */
+ CFA_BAYER = 3, /**< GB/RG */
+ CFA_BAYERFLIP = 4, /**< RG/GB */
+};
+
+#define CFA_TLGRAY 0x80000000U
+#define CFA_TRGRAY 0x40000000U
+#define CFA_BLGRAY 0x20000000U
+#define CFA_BRGRAY 0x10000000U
+
+static int cine_read_probe(AVProbeData *p)
+{
+ int HeaderSize;
+ if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type
+ (HeaderSize = AV_RL16(p->buf + 2)) >= 0x2C && // HeaderSize
+ AV_RL16(p->buf + 4) <= CC_UNINT && // Compression
+ AV_RL16(p->buf + 6) <= 1 && // Version
+ AV_RL32(p->buf + 20) && // ImageCount
+ AV_RL32(p->buf + 24) >= HeaderSize && // OffImageHeader
+ AV_RL32(p->buf + 28) >= HeaderSize && // OffSetup
+ AV_RL32(p->buf + 32) >= HeaderSize) // OffImageOffsets
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int set_metadata_int(AVDictionary **dict, const char *key, int value, int allow_zero)
+{
+ if (value || allow_zero) {
+ return av_dict_set_int(dict, key, value, 0);
+ }
+ return 0;
+}
+
+static int set_metadata_float(AVDictionary **dict, const char *key, float value, int allow_zero)
+{
+ if (value != 0 || allow_zero) {
+ char tmp[64];
+ snprintf(tmp, sizeof(tmp), "%f", value);
+ return av_dict_set(dict, key, tmp, 0);
+ }
+ return 0;
+}
+
+static int cine_read_header(AVFormatContext *avctx)
+{
+ AVIOContext *pb = avctx->pb;
+ AVStream *st;
+ unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA;
+ int vflip;
+ char *description;
+ uint64_t i;
+
+ st = avformat_new_stream(avctx, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codecpar->codec_tag = 0;
+
+ /* CINEFILEHEADER structure */
+ avio_skip(pb, 4); // Type, Headersize
+
+ compression = avio_rl16(pb);
+ version = avio_rl16(pb);
+ if (version != 1) {
+ avpriv_request_sample(avctx, "unknown version %i", version);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber
+
+ st->duration = avio_rl32(pb);
+ offImageHeader = avio_rl32(pb);
+ offSetup = avio_rl32(pb);
+ offImageOffsets = avio_rl32(pb);
+
+ avio_skip(pb, 8); // TriggerTime
+
+ /* BITMAPINFOHEADER structure */
+ avio_seek(pb, offImageHeader, SEEK_SET);
+ avio_skip(pb, 4); //biSize
+ st->codecpar->width = avio_rl32(pb);
+ st->codecpar->height = avio_rl32(pb);
+
+ if (avio_rl16(pb) != 1) // biPlanes
+ return AVERROR_INVALIDDATA;
+
+ biBitCount = avio_rl16(pb);
+ if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (avio_rl32(pb)) {
+ case BMP_RGB:
+ vflip = 0;
+ break;
+ case 0x100: /* BI_PACKED */
+ st->codecpar->codec_tag = MKTAG('B', 'I', 'T', 0);
+ vflip = 1;
+ break;
+ default:
+ avpriv_request_sample(avctx, "unknown bitmap compression");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 4); // biSizeImage
+
+ /* parse SETUP structure */
+ avio_seek(pb, offSetup, SEEK_SET);
+ avio_skip(pb, 140); // FrameRatae16 .. descriptionOld
+ if (avio_rl16(pb) != 0x5453)
+ return AVERROR_INVALIDDATA;
+ length = avio_rl16(pb);
+ if (length < 0x163C) {
+ avpriv_request_sample(avctx, "short SETUP header");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 616); // Binning .. bFlipH
+ if (!avio_rl32(pb) ^ vflip) {
+ st->codecpar->extradata = av_strdup("BottomUp");
+ st->codecpar->extradata_size = 9;
+ }
+
+ avio_skip(pb, 4); // Grid
+
+ avpriv_set_pts_info(st, 64, 1, avio_rl32(pb));
+
+ avio_skip(pb, 20); // Shutter .. bEnableColor
+
+ set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "software_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb), 0);
+
+ CFA = avio_rl32(pb);
+
+ set_metadata_int(&st->metadata, "brightness", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "contrast", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "gamma", avio_rl32(pb), 1);
+
+ avio_skip(pb, 12 + 16); // Reserved1 .. AutoExpRect
+ set_metadata_float(&st->metadata, "wbgain[0].r", av_int2float(avio_rl32(pb)), 1);
+ set_metadata_float(&st->metadata, "wbgain[0].b", av_int2float(avio_rl32(pb)), 1);
+ avio_skip(pb, 36); // WBGain[1].. WBView
+
+ st->codecpar->bits_per_coded_sample = avio_rl32(pb);
+
+ if (compression == CC_RGB) {
+ if (biBitCount == 8) {
+ st->codecpar->format = AV_PIX_FMT_GRAY8;
+ } else if (biBitCount == 16) {
+ st->codecpar->format = AV_PIX_FMT_GRAY16LE;
+ } else if (biBitCount == 24) {
+ st->codecpar->format = AV_PIX_FMT_BGR24;
+ } else if (biBitCount == 48) {
+ st->codecpar->format = AV_PIX_FMT_BGR48LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ } else if (compression == CC_UNINT) {
+ switch (CFA & 0xFFFFFF) {
+ case CFA_BAYER:
+ if (biBitCount == 8) {
+ st->codecpar->format = AV_PIX_FMT_BAYER_GBRG8;
+ } else if (biBitCount == 16) {
+ st->codecpar->format = AV_PIX_FMT_BAYER_GBRG16LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case CFA_BAYERFLIP:
+ if (biBitCount == 8) {
+ st->codecpar->format = AV_PIX_FMT_BAYER_RGGB8;
+ } else if (biBitCount == 16) {
+ st->codecpar->format = AV_PIX_FMT_BAYER_RGGB16LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ default:
+ avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF);
+ return AVERROR_INVALIDDATA;
+ }
+ } else { //CC_LEAD
+ avpriv_request_sample(avctx, "unsupported compression %i", compression);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 668); // Conv8Min ... Sensor
+
+ set_metadata_int(&st->metadata, "shutter_ns", avio_rl32(pb), 0);
+
+ avio_skip(pb, 24); // EDRShutterNs ... ImHeightAcq
+
+#define DESCRIPTION_SIZE 4096
+ description = av_malloc(DESCRIPTION_SIZE + 1);
+ if (!description)
+ return AVERROR(ENOMEM);
+ i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1);
+ if (i < DESCRIPTION_SIZE)
+ avio_skip(pb, DESCRIPTION_SIZE - i);
+ if (description[0])
+ av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL);
+ else
+ av_free(description);
+
+ avio_skip(pb, 1176); // RisingEdge ... cmUser
+
+ set_metadata_int(&st->metadata, "enable_crop", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_left", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_top", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_right", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_bottom", avio_rl32(pb), 1);
+
+ /* parse image offsets */
+ avio_seek(pb, offImageOffsets, SEEK_SET);
+ for (i = 0; i < st->duration; i++)
+ av_add_index_entry(st, avio_rl64(pb), i, 0, 0, AVINDEX_KEYFRAME);
+
+ return 0;
+}
+
+static int cine_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ CineDemuxContext *cine = avctx->priv_data;
+ AVStream *st = avctx->streams[0];
+ AVIOContext *pb = avctx->pb;
+ int n, size, ret;
+
+ if (cine->pts >= st->duration)
+ return AVERROR_EOF;
+
+ avio_seek(pb, st->index_entries[cine->pts].pos, SEEK_SET);
+ n = avio_rl32(pb);
+ if (n < 8)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, n - 8);
+ size = avio_rl32(pb);
+
+ ret = av_get_packet(pb, pkt, size);
+ if (ret < 0)
+ return ret;
+
+ pkt->pts = cine->pts++;
+ pkt->stream_index = 0;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ return 0;
+}
+
+static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
+{
+ CineDemuxContext *cine = avctx->priv_data;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
- if (!avctx->pb->seekable)
++ if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
+ return AVERROR(EIO);
+
+ cine->pts = timestamp;
+ return 0;
+}
+
+AVInputFormat ff_cine_demuxer = {
+ .name = "cine",
+ .long_name = NULL_IF_CONFIG_SMALL("Phantom Cine"),
+ .priv_data_size = sizeof(CineDemuxContext),
+ .read_probe = cine_read_probe,
+ .read_header = cine_read_header,
+ .read_packet = cine_read_packet,
+ .read_seek = cine_read_seek,
+};
diff --cc libavformat/dsfdec.c
index f16b397,0000000..49ca336
mode 100644,000000..100644
--- a/libavformat/dsfdec.c
+++ b/libavformat/dsfdec.c
@@@ -1,163 -1,0 +1,163 @@@
+/*
+ * DSD Stream File (DSF) demuxer
+ * Copyright (c) 2014 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "id3v2.h"
+
+typedef struct {
+ uint64_t data_end;
+} DSFContext;
+
+static int dsf_probe(AVProbeData *p)
+{
+ if (p->buf_size < 12 || memcmp(p->buf, "DSD ", 4) || AV_RL64(p->buf + 4) != 28)
+ return 0;
+ return AVPROBE_SCORE_MAX;
+}
+
+static const uint64_t dsf_channel_layout[] = {
+ 0,
+ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_SURROUND,
+ AV_CH_LAYOUT_QUAD,
+ AV_CH_LAYOUT_4POINT0,
+ AV_CH_LAYOUT_5POINT0_BACK,
+ AV_CH_LAYOUT_5POINT1_BACK,
+};
+
+static void read_id3(AVFormatContext *s, uint64_t id3pos)
+{
+ ID3v2ExtraMeta *id3v2_extra_meta = NULL;
+ if (avio_seek(s->pb, id3pos, SEEK_SET) < 0)
+ return;
+
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0);
+ if (id3v2_extra_meta)
+ ff_id3v2_parse_apic(s, &id3v2_extra_meta);
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+}
+
+static int dsf_read_header(AVFormatContext *s)
+{
+ DSFContext *dsf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ uint64_t id3pos;
+ unsigned int channel_type;
+
+ avio_skip(pb, 4);
+ if (avio_rl64(pb) != 28)
+ return AVERROR_INVALIDDATA;
+
+ /* create primary stream before any id3 coverart streams */
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 8);
+ id3pos = avio_rl64(pb);
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ read_id3(s, id3pos);
+ avio_seek(pb, 28, SEEK_SET);
+ }
+
+ /* fmt chunk */
+
+ if (avio_rl32(pb) != MKTAG('f', 'm', 't', ' ') || avio_rl64(pb) != 52)
+ return AVERROR_INVALIDDATA;
+
+ if (avio_rl32(pb) != 1) {
+ avpriv_request_sample(s, "unknown format version");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (avio_rl32(pb)) {
+ avpriv_request_sample(s, "unknown format id");
+ return AVERROR_INVALIDDATA;
+ }
+
+ channel_type = avio_rl32(pb);
+ if (channel_type < FF_ARRAY_ELEMS(dsf_channel_layout))
+ st->codecpar->channel_layout = dsf_channel_layout[channel_type];
+ if (!st->codecpar->channel_layout)
+ avpriv_request_sample(s, "channel type %i", channel_type);
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->channels = avio_rl32(pb);
+ st->codecpar->sample_rate = avio_rl32(pb) / 8;
+
+ if (st->codecpar->channels <= 0)
+ return AVERROR_INVALIDDATA;
+
+ switch(avio_rl32(pb)) {
+ case 1: st->codecpar->codec_id = AV_CODEC_ID_DSD_LSBF_PLANAR; break;
+ case 8: st->codecpar->codec_id = AV_CODEC_ID_DSD_MSBF_PLANAR; break;
+ default:
+ avpriv_request_sample(s, "unknown most significant bit");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 8);
+ st->codecpar->block_align = avio_rl32(pb);
+ if (st->codecpar->block_align > INT_MAX / st->codecpar->channels) {
+ avpriv_request_sample(s, "block_align overflow");
+ return AVERROR_INVALIDDATA;
+ }
+ st->codecpar->block_align *= st->codecpar->channels;
+ st->codecpar->bit_rate = st->codecpar->channels * st->codecpar->sample_rate * 8LL;
+ avio_skip(pb, 4);
+
+ /* data chunk */
+
+ dsf->data_end = avio_tell(pb);
+ if (avio_rl32(pb) != MKTAG('d', 'a', 't', 'a'))
+ return AVERROR_INVALIDDATA;
+ dsf->data_end += avio_rl64(pb);
+
+ return 0;
+}
+
+static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ DSFContext *dsf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
+ int64_t pos = avio_tell(pb);
+
+ if (pos >= dsf->data_end)
+ return AVERROR_EOF;
+
+ pkt->stream_index = 0;
+ return av_get_packet(pb, pkt, FFMIN(dsf->data_end - pos, st->codecpar->block_align));
+}
+
+AVInputFormat ff_dsf_demuxer = {
+ .name = "dsf",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD Stream File (DSF)"),
+ .priv_data_size = sizeof(DSFContext),
+ .read_probe = dsf_probe,
+ .read_header = dsf_read_header,
+ .read_packet = dsf_read_packet,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK,
+};
diff --cc libavformat/dtshddec.c
index f5f0407,0000000..1bd403c
mode 100644,000000..100644
--- a/libavformat/dtshddec.c
+++ b/libavformat/dtshddec.c
@@@ -1,172 -1,0 +1,172 @@@
+/*
+ * Raw DTS-HD demuxer
+ * 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/intreadwrite.h"
+#include "libavutil/dict.h"
+#include "libavcodec/dca.h"
+#include "avformat.h"
+#include "internal.h"
+
+#define AUPR_HDR 0x415550522D484452
+#define AUPRINFO 0x41555052494E464F
+#define BITSHVTB 0x4249545348565442
+#define BLACKOUT 0x424C41434B4F5554
+#define BRANCHPT 0x4252414E43485054
+#define BUILDVER 0x4255494C44564552
+#define CORESSMD 0x434F524553534D44
+#define DTSHDHDR 0x4454534844484452
+#define EXTSS_MD 0x45585453535f4d44
+#define FILEINFO 0x46494C45494E464F
+#define NAVI_TBL 0x4E4156492D54424C
+#define STRMDATA 0x5354524D44415441
+#define TIMECODE 0x54494D45434F4445
+
+typedef struct DTSHDDemuxContext {
+ uint64_t data_end;
+} DTSHDDemuxContext;
+
+static int dtshd_probe(AVProbeData *p)
+{
+ if (AV_RB64(p->buf) == DTSHDHDR)
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int dtshd_read_header(AVFormatContext *s)
+{
+ DTSHDDemuxContext *dtshd = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t chunk_type, chunk_size;
+ int64_t duration, data_start;
+ AVStream *st;
+ int ret;
+ char *value;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->codec_id = AV_CODEC_ID_DTS;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+
+ for (;;) {
+ chunk_type = avio_rb64(pb);
+ chunk_size = avio_rb64(pb);
+
+ if (avio_feof(pb))
+ break;
+
+ if (chunk_size < 4) {
+ av_log(s, AV_LOG_ERROR, "chunk size too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (chunk_size > ((uint64_t)1 << 61)) {
+ av_log(s, AV_LOG_ERROR, "chunk size too big\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (chunk_type) {
+ case STRMDATA:
+ data_start = avio_tell(pb);
+ dtshd->data_end = data_start + chunk_size;
+ if (dtshd->data_end <= chunk_size)
+ return AVERROR_INVALIDDATA;
- if (!pb->seekable)
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
+ goto break_loop;
+ goto skip;
+ break;
+ case AUPR_HDR:
+ if (chunk_size < 21)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 3);
+ st->codecpar->sample_rate = avio_rb24(pb);
+ if (!st->codecpar->sample_rate)
+ return AVERROR_INVALIDDATA;
+ duration = avio_rb32(pb); // num_frames
+ duration *= avio_rb16(pb); // samples_per_frames
+ st->duration = duration;
+ avio_skip(pb, 5);
+ st->codecpar->channels = ff_dca_count_chs_for_mask(avio_rb16(pb));
+ st->codecpar->initial_padding = avio_rb16(pb);
+ avio_skip(pb, chunk_size - 21);
+ break;
+ case FILEINFO:
+ if (chunk_size > INT_MAX)
+ goto skip;
+ value = av_malloc(chunk_size);
+ if (!value)
+ goto skip;
+ avio_read(pb, value, chunk_size);
+ value[chunk_size - 1] = 0;
+ av_dict_set(&s->metadata, "fileinfo", value,
+ AV_DICT_DONT_STRDUP_VAL);
+ break;
+ default:
+skip:
+ ret = avio_skip(pb, chunk_size);
+ if (ret < 0)
+ return ret;
+ };
+ }
+
+ if (!dtshd->data_end)
+ return AVERROR_EOF;
+
+ avio_seek(pb, data_start, SEEK_SET);
+
+break_loop:
+ if (st->codecpar->sample_rate)
+ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+
+ return 0;
+}
+
+static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ DTSHDDemuxContext *dtshd = s->priv_data;
+ int64_t size, left;
+ int ret;
+
+ left = dtshd->data_end - avio_tell(s->pb);
+ size = FFMIN(left, 1024);
+ if (size <= 0)
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret < 0)
+ return ret;
+
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_dtshd_demuxer = {
+ .name = "dtshd",
+ .long_name = NULL_IF_CONFIG_SMALL("raw DTS-HD"),
+ .priv_data_size = sizeof(DTSHDDemuxContext),
+ .read_probe = dtshd_probe,
+ .read_header = dtshd_read_header,
+ .read_packet = raw_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .extensions = "dtshd",
+ .raw_codec_id = AV_CODEC_ID_DTS,
+};
diff --cc libavformat/dv.c
index 89a9e10,d4e5180..06de044
--- a/libavformat/dv.c
+++ b/libavformat/dv.c
@@@ -534,9 -473,6 +534,9 @@@ static int dv_read_header(AVFormatConte
(AVRational) { 8, 1 },
c->dv_demux->sys->time_base);
- if (s->pb->seekable)
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+ dv_read_timecode(s);
+
return 0;
}
diff --cc libavformat/ffmdec.c
index f863bf7,0000000..de6ac27
mode 100644,000000..100644
--- a/libavformat/ffmdec.c
+++ b/libavformat/ffmdec.c
@@@ -1,878 -1,0 +1,878 @@@
+/*
+ * FFM (ffserver live feed) demuxer
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * 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 <stdint.h>
+
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/internal.h"
+#include "avformat.h"
+#include "internal.h"
+#include "ffm.h"
+#include "avio_internal.h"
+
+static int ffm_is_avail_data(AVFormatContext *s, int size)
+{
+ FFMContext *ffm = s->priv_data;
+ int64_t pos, avail_size;
+ ptrdiff_t len;
+
+ len = ffm->packet_end - ffm->packet_ptr;
+ if (size <= len)
+ return 1;
+ pos = avio_tell(s->pb);
+ if (!ffm->write_index) {
+ if (pos == ffm->file_size)
+ return AVERROR_EOF;
+ avail_size = ffm->file_size - pos;
+ } else {
+ if (pos == ffm->write_index) {
+ /* exactly at the end of stream */
+ if (ffm->server_attached)
+ return AVERROR(EAGAIN);
+ else
+ return AVERROR_INVALIDDATA;
+ } else if (pos < ffm->write_index) {
+ avail_size = ffm->write_index - pos;
+ } else {
+ avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
+ }
+ }
+ avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
+ if (size <= avail_size)
+ return 1;
+ else if (ffm->server_attached)
+ return AVERROR(EAGAIN);
+ else
+ return AVERROR_INVALIDDATA;
+}
+
+static int ffm_resync(AVFormatContext *s, uint32_t state)
+{
+ av_log(s, AV_LOG_ERROR, "resyncing\n");
+ while (state != PACKET_ID) {
+ if (avio_feof(s->pb)) {
+ av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n");
+ return -1;
+ }
+ state = (state << 8) | avio_r8(s->pb);
+ }
+ return 0;
+}
+
+/* first is true if we read the frame header */
+static int ffm_read_data(AVFormatContext *s,
+ uint8_t *buf, int size, int header)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int fill_size, size1, frame_offset;
+ uint32_t id;
+ ptrdiff_t len;
+ int64_t last_pos = -1;
+
+ size1 = size;
+ while (size > 0) {
+ redo:
+ len = ffm->packet_end - ffm->packet_ptr;
+ if (len < 0)
+ return -1;
+ if (len > size)
+ len = size;
+ if (len == 0) {
+ if (avio_tell(pb) == ffm->file_size) {
+ if (ffm->server_attached) {
+ avio_seek(pb, ffm->packet_size, SEEK_SET);
+ } else
+ return AVERROR_EOF;
+ }
+ retry_read:
+ if (pb->buffer_size != ffm->packet_size) {
+ int64_t tell = avio_tell(pb);
+ int ret = ffio_set_buf_size(pb, ffm->packet_size);
+ if (ret < 0)
+ return ret;
+ avio_seek(pb, tell, SEEK_SET);
+ }
+ id = avio_rb16(pb); /* PACKET_ID */
+ if (id != PACKET_ID) {
+ if (ffm_resync(s, id) < 0)
+ return -1;
+ last_pos = avio_tell(pb);
+ }
+ fill_size = avio_rb16(pb);
+ ffm->dts = avio_rb64(pb);
+ frame_offset = avio_rb16(pb);
+ avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
+ if (ffm->packet_size < FFM_HEADER_SIZE + fill_size || frame_offset < 0) {
+ return -1;
+ }
+ ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
+ /* if first packet or resynchronization packet, we must
+ handle it specifically */
+ if (ffm->first_packet || (frame_offset & 0x8000)) {
+ if (!frame_offset) {
+ /* This packet has no frame headers in it */
+ if (avio_tell(pb) >= ffm->packet_size * 3LL) {
+ int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos);
+ seekback = FFMAX(seekback, 0);
+ avio_seek(pb, -seekback, SEEK_CUR);
+ goto retry_read;
+ }
+ /* This is bad, we cannot find a valid frame header */
+ return 0;
+ }
+ ffm->first_packet = 0;
+ if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) {
+ ffm->packet_end = ffm->packet_ptr;
+ return -1;
+ }
+ ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
+ if (!header)
+ break;
+ } else {
+ ffm->packet_ptr = ffm->packet;
+ }
+ goto redo;
+ }
+ memcpy(buf, ffm->packet_ptr, len);
+ buf += len;
+ ffm->packet_ptr += len;
+ size -= len;
+ header = 0;
+ }
+ return size1 - size;
+}
+
+/* ensure that actual seeking happens between FFM_PACKET_SIZE
+ and file_size - FFM_PACKET_SIZE */
+static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t pos;
+
+ pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE);
+ pos = FFMAX(pos, FFM_PACKET_SIZE);
+ ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos);
+ return avio_seek(pb, pos, SEEK_SET);
+}
+
+static int64_t get_dts(AVFormatContext *s, int64_t pos)
+{
+ AVIOContext *pb = s->pb;
+ int64_t dts;
+
+ ffm_seek1(s, pos);
+ avio_skip(pb, 4);
+ dts = avio_rb64(pb);
+ ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0);
+ return dts;
+}
+
+static void adjust_write_index(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t pts;
+ //int64_t orig_write_index = ffm->write_index;
+ int64_t pos_min, pos_max;
+ int64_t pts_start;
+ int64_t ptr = avio_tell(pb);
+
+
+ pos_min = 0;
+ pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
+
+ pts_start = get_dts(s, pos_min);
+
+ pts = get_dts(s, pos_max);
+
+ if (pts - 100000 > pts_start)
+ goto end;
+
+ ffm->write_index = FFM_PACKET_SIZE;
+
+ pts_start = get_dts(s, pos_min);
+
+ pts = get_dts(s, pos_max);
+
+ if (pts - 100000 <= pts_start) {
+ while (1) {
+ int64_t newpos;
+ int64_t newpts;
+
+ newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
+
+ if (newpos == pos_min)
+ break;
+
+ newpts = get_dts(s, newpos);
+
+ if (newpts - 100000 <= pts) {
+ pos_max = newpos;
+ pts = newpts;
+ } else {
+ pos_min = newpos;
+ }
+ }
+ ffm->write_index += pos_max;
+ }
+
+ end:
+ avio_seek(pb, ptr, SEEK_SET);
+}
+
+
+static int ffm_append_recommended_configuration(AVStream *st, char **conf)
+{
+ int ret;
+ size_t newsize;
+ av_assert0(conf && st);
+ if (!*conf)
+ return 0;
+ if (!st->recommended_encoder_configuration) {
+ st->recommended_encoder_configuration = *conf;
+ *conf = 0;
+ return 0;
+ }
+ newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2;
+ if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0)
+ return ret;
+ av_strlcat(st->recommended_encoder_configuration, ",", newsize);
+ av_strlcat(st->recommended_encoder_configuration, *conf, newsize);
+ av_freep(conf);
+ return 0;
+}
+
+#define VALIDATE_PARAMETER(parameter, name, check) { \
+ if (check) { \
+ av_log(s, AV_LOG_ERROR, "Invalid " name " %d\n", codecpar->parameter); \
+ ret = AVERROR_INVALIDDATA; \
+ goto fail; \
+ } \
+}
+
+static int ffm2_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st = NULL;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *dummy_codec = NULL;
+ AVCodecParameters *codecpar = NULL;
+ const AVCodecDescriptor *codec_desc;
+ int ret;
+ int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1;
+ AVCodec *enc;
+ char *buffer;
+
+ ffm->packet_size = avio_rb32(pb);
+ if (ffm->packet_size != FFM_PACKET_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n",
+ ffm->packet_size, FFM_PACKET_SIZE);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ ffm->write_index = avio_rb64(pb);
+ /* get also filesize */
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ ffm->file_size = avio_size(pb);
+ if (ffm->write_index && 0)
+ adjust_write_index(s);
+ } else {
+ ffm->file_size = (UINT64_C(1) << 63) - 1;
+ }
+ dummy_codec = avcodec_alloc_context3(NULL);
+
+ while(!avio_feof(pb)) {
+ unsigned id = avio_rb32(pb);
+ unsigned size = avio_rb32(pb);
+ int64_t next = avio_tell(pb) + size;
+ char rc_eq_buf[128];
+ int flags;
+
+ if(!id)
+ break;
+
+ switch(id) {
+ case MKBETAG('M', 'A', 'I', 'N'):
+ if (f_main++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ avio_rb32(pb); /* nb_streams */
+ avio_rb32(pb); /* total bitrate */
+ break;
+ case MKBETAG('C', 'O', 'M', 'M'):
+ f_cprv = f_stvi = f_stau = 0;
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ codecpar = st->codecpar;
+ /* generic info */
+ codecpar->codec_id = avio_rb32(pb);
+ codec_desc = avcodec_descriptor_get(codecpar->codec_id);
+ if (!codec_desc) {
+ av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id);
+ codecpar->codec_id = AV_CODEC_ID_NONE;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->codec_type = avio_r8(pb);
+ if (codecpar->codec_type != codec_desc->type) {
+ av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n",
+ codec_desc->type, codecpar->codec_type);
+ codecpar->codec_id = AV_CODEC_ID_NONE;
+ codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->bit_rate = avio_rb32(pb);
+ if (codecpar->bit_rate < 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ flags = avio_rb32(pb);
+#if FF_API_LAVF_AVCTX
+FF_DISABLE_DEPRECATION_WARNINGS
+ st->codec->flags = flags;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ avio_rb32(pb); // flags2
+ avio_rb32(pb); // debug
+ if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+ int size = avio_rb32(pb);
+ if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!codecpar->extradata) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ codecpar->extradata_size = size;
+ avio_read(pb, codecpar->extradata, size);
+ }
+ break;
+ case MKBETAG('S', 'T', 'V', 'I'):
+ if (f_stvi++ || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ avio_rb32(pb); // time_base.num
+ avio_rb32(pb); // time_base.den
+ codecpar->width = avio_rb16(pb);
+ codecpar->height = avio_rb16(pb);
+ ret = av_image_check_size(codecpar->width, codecpar->height, 0, s);
+ if (ret < 0)
+ goto fail;
+ avio_rb16(pb); // gop_size
+ codecpar->format = avio_rb32(pb);
+ if (!av_pix_fmt_desc_get(codecpar->format)) {
+ av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format);
+ codecpar->format = AV_PIX_FMT_NONE;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ avio_r8(pb); // qmin
+ avio_r8(pb); // qmax
+ avio_r8(pb); // max_qdiff
+ avio_rb16(pb); // qcompress / 10000.0
+ avio_rb16(pb); // qblur / 10000.0
+ avio_rb32(pb); // bit_rate_tolerance
+ avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
+
+ avio_rb32(pb); // rc_max_rate
+ avio_rb32(pb); // rc_min_rate
+ avio_rb32(pb); // rc_buffer_size
+ avio_rb64(pb); // i_quant_factor
+ avio_rb64(pb); // b_quant_factor
+ avio_rb64(pb); // i_quant_offset
+ avio_rb64(pb); // b_quant_offset
+ avio_rb32(pb); // dct_algo
+ avio_rb32(pb); // strict_std_compliance
+ avio_rb32(pb); // max_b_frames
+ avio_rb32(pb); // mpeg_quant
+ avio_rb32(pb); // intra_dc_precision
+ avio_rb32(pb); // me_method
+ avio_rb32(pb); // mb_decision
+ avio_rb32(pb); // nsse_weight
+ avio_rb32(pb); // frame_skip_cmp
+ avio_rb64(pb); // rc_buffer_aggressivity
+ codecpar->codec_tag = avio_rb32(pb);
+ avio_r8(pb); // thread_count
+ avio_rb32(pb); // coder_type
+ avio_rb32(pb); // me_cmp
+ avio_rb32(pb); // me_subpel_quality
+ avio_rb32(pb); // me_range
+ avio_rb32(pb); // keyint_min
+ avio_rb32(pb); // scenechange_threshold
+ avio_rb32(pb); // b_frame_strategy
+ avio_rb64(pb); // qcompress
+ avio_rb64(pb); // qblur
+ avio_rb32(pb); // max_qdiff
+ avio_rb32(pb); // refs
+ break;
+ case MKBETAG('S', 'T', 'A', 'U'):
+ if (f_stau++ || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ codecpar->sample_rate = avio_rb32(pb);
+ VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0)
+ codecpar->channels = avio_rl16(pb);
+ VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0)
+ codecpar->frame_size = avio_rl16(pb);
+ VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0)
+ break;
+ case MKBETAG('C', 'P', 'R', 'V'):
+ if (f_cprv++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ enc = avcodec_find_encoder(codecpar->codec_id);
+ if (enc && enc->priv_data_size && enc->priv_class) {
+ buffer = av_malloc(size + 1);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, size, buffer, size + 1);
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ }
+ break;
+ case MKBETAG('S', '2', 'V', 'I'):
+ if (f_stvi++ || !size || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, INT_MAX, buffer, size);
+ // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed
+ avcodec_parameters_to_context(dummy_codec, codecpar);
+ av_set_options_string(dummy_codec, buffer, "=", ",");
+ avcodec_parameters_from_context(codecpar, dummy_codec);
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ break;
+ case MKBETAG('S', '2', 'A', 'U'):
+ if (f_stau++ || !size || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, INT_MAX, buffer, size);
+ // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed
+ avcodec_parameters_to_context(dummy_codec, codecpar);
+ av_set_options_string(dummy_codec, buffer, "=", ",");
+ avcodec_parameters_from_context(codecpar, dummy_codec);
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ break;
+ }
+ avio_seek(pb, next, SEEK_SET);
+ }
+
+ /* get until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached)
+ avio_r8(pb);
+
+ /* init packet demux */
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->frame_offset = 0;
+ ffm->dts = 0;
+ ffm->read_state = READ_HEADER;
+ ffm->first_packet = 1;
+ avcodec_free_context(&dummy_codec);
+ return 0;
+ fail:
+ avcodec_free_context(&dummy_codec);
+ return ret;
+}
+
+static int ffm_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *dummy_codec = NULL;
+ AVCodecParameters *codecpar;
+ const AVCodecDescriptor *codec_desc;
+ int i, nb_streams, ret;
+ uint32_t tag;
+
+ /* header */
+ tag = avio_rl32(pb);
+ if (tag == MKTAG('F', 'F', 'M', '2'))
+ return ffm2_read_header(s);
+ if (tag != MKTAG('F', 'F', 'M', '1')) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ ffm->packet_size = avio_rb32(pb);
+ if (ffm->packet_size != FFM_PACKET_SIZE) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ ffm->write_index = avio_rb64(pb);
+ /* get also filesize */
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ ffm->file_size = avio_size(pb);
+ if (ffm->write_index && 0)
+ adjust_write_index(s);
+ } else {
+ ffm->file_size = (UINT64_C(1) << 63) - 1;
+ }
+ dummy_codec = avcodec_alloc_context3(NULL);
+
+ nb_streams = avio_rb32(pb);
+ avio_rb32(pb); /* total bitrate */
+ /* read each stream */
+ for(i=0;i<nb_streams;i++) {
+ char rc_eq_buf[128];
+ int flags;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ codecpar = st->codecpar;
+ /* generic info */
+ codecpar->codec_id = avio_rb32(pb);
+ codec_desc = avcodec_descriptor_get(codecpar->codec_id);
+ if (!codec_desc) {
+ av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id);
+ codecpar->codec_id = AV_CODEC_ID_NONE;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->codec_type = avio_r8(pb); /* codec_type */
+ if (codecpar->codec_type != codec_desc->type) {
+ av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n",
+ codec_desc->type, codecpar->codec_type);
+ codecpar->codec_id = AV_CODEC_ID_NONE;
+ codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->bit_rate = avio_rb32(pb);
+ if (codecpar->bit_rate < 0) {
+ av_log(s, AV_LOG_WARNING, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ flags = avio_rb32(pb);
+#if FF_API_LAVF_AVCTX
+FF_DISABLE_DEPRECATION_WARNINGS
+ st->codec->flags = flags;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ avio_rb32(pb); // flags2
+ avio_rb32(pb); // debug
+ /* specific info */
+ switch(codecpar->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ avio_rb32(pb); // time_base.num
+ avio_rb32(pb); // time_base.den
+ codecpar->width = avio_rb16(pb);
+ codecpar->height = avio_rb16(pb);
+ if ((ret = av_image_check_size(codecpar->width, codecpar->height, 0, s)) < 0)
+ goto fail;
+ avio_rb16(pb); // gop_size
+ codecpar->format = avio_rb32(pb);
+ if (!av_pix_fmt_desc_get(codecpar->format)) {
+ av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format);
+ codecpar->format = AV_PIX_FMT_NONE;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ avio_r8(pb); // qmin
+ avio_r8(pb); // qmax
+ avio_r8(pb); // max_qdiff
+ avio_rb16(pb); // qcompress / 10000.0
+ avio_rb16(pb); // qblur / 10000.0
+ avio_rb32(pb); // bit_rate_tolerance
+ avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
+
+ avio_rb32(pb); // rc_max_rate
+ avio_rb32(pb); // rc_min_rate
+ avio_rb32(pb); // rc_buffer_size
+ avio_rb64(pb); // i_quant_factor
+ avio_rb64(pb); // b_quant_factor
+ avio_rb64(pb); // i_quant_offset
+ avio_rb64(pb); // b_quant_offset
+ avio_rb32(pb); // dct_algo
+ avio_rb32(pb); // strict_std_compliance
+ avio_rb32(pb); // max_b_frames
+ avio_rb32(pb); // mpeg_quant
+ avio_rb32(pb); // intra_dc_precision
+ avio_rb32(pb); // me_method
+ avio_rb32(pb); // mb_decision
+ avio_rb32(pb); // nsse_weight
+ avio_rb32(pb); // frame_skip_cmp
+ avio_rb64(pb); // rc_buffer_aggressivity
+ codecpar->codec_tag = avio_rb32(pb);
+ avio_r8(pb); // thread_count
+ avio_rb32(pb); // coder_type
+ avio_rb32(pb); // me_cmp
+ avio_rb32(pb); // me_subpel_quality
+ avio_rb32(pb); // me_range
+ avio_rb32(pb); // keyint_min
+ avio_rb32(pb); // scenechange_threshold
+ avio_rb32(pb); // b_frame_strategy
+ avio_rb64(pb); // qcompress
+ avio_rb64(pb); // qblur
+ avio_rb32(pb); // max_qdiff
+ avio_rb32(pb); // refs
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ codecpar->sample_rate = avio_rb32(pb);
+ VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0)
+ codecpar->channels = avio_rl16(pb);
+ VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0)
+ codecpar->frame_size = avio_rl16(pb);
+ VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0)
+ break;
+ default:
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+ int size = avio_rb32(pb);
+ if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!codecpar->extradata) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ codecpar->extradata_size = size;
+ avio_read(pb, codecpar->extradata, size);
+ }
+ }
+
+ /* get until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached)
+ avio_r8(pb);
+
+ /* init packet demux */
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->frame_offset = 0;
+ ffm->dts = 0;
+ ffm->read_state = READ_HEADER;
+ ffm->first_packet = 1;
+ avcodec_free_context(&dummy_codec);
+ return 0;
+ fail:
+ avcodec_free_context(&dummy_codec);
+ return ret;
+}
+
+/* return < 0 if eof */
+static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int size;
+ FFMContext *ffm = s->priv_data;
+ int duration, ret;
+
+ switch(ffm->read_state) {
+ case READ_HEADER:
+ if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0)
+ return ret;
+
+ ff_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n",
+ avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size);
+ if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
+ FRAME_HEADER_SIZE)
+ return -1;
+ if (ffm->header[1] & FLAG_DTS)
+ if (ffm_read_data(s, ffm->header+16, 4, 1) != 4)
+ return -1;
+ ffm->read_state = READ_DATA;
+ /* fall through */
+ case READ_DATA:
+ size = AV_RB24(ffm->header + 2);
+ if ((ret = ffm_is_avail_data(s, size)) < 0)
+ return ret;
+
+ duration = AV_RB24(ffm->header + 5);
+
+ if (av_new_packet(pkt, size) < 0) {
+ return AVERROR(ENOMEM);
+ }
+ pkt->stream_index = ffm->header[0];
+ if ((unsigned)pkt->stream_index >= s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index);
+ av_packet_unref(pkt);
+ ffm->read_state = READ_HEADER;
+ return -1;
+ }
+ pkt->pos = avio_tell(s->pb);
+ if (ffm->header[1] & FLAG_KEY_FRAME)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ ffm->read_state = READ_HEADER;
+ if (ffm_read_data(s, pkt->data, size, 0) != size) {
+ /* bad case: desynchronized packet. we cancel all the packet loading */
+ av_packet_unref(pkt);
+ return -1;
+ }
+ pkt->pts = AV_RB64(ffm->header+8);
+ if (ffm->header[1] & FLAG_DTS)
+ pkt->dts = pkt->pts - AV_RB32(ffm->header+16);
+ else
+ pkt->dts = pkt->pts;
+ pkt->duration = duration;
+ break;
+ }
+ return 0;
+}
+
+/* seek to a given time in the file. The file read pointer is
+ positioned at or before pts. XXX: the following code is quite
+ approximative */
+static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
+{
+ FFMContext *ffm = s->priv_data;
+ int64_t pos_min, pos_max, pos;
+ int64_t pts_min, pts_max, pts;
+ double pos1;
+
+ ff_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
+ /* find the position using linear interpolation (better than
+ dichotomy in typical cases) */
+ if (ffm->write_index && ffm->write_index < ffm->file_size) {
+ if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) {
+ pos_min = FFM_PACKET_SIZE;
+ pos_max = ffm->write_index - FFM_PACKET_SIZE;
+ } else {
+ pos_min = ffm->write_index;
+ pos_max = ffm->file_size - FFM_PACKET_SIZE;
+ }
+ } else {
+ pos_min = FFM_PACKET_SIZE;
+ pos_max = ffm->file_size - FFM_PACKET_SIZE;
+ }
+ while (pos_min <= pos_max) {
+ pts_min = get_dts(s, pos_min);
+ pts_max = get_dts(s, pos_max);
+ if (pts_min > wanted_pts || pts_max <= wanted_pts) {
+ pos = pts_min > wanted_pts ? pos_min : pos_max;
+ goto found;
+ }
+ /* linear interpolation */
+ pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
+ (double)(pts_max - pts_min);
+ pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
+ if (pos <= pos_min)
+ pos = pos_min;
+ else if (pos >= pos_max)
+ pos = pos_max;
+ pts = get_dts(s, pos);
+ /* check if we are lucky */
+ if (pts == wanted_pts) {
+ goto found;
+ } else if (pts > wanted_pts) {
+ pos_max = pos - FFM_PACKET_SIZE;
+ } else {
+ pos_min = pos + FFM_PACKET_SIZE;
+ }
+ }
+ pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
+
+ found:
+ if (ffm_seek1(s, pos) < 0)
+ return -1;
+
+ /* reset read state */
+ ffm->read_state = READ_HEADER;
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->first_packet = 1;
+
+ return 0;
+}
+
+static int ffm_probe(AVProbeData *p)
+{
+ if (
+ p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
+ (p->buf[3] == '1' || p->buf[3] == '2'))
+ return AVPROBE_SCORE_MAX + 1;
+ return 0;
+}
+
+static const AVOption options[] = {
+ {"server_attached", NULL, offsetof(FFMContext, server_attached), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_EXPORT },
+ {"ffm_write_index", NULL, offsetof(FFMContext, write_index), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT },
+ {"ffm_file_size", NULL, offsetof(FFMContext, file_size), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT },
+ { NULL },
+};
+
+static const AVClass ffm_class = {
+ .class_name = "ffm demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+AVInputFormat ff_ffm_demuxer = {
+ .name = "ffm",
+ .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
+ .priv_data_size = sizeof(FFMContext),
+ .read_probe = ffm_probe,
+ .read_header = ffm_read_header,
+ .read_packet = ffm_read_packet,
+ .read_seek = ffm_seek,
+ .priv_class = &ffm_class,
+};
diff --cc libavformat/flvdec.c
index 3959a36,b82ea33..cdcfb9c
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@@ -477,20 -387,16 +477,20 @@@ static int amf_parse_object(AVFormatCon
num_val = avio_r8(ioc);
break;
case AMF_DATA_TYPE_STRING:
- if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0)
+ if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0) {
+ av_log(s, AV_LOG_ERROR, "AMF_DATA_TYPE_STRING parsing failed\n");
return -1;
+ }
break;
case AMF_DATA_TYPE_OBJECT:
- if ((vstream || astream) && key &&
+ if (key &&
- ioc->seekable &&
++ (ioc->seekable & AVIO_SEEKABLE_NORMAL) &&
!strcmp(KEYFRAMES_TAG, key) && depth == 1)
- if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
+ if (parse_keyframes_index(s, ioc,
max_pos) < 0)
- return -1;
-
+ av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
+ else
+ add_keyframes_index(s);
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,
@@@ -1032,27 -813,27 +1032,27 @@@ skip
}
}
if (i == s->nb_streams) {
- st = create_stream(s, is_audio ? AVMEDIA_TYPE_AUDIO
- : AVMEDIA_TYPE_VIDEO);
+ static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE};
+ st = create_stream(s, stream_types[stream_type]);
if (!st)
return AVERROR(ENOMEM);
+
}
- av_log(s, AV_LOG_TRACE, "%d %X %d \n", is_audio, flags, st->discard);
+ av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard);
- if (s->pb->seekable &&
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||
- is_audio)
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
+ ((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);
- if ((st->discard >= AVDISCARD_NONKEY &&
- !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || is_audio)) ||
- (st->discard >= AVDISCARD_BIDIR &&
- ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && !is_audio)) ||
- st->discard >= AVDISCARD_ALL) {
+ if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
+ ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO)))
+ || st->discard >= AVDISCARD_ALL
+ ) {
avio_seek(s->pb, next, SEEK_SET);
- continue;
+ ret = FFERROR_REDO;
+ goto leave;
}
- break;
- }
// if not streamed and no duration from metadata then seek to end to find
// the duration from the timestamps
diff --cc libavformat/gxfenc.c
index 79951b5,32714f6..0e0772b
--- a/libavformat/gxfenc.c
+++ b/libavformat/gxfenc.c
@@@ -706,11 -632,9 +706,11 @@@ static int gxf_write_header(AVFormatCon
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) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
- av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome");
+ av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome\n");
return -1;
}
diff --cc libavformat/icoenc.c
index a7ada19,0000000..e641f7b
mode 100644,000000..100644
--- a/libavformat/icoenc.c
+++ b/libavformat/icoenc.c
@@@ -1,203 -1,0 +1,203 @@@
+/*
+ * Microsoft Windows ICO muxer
+ * Copyright (c) 2012 Michael Bradshaw <mjbshaw gmail com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Microsoft Windows ICO muxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/pixdesc.h"
+#include "avformat.h"
+
+typedef struct {
+ int offset;
+ int size;
+ unsigned char width;
+ unsigned char height;
+ short bits;
+} IcoImage;
+
+typedef struct {
+ int current_image;
+ int nb_images;
+ IcoImage *images;
+} IcoMuxContext;
+
+static int ico_check_attributes(AVFormatContext *s, const AVCodecParameters *p)
+{
+ if (p->codec_id == AV_CODEC_ID_BMP) {
+ if (p->format == AV_PIX_FMT_PAL8 && AV_PIX_FMT_RGB32 != AV_PIX_FMT_BGRA) {
+ av_log(s, AV_LOG_ERROR, "Wrong endianness for bmp pixel format\n");
+ return AVERROR(EINVAL);
+ } else if (p->format != AV_PIX_FMT_PAL8 &&
+ p->format != AV_PIX_FMT_RGB555LE &&
+ p->format != AV_PIX_FMT_BGR24 &&
+ p->format != AV_PIX_FMT_BGRA) {
+ av_log(s, AV_LOG_ERROR, "BMP must be 1bit, 4bit, 8bit, 16bit, 24bit, or 32bit\n");
+ return AVERROR(EINVAL);
+ }
+ } else if (p->codec_id == AV_CODEC_ID_PNG) {
+ if (p->format != AV_PIX_FMT_RGBA) {
+ av_log(s, AV_LOG_ERROR, "PNG in ico requires pixel format to be rgba\n");
+ return AVERROR(EINVAL);
+ }
+ } else {
+ const AVCodecDescriptor *codesc = avcodec_descriptor_get(p->codec_id);
+ av_log(s, AV_LOG_ERROR, "Unsupported codec %s\n", codesc ? codesc->name : "");
+ return AVERROR(EINVAL);
+ }
+
+ if (p->width > 256 ||
+ p->height > 256) {
+ av_log(s, AV_LOG_ERROR, "Unsupported dimensions %dx%d (dimensions cannot exceed 256x256)\n", p->width, p->height);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int ico_write_header(AVFormatContext *s)
+{
+ IcoMuxContext *ico = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret;
+ int i;
+
- if (!pb->seekable) {
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+ av_log(s, AV_LOG_ERROR, "Output is not seekable\n");
+ return AVERROR(EINVAL);
+ }
+
+ ico->current_image = 0;
+ ico->nb_images = s->nb_streams;
+
+ avio_wl16(pb, 0); // reserved
+ avio_wl16(pb, 1); // 1 == icon
+ avio_skip(pb, 2); // skip the number of images
+
+ for (i = 0; i < s->nb_streams; i++) {
+ if (ret = ico_check_attributes(s, s->streams[i]->codecpar))
+ return ret;
+
+ // Fill in later when writing trailer...
+ avio_skip(pb, 16);
+ }
+
+ ico->images = av_mallocz_array(ico->nb_images, sizeof(IcoMuxContext));
+ if (!ico->images)
+ return AVERROR(ENOMEM);
+
+ avio_flush(pb);
+
+ return 0;
+}
+
+static int ico_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ IcoMuxContext *ico = s->priv_data;
+ IcoImage *image;
+ AVIOContext *pb = s->pb;
+ AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
+ int i;
+
+ if (ico->current_image >= ico->nb_images) {
+ av_log(s, AV_LOG_ERROR, "ICO already contains %d images\n", ico->current_image);
+ return AVERROR(EIO);
+ }
+
+ image = &ico->images[ico->current_image++];
+
+ image->offset = avio_tell(pb);
+ image->width = (par->width == 256) ? 0 : par->width;
+ image->height = (par->height == 256) ? 0 : par->height;
+
+ if (par->codec_id == AV_CODEC_ID_PNG) {
+ image->bits = par->bits_per_coded_sample;
+ image->size = pkt->size;
+
+ avio_write(pb, pkt->data, pkt->size);
+ } else { // BMP
+ if (AV_RL32(pkt->data + 14) != 40) { // must be BITMAPINFOHEADER
+ av_log(s, AV_LOG_ERROR, "Invalid BMP\n");
+ return AVERROR(EINVAL);
+ }
+
+ image->bits = AV_RL16(pkt->data + 28); // allows things like 1bit and 4bit images to be preserved
+ image->size = pkt->size - 14 + par->height * (par->width + 7) / 8;
+
+ avio_write(pb, pkt->data + 14, 8); // Skip the BITMAPFILEHEADER header
+ avio_wl32(pb, AV_RL32(pkt->data + 22) * 2); // rewrite height as 2 * height
+ avio_write(pb, pkt->data + 26, pkt->size - 26);
+
+ for (i = 0; i < par->height * (par->width + 7) / 8; ++i)
+ avio_w8(pb, 0x00); // Write bitmask (opaque)
+ }
+
+ return 0;
+}
+
+static int ico_write_trailer(AVFormatContext *s)
+{
+ IcoMuxContext *ico = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i;
+
+ avio_seek(pb, 4, SEEK_SET);
+
+ avio_wl16(pb, ico->current_image);
+
+ for (i = 0; i < ico->nb_images; i++) {
+ avio_w8(pb, ico->images[i].width);
+ avio_w8(pb, ico->images[i].height);
+
+ if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_BMP &&
+ s->streams[i]->codecpar->format == AV_PIX_FMT_PAL8) {
+ avio_w8(pb, (ico->images[i].bits >= 8) ? 0 : 1 << ico->images[i].bits);
+ } else {
+ avio_w8(pb, 0);
+ }
+
+ avio_w8(pb, 0); // reserved
+ avio_wl16(pb, 1); // color planes
+ avio_wl16(pb, ico->images[i].bits);
+ avio_wl32(pb, ico->images[i].size);
+ avio_wl32(pb, ico->images[i].offset);
+ }
+
+ av_freep(&ico->images);
+
+ return 0;
+}
+
+AVOutputFormat ff_ico_muxer = {
+ .name = "ico",
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
+ .priv_data_size = sizeof(IcoMuxContext),
+ .mime_type = "image/vnd.microsoft.icon",
+ .extensions = "ico",
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_BMP,
+ .write_header = ico_write_header,
+ .write_packet = ico_write_packet,
+ .write_trailer = ico_write_trailer,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
diff --cc libavformat/ivfenc.c
index f3ae4dc,1e57106..fdc0ee0
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@@ -62,26 -53,6 +62,26 @@@ static int ivf_write_packet(AVFormatCon
avio_wl32(pb, pkt->size);
avio_wl64(pb, pkt->pts);
avio_write(pb, pkt->data, pkt->size);
+ if (ctx->frame_cnt)
+ ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
+ ctx->frame_cnt++;
+ ctx->last_pts = pkt->pts;
+
+ return 0;
+}
+
+static int ivf_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ IVFEncContext *ctx = s->priv_data;
+
- if (pb->seekable && ctx->frame_cnt > 1) {
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && ctx->frame_cnt > 1) {
+ size_t end = avio_tell(pb);
+
+ avio_seek(pb, 24, SEEK_SET);
+ avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
+ avio_seek(pb, end, SEEK_SET);
+ }
return 0;
}
diff --cc libavformat/matroskadec.c
index bad034b,991f86b..2e3c9bf
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@@ -1616,7 -1393,9 +1616,7 @@@ static void matroska_execute_seekhead(M
int i;
// we should not do any seeking in the streaming case
- if (!matroska->ctx->pb->seekable)
- if (!(matroska->ctx->pb->seekable & AVIO_SEEKABLE_NORMAL) ||
- (matroska->ctx->flags & AVFMT_FLAG_IGNIDX))
++ if (!(matroska->ctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
return;
for (i = 0; i < seekhead_list->nb_elem; i++) {
diff --cc libavformat/matroskaenc.c
index df77313,cfced72..af941ce
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@@ -325,67 -264,11 +325,67 @@@ static void end_ebml_master(AVIOContex
avio_seek(pb, pos, SEEK_SET);
}
+static int start_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv,
+ ebml_master *master, unsigned int elementid, uint64_t expectedsize)
+{
+ int ret;
+
+ if ((ret = avio_open_dyn_buf(dyn_cp)) < 0)
+ return ret;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ *master = start_ebml_master(pb, elementid, expectedsize);
+ if (mkv->write_crc && mkv->mode != MODE_WEBM)
+ put_ebml_void(*dyn_cp, 6); /* Reserve space for CRC32 so position/size calculations using avio_tell() take it into account */
+ } else
+ *master = start_ebml_master(*dyn_cp, elementid, expectedsize);
+
+ return 0;
+}
+
+static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv,
+ ebml_master master)
+{
+ uint8_t *buf, crc[4];
+ int size, skip = 0;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ size = avio_close_dyn_buf(*dyn_cp, &buf);
+ if (mkv->write_crc && mkv->mode != MODE_WEBM) {
+ skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */
+ AV_WL32(crc, av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), UINT32_MAX, buf + skip, size - skip) ^ UINT32_MAX);
+ put_ebml_binary(pb, EBML_ID_CRC32, crc, sizeof(crc));
+ }
+ avio_write(pb, buf + skip, size - skip);
+ end_ebml_master(pb, master);
+ } else {
+ end_ebml_master(*dyn_cp, master);
+ size = avio_close_dyn_buf(*dyn_cp, &buf);
+ avio_write(pb, buf, size);
+ }
+ av_free(buf);
+ *dyn_cp = NULL;
+}
+
+/**
+* Complete ebml master whithout destroying the buffer, allowing for later updates
+*/
+static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv,
+ ebml_master master)
+{
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+
+ uint8_t *buf;
+ int size = avio_get_dyn_buf(*dyn_cp, &buf);
+
+ avio_write(pb, buf, size);
+ end_ebml_master(pb, 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);
}
@@@ -1418,12 -935,7 +1418,12 @@@ static int mkv_write_tracks(AVFormatCon
if (ret < 0)
return ret;
}
- end_ebml_master(pb, tracks);
+
- if (pb->seekable && !mkv->is_live)
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
+ end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
+ else
+ end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
+
return 0;
}
@@@ -1614,31 -1083,6 +1614,31 @@@ static int mkv_write_tags(AVFormatConte
if (ret < 0) return ret;
}
- if (s->pb->seekable && !mkv->is_live) {
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {
+ for (i = 0; i < s->nb_streams; i++) {
+ AVIOContext *pb;
+ AVStream *st = s->streams[i];
+ ebml_master tag_target;
+ ebml_master tag;
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
+ continue;
+
+ mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target);
+ pb = mkv->tags_bc;
+
+ tag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0);
+ put_ebml_string(pb, MATROSKA_ID_TAGNAME, "DURATION");
+ mkv->stream_duration_offsets[i] = avio_tell(pb);
+
+ // Reserve space to write duration as a 20-byte string.
+ // 2 (ebml id) + 1 (data size) + 20 (data)
+ put_ebml_void(pb, 23);
+ end_ebml_master(pb, tag);
+ end_ebml_master(pb, tag_target);
+ }
+ }
+
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *ch = s->chapters[i];
@@@ -1649,26 -1093,8 +1649,26 @@@
if (ret < 0) return ret;
}
- if (tags.pos)
- end_ebml_master(s->pb, tags);
+ if (mkv->have_attachments) {
+ for (i = 0; i < mkv->attachments->num_entries; i++) {
+ mkv_attachment *attachment = &mkv->attachments->entries[i];
+ AVStream *st = s->streams[attachment->stream_idx];
+
+ if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID))
+ continue;
+
+ ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid, &mkv->tags);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (mkv->tags.pos) {
- if (s->pb->seekable && !mkv->is_live)
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
+ end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, mkv->tags);
+ else
+ end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags);
+ }
return 0;
}
@@@ -1906,30 -1231,8 +1906,30 @@@ static int mkv_write_header(AVFormatCon
// reserve space for the duration
mkv->duration = 0;
mkv->duration_offset = avio_tell(pb);
- put_ebml_void(pb, 11); // assumes double-precision float to be written
- end_ebml_master(pb, segment_info);
+ if (!mkv->is_live) {
+ int64_t metadata_duration = get_metadata_duration(s);
+
+ if (s->duration > 0) {
+ int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE);
+ put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
+ av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration);
+ } else if (metadata_duration > 0) {
+ int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE);
+ put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
+ av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration);
+ } else {
+ put_ebml_void(pb, 11); // assumes double-precision float to be written
+ }
+ }
- if (s->pb->seekable && !mkv->is_live)
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
+ end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, mkv->info);
+ else
+ end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, mkv->info);
+ pb = s->pb;
+
+ // initialize stream_duration fields
+ mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t));
+ mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t));
ret = mkv_write_tracks(s);
if (ret < 0)
@@@ -1941,26 -1241,25 +1941,26 @@@
if (mkv->mode != MODE_WEBM) {
ret = mkv_write_chapters(s);
if (ret < 0)
- return ret;
+ goto fail;
- ret = mkv_write_tags(s);
+ ret = mkv_write_attachments(s);
if (ret < 0)
- return ret;
+ goto fail;
- ret = mkv_write_attachments(s);
+ ret = mkv_write_tags(s);
if (ret < 0)
- return ret;
+ goto fail;
}
- if (!s->pb->seekable && !mkv->is_live)
- if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
- mkv_write_seekhead(pb, mkv->main_seekhead);
++ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live)
+ mkv_write_seekhead(pb, mkv);
mkv->cues = mkv_start_cues(mkv->segment_offset);
- if (!mkv->cues)
- return AVERROR(ENOMEM);
-
+ if (!mkv->cues) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
- if (pb->seekable && mkv->reserve_cues_space) {
+ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mkv->reserve_cues_space) {
mkv->cues_pos = avio_tell(pb);
put_ebml_void(pb, mkv->reserve_cues_space);
}
@@@ -2128,135 -1473,65 +2128,135 @@@ static void mkv_write_block(AVFormatCon
avio_write(pb, data + offset, size);
if (data != pkt->data)
av_free(data);
-}
-static int srt_get_duration(uint8_t **buf)
-{
- int i, duration = 0;
-
- for (i = 0; i < 2 && !duration; i++) {
- int s_hour, s_min, s_sec, s_hsec, e_hour, e_min, e_sec, e_hsec;
- if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d",
- &s_hour, &s_min, &s_sec, &s_hsec,
- &e_hour, &e_min, &e_sec, &e_hsec) == 8) {
- s_min += 60 * s_hour;
- e_min += 60 * e_hour;
- s_sec += 60 * s_min;
-
- e_sec += 60 * e_min;
- s_hsec += 1000 * s_sec;
- e_hsec += 1000 * e_sec;
-
- duration = e_hsec - s_hsec;
- }
- *buf += strcspn(*buf, "\n") + 1;
+ if (blockid == MATROSKA_ID_BLOCK && !keyframe) {
+ put_ebml_sint(pb, MATROSKA_ID_BLOCKREFERENCE,
+ mkv->last_track_timestamp[track_number - 1]);
+ }
+ mkv->last_track_timestamp[track_number - 1] = ts - mkv->cluster_pts;
+
+ 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);
}
- return duration;
}
-static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb,
- AVPacket *pkt)
+static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
{
+ MatroskaMuxContext *mkv = s->priv_data;
ebml_master blockgroup;
- AVPacket pkt2 = *pkt;
- int64_t duration = srt_get_duration(&pkt2.data);
- pkt2.size -= pkt2.data - pkt->data;
-
- blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
- mkv_blockgroup_size(pkt2.size));
- mkv_write_block(s, pb, MATROSKA_ID_BLOCK, &pkt2, 0);
- put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
+ 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 %" PRId64 ", 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 duration;
+ return pkt->duration;
}
-static void mkv_flush_dynbuf(AVFormatContext *s)
+static void mkv_start_new_cluster(AVFormatContext *s, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
- int bufsize;
- uint8_t *dyn_buf;
- if (!mkv->dyn_bc)
- return;
+ end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster);
+ mkv->cluster_pos = -1;
- if (s->pb->seekable)
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+ av_log(s, AV_LOG_DEBUG,
+ "Starting new cluster at offset %" PRIu64 " bytes, "
+ "pts %" PRIu64 "dts %" PRIu64 "\n",
+ avio_tell(s->pb), pkt->pts, pkt->dts);
+ else
+ av_log(s, AV_LOG_DEBUG, "Starting new cluster, "
+ "pts %" PRIu64 "dts %" PRIu64 "\n",
+ pkt->pts, pkt->dts);
+ avio_flush(s->pb);
+}
- bufsize = avio_close_dyn_buf(mkv->dyn_bc, &dyn_buf);
- avio_write(s->pb, dyn_buf, bufsize);
- av_free(dyn_buf);
- mkv->dyn_bc = NULL;
+static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ mkv_track *track = &mkv->tracks[pkt->stream_index];
+ AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
+ uint8_t *side_data;
+ int side_data_size = 0, ret;
+
+ side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+ &side_data_size);
+
+ switch (par->codec_id) {
+ case AV_CODEC_ID_FLAC:
- if (side_data_size && s->pb->seekable) {
++ if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+ AVCodecParameters *codecpriv_par;
+ int64_t curpos;
+ if (side_data_size != par->extradata_size) {
+ av_log(s, AV_LOG_ERROR, "Invalid FLAC STREAMINFO metadata for output stream %d\n",
+ pkt->stream_index);
+ return AVERROR(EINVAL);
+ }
+ codecpriv_par = avcodec_parameters_alloc();
+ if (!codecpriv_par)
+ return AVERROR(ENOMEM);
+ ret = avcodec_parameters_copy(codecpriv_par, par);
+ if (ret < 0) {
+ avcodec_parameters_free(&codecpriv_par);
+ return ret;
+ }
+ memcpy(codecpriv_par->extradata, side_data, side_data_size);
+ curpos = avio_tell(mkv->tracks_bc);
+ avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET);
+ mkv_write_codecprivate(s, mkv->tracks_bc, codecpriv_par, 1, 0);
+ avio_seek(mkv->tracks_bc, curpos, SEEK_SET);
+ avcodec_parameters_free(&codecpriv_par);
+ }
+ break;
+ default:
+ if (side_data_size)
+ av_log(s, AV_LOG_DEBUG, "Ignoring new extradata in a packet for stream %d.\n", pkt->stream_index);
+ break;
+ }
+
+ return 0;
}
-static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_cue)
{
MatroskaMuxContext *mkv = s->priv_data;
AVIOContext *pb = s->pb;
@@@ -2274,59 -1547,48 +2274,59 @@@
}
ts += mkv->tracks[pkt->stream_index].ts_offset;
- if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
- if (!mkv->dyn_bc) {
- ret = avio_open_dyn_buf(&mkv->dyn_bc);
- if (ret < 0)
- return ret;
+ if (mkv->cluster_pos != -1) {
+ int64_t cluster_time = ts - mkv->cluster_pts + mkv->tracks[pkt->stream_index].ts_offset;
+ if ((int16_t)cluster_time != cluster_time) {
+ av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n");
+ mkv_start_new_cluster(s, pkt);
}
- pb = mkv->dyn_bc;
}
- if (!mkv->cluster_pos) {
+ if (mkv->cluster_pos == -1) {
mkv->cluster_pos = avio_tell(s->pb);
- mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0);
- put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts));
+ ret = start_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, &mkv->cluster, MATROSKA_ID_CLUSTER, 0);
+ if (ret < 0)
+ return ret;
+ put_ebml_uint(mkv->dyn_bc, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts));
mkv->cluster_pts = FFMAX(0, ts);
}
+ pb = mkv->dyn_bc;
+
+ relative_packet_pos = avio_tell(pb);
if (par->codec_type != AVMEDIA_TYPE_SUBTITLE) {
- mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7);
- } else if (par->codec_id == AV_CODEC_ID_SSA) {
- duration = mkv_write_ass_blocks(s, pb, pkt);
- } else if (par->codec_id == AV_CODEC_ID_SRT) {
- duration = mkv_write_srt_blocks(s, pb, pkt);
+ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
- if (s->pb->seekable && (par->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue)) {
++ if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && (par->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue)) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, mkv->cluster_pos, relative_packet_pos, -1);
+ if (ret < 0) return ret;
+ }
} else {
- ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
- mkv_blockgroup_size(pkt->size));
- duration = pkt->duration;
+ if (par->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));
+
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
- if (pkt->convergence_duration)
- duration = pkt->convergence_duration;
+ /* For backward compatibility, prefer convergence_duration. */
+ if (pkt->convergence_duration > 0) {
+ duration = pkt->convergence_duration;
+ }
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 0);
- put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
- end_ebml_master(pb, blockgroup);
- }
+ /* All subtitle blocks are considered to be keyframes. */
+ mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 1);
+ put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
+ end_ebml_master(pb, blockgroup);
+ }
- if (s->pb->seekable) {
- if (par->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) {
- ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts,
- mkv->cluster_pos);
- if (ret < 0)
- return ret;
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts,
+ mkv->cluster_pos, relative_packet_pos, duration);
+ if (ret < 0)
+ return ret;
+ }
}
mkv->duration = FFMAX(mkv->duration, ts + duration);
@@@ -2416,17 -1665,20 +2416,17 @@@ static int mkv_write_packet(AVFormatCon
static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
- AVIOContext *pb;
- if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
- pb = s->pb;
- else
- pb = mkv->dyn_bc;
+
if (!pkt) {
- if (mkv->cluster_pos) {
- 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 = 0;
- if (mkv->dyn_bc)
- mkv_flush_dynbuf(s);
+ if (mkv->cluster_pos != -1) {
+ end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster);
+ mkv->cluster_pos = -1;
- if (s->pb->seekable)
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+ av_log(s, AV_LOG_DEBUG,
+ "Flushing cluster at offset %" PRIu64 " bytes\n",
+ avio_tell(s->pb));
+ else
+ av_log(s, AV_LOG_DEBUG, "Flushing cluster\n");
avio_flush(s->pb);
}
return 1;
@@@ -2462,7 -1717,7 +2462,7 @@@ static int mkv_write_trailer(AVFormatCo
return ret;
}
- if (pb->seekable && !mkv->is_live) {
- if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
++ if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) {
if (mkv->cues->num_entries) {
if (mkv->reserve_cues_space) {
int64_t cues_end;
diff --cc libavformat/mlvdec.c
index 665b28d,0000000..90c3779
mode 100644,000000..100644
--- a/libavformat/mlvdec.c
+++ b/libavformat/mlvdec.c
@@@ -1,478 -1,0 +1,478 @@@
+/*
+ * Magic Lantern Video (MLV) demuxer
+ * Copyright (c) 2014 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Magic Lantern Video (MLV) demuxer
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/rational.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "riff.h"
+
+#define MLV_VERSION "v2.0"
+
+#define MLV_VIDEO_CLASS_RAW 1
+#define MLV_VIDEO_CLASS_YUV 2
+#define MLV_VIDEO_CLASS_JPEG 3
+#define MLV_VIDEO_CLASS_H264 4
+
+#define MLV_AUDIO_CLASS_WAV 1
+
+#define MLV_CLASS_FLAG_DELTA 0x40
+#define MLV_CLASS_FLAG_LZMA 0x80
+
+typedef struct {
+ AVIOContext *pb[101];
+ int class[2];
+ int stream_index;
+ uint64_t pts;
+} MlvContext;
+
+static int probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) == MKTAG('M','L','V','I') &&
+ AV_RL32(p->buf + 4) >= 52 &&
+ !memcmp(p->buf + 8, MLV_VERSION, 5))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int check_file_header(AVIOContext *pb, uint64_t guid)
+{
+ unsigned int size;
+ uint8_t version[8];
+
+ avio_skip(pb, 4);
+ size = avio_rl32(pb);
+ if (size < 52)
+ return AVERROR_INVALIDDATA;
+ avio_read(pb, version, 8);
+ if (memcmp(version, MLV_VERSION, 5) || avio_rl64(pb) != guid)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, size - 24);
+ return 0;
+}
+
+static void read_string(AVFormatContext *avctx, AVIOContext *pb, const char *tag, int size)
+{
+ char * value = av_malloc(size + 1);
+ if (!value) {
+ avio_skip(pb, size);
+ return;
+ }
+
+ avio_read(pb, value, size);
+ if (!value[0]) {
+ av_free(value);
+ return;
+ }
+
+ value[size] = 0;
+ av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
+}
+
+static void read_uint8(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_r8(pb), 0);
+}
+
+static void read_uint16(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl16(pb), 0);
+}
+
+static void read_uint32(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl32(pb), 0);
+}
+
+static void read_uint64(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl64(pb), 0);
+}
+
+static int scan_file(AVFormatContext *avctx, AVStream *vst, AVStream *ast, int file)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb = mlv->pb[file];
+ int ret;
+ while (!avio_feof(pb)) {
+ int type;
+ unsigned int size;
+ type = avio_rl32(pb);
+ size = avio_rl32(pb);
+ avio_skip(pb, 8); //timestamp
+ if (size < 16)
+ break;
+ size -= 16;
+ if (vst && type == MKTAG('R','A','W','I') && size >= 164) {
+ vst->codecpar->width = avio_rl16(pb);
+ vst->codecpar->height = avio_rl16(pb);
+ ret = av_image_check_size(vst->codecpar->width, vst->codecpar->height, 0, avctx);
+ if (ret < 0)
+ return ret;
+ if (avio_rl32(pb) != 1)
+ avpriv_request_sample(avctx, "raw api version");
+ avio_skip(pb, 20); // pointer, width, height, pitch, frame_size
+ vst->codecpar->bits_per_coded_sample = avio_rl32(pb);
+ if (vst->codecpar->bits_per_coded_sample < 0 ||
+ vst->codecpar->bits_per_coded_sample > (INT_MAX - 7) / (vst->codecpar->width * vst->codecpar->height)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "invalid bits_per_coded_sample %d (size: %dx%d)\n",
+ vst->codecpar->bits_per_coded_sample,
+ vst->codecpar->width, vst->codecpar->height);
+ return AVERROR_INVALIDDATA;
+ }
+ avio_skip(pb, 8 + 16 + 24); // black_level, white_level, xywh, active_area, exposure_bias
+ if (avio_rl32(pb) != 0x2010100) /* RGGB */
+ avpriv_request_sample(avctx, "cfa_pattern");
+ avio_skip(pb, 80); // calibration_illuminant1, color_matrix1, dynamic_range
+ vst->codecpar->format = AV_PIX_FMT_BAYER_RGGB16LE;
+ vst->codecpar->codec_tag = MKTAG('B', 'I', 'T', 16);
+ size -= 164;
+ } else if (ast && type == MKTAG('W', 'A', 'V', 'I') && size >= 16) {
+ ret = ff_get_wav_header(avctx, pb, ast->codecpar, 16, 0);
+ if (ret < 0)
+ return ret;
+ size -= 16;
+ } else if (type == MKTAG('I','N','F','O')) {
+ if (size > 0)
+ read_string(avctx, pb, "info", size);
+ continue;
+ } else if (type == MKTAG('I','D','N','T') && size >= 36) {
+ read_string(avctx, pb, "cameraName", 32);
+ read_uint32(avctx, pb, "cameraModel", "0x%"PRIx32);
+ size -= 36;
+ if (size >= 32) {
+ read_string(avctx, pb, "cameraSerial", 32);
+ size -= 32;
+ }
+ } else if (type == MKTAG('L','E','N','S') && size >= 48) {
+ read_uint16(avctx, pb, "focalLength", "%i");
+ read_uint16(avctx, pb, "focalDist", "%i");
+ read_uint16(avctx, pb, "aperture", "%i");
+ read_uint8(avctx, pb, "stabilizerMode", "%i");
+ read_uint8(avctx, pb, "autofocusMode", "%i");
+ read_uint32(avctx, pb, "flags", "0x%"PRIx32);
+ read_uint32(avctx, pb, "lensID", "%"PRIi32);
+ read_string(avctx, pb, "lensName", 32);
+ size -= 48;
+ if (size >= 32) {
+ read_string(avctx, pb, "lensSerial", 32);
+ size -= 32;
+ }
+ } else if (vst && type == MKTAG('V', 'I', 'D', 'F') && size >= 4) {
+ uint64_t pts = avio_rl32(pb);
+ ff_add_index_entry(&vst->index_entries, &vst->nb_index_entries, &vst->index_entries_allocated_size,
+ avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME);
+ size -= 4;
+ } else if (ast && type == MKTAG('A', 'U', 'D', 'F') && size >= 4) {
+ uint64_t pts = avio_rl32(pb);
+ ff_add_index_entry(&ast->index_entries, &ast->nb_index_entries, &ast->index_entries_allocated_size,
+ avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME);
+ size -= 4;
+ } else if (vst && type == MKTAG('W','B','A','L') && size >= 28) {
+ read_uint32(avctx, pb, "wb_mode", "%"PRIi32);
+ read_uint32(avctx, pb, "kelvin", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_r", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_g", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_b", "%"PRIi32);
+ read_uint32(avctx, pb, "wbs_gm", "%"PRIi32);
+ read_uint32(avctx, pb, "wbs_ba", "%"PRIi32);
+ size -= 28;
+ } else if (type == MKTAG('R','T','C','I') && size >= 20) {
+ char str[32];
+ struct tm time = { 0 };
+ time.tm_sec = avio_rl16(pb);
+ time.tm_min = avio_rl16(pb);
+ time.tm_hour = avio_rl16(pb);
+ time.tm_mday = avio_rl16(pb);
+ time.tm_mon = avio_rl16(pb);
+ time.tm_year = avio_rl16(pb);
+ time.tm_wday = avio_rl16(pb);
+ time.tm_yday = avio_rl16(pb);
+ time.tm_isdst = avio_rl16(pb);
+ avio_skip(pb, 2);
+ if (strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time))
+ av_dict_set(&avctx->metadata, "time", str, 0);
+ size -= 20;
+ } else if (type == MKTAG('E','X','P','O') && size >= 16) {
+ av_dict_set(&avctx->metadata, "isoMode", avio_rl32(pb) ? "auto" : "manual", 0);
+ read_uint32(avctx, pb, "isoValue", "%"PRIi32);
+ read_uint32(avctx, pb, "isoAnalog", "%"PRIi32);
+ read_uint32(avctx, pb, "digitalGain", "%"PRIi32);
+ size -= 16;
+ if (size >= 8) {
+ read_uint64(avctx, pb, "shutterValue", "%"PRIi64);
+ size -= 8;
+ }
+ } else if (type == MKTAG('S','T','Y','L') && size >= 36) {
+ read_uint32(avctx, pb, "picStyleId", "%"PRIi32);
+ read_uint32(avctx, pb, "contrast", "%"PRIi32);
+ read_uint32(avctx, pb, "sharpness", "%"PRIi32);
+ read_uint32(avctx, pb, "saturation", "%"PRIi32);
+ read_uint32(avctx, pb, "colortone", "%"PRIi32);
+ read_string(avctx, pb, "picStyleName", 16);
+ size -= 36;
+ } else if (type == MKTAG('M','A','R','K')) {
+ } else if (type == MKTAG('N','U','L','L')) {
+ } else if (type == MKTAG('M','L','V','I')) { /* occurs when MLV and Mnn files are concatenated */
+ } else {
+ av_log(avctx, AV_LOG_INFO, "unsupported tag %c%c%c%c, size %u\n", type&0xFF, (type>>8)&0xFF, (type>>16)&0xFF, (type>>24)&0xFF, size);
+ }
+ avio_skip(pb, size);
+ }
+ return 0;
+}
+
+static int read_header(AVFormatContext *avctx)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb = avctx->pb;
+ AVStream *vst = NULL, *ast = NULL;
+ int size, ret;
+ unsigned nb_video_frames, nb_audio_frames;
+ uint64_t guid;
+ char guidstr[32];
+
+ avio_skip(pb, 4);
+ size = avio_rl32(pb);
+ if (size < 52)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(pb, 8);
+
+ guid = avio_rl64(pb);
+ snprintf(guidstr, sizeof(guidstr), "0x%"PRIx64, guid);
+ av_dict_set(&avctx->metadata, "guid", guidstr, 0);
+
+ avio_skip(pb, 8); //fileNum, fileCount, fileFlags
+
+ mlv->class[0] = avio_rl16(pb);
+ mlv->class[1] = avio_rl16(pb);
+
+ nb_video_frames = avio_rl32(pb);
+ nb_audio_frames = avio_rl32(pb);
+
+ if (nb_video_frames && mlv->class[0]) {
+ vst = avformat_new_stream(avctx, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ vst->id = 0;
+ vst->nb_frames = nb_video_frames;
+ if ((mlv->class[0] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA)))
+ avpriv_request_sample(avctx, "compression");
+ vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ switch (mlv->class[0] & ~(MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA)) {
+ case MLV_VIDEO_CLASS_RAW:
+ vst->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ break;
+ case MLV_VIDEO_CLASS_YUV:
+ vst->codecpar->format = AV_PIX_FMT_YUV420P;
+ vst->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ vst->codecpar->codec_tag = 0;
+ break;
+ case MLV_VIDEO_CLASS_JPEG:
+ vst->codecpar->codec_id = AV_CODEC_ID_MJPEG;
+ vst->codecpar->codec_tag = 0;
+ break;
+ case MLV_VIDEO_CLASS_H264:
+ vst->codecpar->codec_id = AV_CODEC_ID_H264;
+ vst->codecpar->codec_tag = 0;
+ break;
+ default:
+ avpriv_request_sample(avctx, "unknown video class");
+ }
+ }
+
+ if (nb_audio_frames && mlv->class[1]) {
+ ast = avformat_new_stream(avctx, NULL);
+ if (!ast)
+ return AVERROR(ENOMEM);
+ ast->id = 1;
+ ast->nb_frames = nb_audio_frames;
+ if ((mlv->class[1] & MLV_CLASS_FLAG_LZMA))
+ avpriv_request_sample(avctx, "compression");
+ if ((mlv->class[1] & ~MLV_CLASS_FLAG_LZMA) != MLV_AUDIO_CLASS_WAV)
+ avpriv_request_sample(avctx, "unknown audio class");
+
+ ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ avpriv_set_pts_info(ast, 33, 1, ast->codecpar->sample_rate);
+ }
+
+ if (vst) {
+ AVRational framerate;
+ framerate.num = avio_rl32(pb);
+ framerate.den = avio_rl32(pb);
+ avpriv_set_pts_info(vst, 64, framerate.den, framerate.num);
+ } else
+ avio_skip(pb, 8);
+
+ avio_skip(pb, size - 52);
+
+ /* scan primary file */
+ mlv->pb[100] = avctx->pb;
+ ret = scan_file(avctx, vst, ast, 100);
+ if (ret < 0)
+ return ret;
+
+ /* scan secondary files */
+ if (strlen(avctx->filename) > 2) {
+ int i;
+ char *filename = av_strdup(avctx->filename);
+
+ if (!filename)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < 100; i++) {
+ snprintf(filename + strlen(filename) - 2, 3, "%02d", i);
+ if (avctx->io_open(avctx, &mlv->pb[i], filename, AVIO_FLAG_READ, NULL) < 0)
+ break;
+ if (check_file_header(mlv->pb[i], guid) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ignoring %s; bad format or guid mismatch\n", filename);
+ ff_format_io_close(avctx, &mlv->pb[i]);
+ continue;
+ }
+ av_log(avctx, AV_LOG_INFO, "scanning %s\n", filename);
+ ret = scan_file(avctx, vst, ast, i);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ignoring %s; %s\n", filename, av_err2str(ret));
+ ff_format_io_close(avctx, &mlv->pb[i]);
+ continue;
+ }
+ }
+ av_free(filename);
+ }
+
+ if (vst)
+ vst->duration = vst->nb_index_entries;
+ if (ast)
+ ast->duration = ast->nb_index_entries;
+
+ if ((vst && !vst->nb_index_entries) || (ast && !ast->nb_index_entries)) {
+ av_log(avctx, AV_LOG_ERROR, "no index entries found\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (vst && ast)
+ avio_seek(pb, FFMIN(vst->index_entries[0].pos, ast->index_entries[0].pos), SEEK_SET);
+ else if (vst)
+ avio_seek(pb, vst->index_entries[0].pos, SEEK_SET);
+ else if (ast)
+ avio_seek(pb, ast->index_entries[0].pos, SEEK_SET);
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb;
+ AVStream *st = avctx->streams[mlv->stream_index];
+ int index, ret;
+ unsigned int size, space;
+
+ if (mlv->pts >= st->duration)
+ return AVERROR_EOF;
+
+ index = av_index_search_timestamp(st, mlv->pts, AVSEEK_FLAG_ANY);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_ERROR, "could not find index entry for frame %"PRId64"\n", mlv->pts);
+ return AVERROR(EIO);
+ }
+
+ pb = mlv->pb[st->index_entries[index].size];
+ avio_seek(pb, st->index_entries[index].pos, SEEK_SET);
+
+ avio_skip(pb, 4); // blockType
+ size = avio_rl32(pb);
+ if (size < 16)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 12); //timestamp, frameNumber
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
+ avio_skip(pb, 8); // cropPosX, cropPosY, panPosX, panPosY
+ space = avio_rl32(pb);
+ avio_skip(pb, space);
+
+ if ((mlv->class[st->id] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA))) {
+ ret = AVERROR_PATCHWELCOME;
+ } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = av_get_packet(pb, pkt, (st->codecpar->width * st->codecpar->height * st->codecpar->bits_per_coded_sample + 7) >> 3);
+ } else { // AVMEDIA_TYPE_AUDIO
+ if (space > UINT_MAX - 24 || size < (24 + space))
+ return AVERROR_INVALIDDATA;
+ ret = av_get_packet(pb, pkt, size - (24 + space));
+ }
+
+ if (ret < 0)
+ return ret;
+
+ pkt->stream_index = mlv->stream_index;
+ pkt->pts = mlv->pts;
+
+ mlv->stream_index++;
+ if (mlv->stream_index == avctx->nb_streams) {
+ mlv->stream_index = 0;
+ mlv->pts++;
+ }
+ return 0;
+}
+
+static int read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
+{
+ MlvContext *mlv = avctx->priv_data;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
- if (!avctx->pb->seekable)
++ if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
+ return AVERROR(EIO);
+
+ mlv->pts = timestamp;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ MlvContext *mlv = s->priv_data;
+ int i;
+ for (i = 0; i < 100; i++)
+ if (mlv->pb[i])
+ ff_format_io_close(s, &mlv->pb[i]);
+ return 0;
+}
+
+AVInputFormat ff_mlv_demuxer = {
+ .name = "mlv",
+ .long_name = NULL_IF_CONFIG_SMALL("Magic Lantern Video (MLV)"),
+ .priv_data_size = sizeof(MlvContext),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_close = read_close,
+ .read_seek = read_seek,
+};
diff --cc libavformat/mov.c
index f7dd250,36e75d5..3754346
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@@ -1164,21 -885,6 +1164,21 @@@ static int mov_read_moov(MOVContext *c
static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
+ if (!c->has_looked_for_mfra && c->use_mfra_for > 0) {
+ c->has_looked_for_mfra = 1;
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ int ret;
+ av_log(c->fc, AV_LOG_VERBOSE, "stream has moof boxes, will look "
+ "for a mfra\n");
+ if ((ret = mov_read_mfra(c, pb)) < 0) {
+ av_log(c->fc, AV_LOG_VERBOSE, "found a moof box but failed to "
+ "read the mfra (may be a live ismv)\n");
+ }
+ } else {
+ av_log(c->fc, AV_LOG_VERBOSE, "found a moof box but stream is not "
+ "seekable, can not look for mfra\n");
+ }
+ }
c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8;
av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset);
return mov_read_default(c, pb, atom);
@@@ -5416,16 -3267,13 +5416,16 @@@ static int mov_read_default(MOVContext
int64_t start_pos = avio_tell(pb);
int64_t left;
int err = parse(c, pb, a);
- if (err < 0)
+ if (err < 0) {
+ c->atom_depth --;
return err;
+ }
if (c->found_moov && c->found_mdat &&
- ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) ||
- ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX) ||
++ ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) ||
start_pos + a.size == avio_size(pb))) {
- if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete)
- if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX)
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete)
c->next_root_atom = start_pos + a.size;
+ c->atom_depth --;
return 0;
}
left = a.size - avio_tell(pb) + start_pos;
@@@ -5926,16 -3461,9 +5926,16 @@@ static int mov_read_header(AVFormatCont
MOVAtom atom = { AV_RL32("root") };
int i;
+ if (mov->decryption_key_len != 0 && mov->decryption_key_len != AES_CTR_KEY_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid decryption key len %d expected %d\n",
+ mov->decryption_key_len, AES_CTR_KEY_SIZE);
+ return AVERROR(EINVAL);
+ }
+
mov->fc = s;
+ mov->trak_index = -1;
/* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
- if (pb->seekable)
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
atom.size = avio_size(pb);
else
atom.size = INT64_MAX;
@@@ -5949,7 -3474,6 +5949,7 @@@
mov_read_close(s);
return err;
}
- } while (pb->seekable && !mov->found_moov && !mov->moov_retry++);
++ } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++);
if (!mov->found_moov) {
av_log(s, AV_LOG_ERROR, "moov atom not found\n");
mov_read_close(s);
@@@ -5957,18 -3481,9 +5957,18 @@@
}
av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
- if (pb->seekable) {
- if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mov->chapter_track > 0)
- mov_read_chapters(s);
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ if (mov->nb_chapter_tracks > 0 && !mov->ignore_chapters)
+ mov_read_chapters(s);
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->codecpar->codec_tag == AV_RL32("tmcd")) {
+ mov_read_timecode_track(s, s->streams[i]);
+ } else if (s->streams[i]->codecpar->codec_tag == AV_RL32("rtmd")) {
+ mov_read_rtmd_track(s, s->streams[i]);
+ }
+ }
+ /* copy timecode metadata from tmcd tracks to the related video streams */
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MOVStreamContext *sc = st->priv_data;
diff --cc libavformat/mp3dec.c
index b45a066,e282218..0924a57
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@@ -370,9 -332,6 +370,9 @@@ static int mp3_read_header(AVFormatCont
if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
ff_id3v1_read(s);
- if(s->pb->seekable)
++ if(s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+ mp3->filesize = avio_size(s->pb);
+
if (mp3_parse_vbr_tags(s, st, off) < 0)
avio_seek(s->pb, off, SEEK_SET);
diff --cc libavformat/mp3enc.c
index 49f3742,d87d7be..0348622
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@@ -142,10 -139,10 +142,10 @@@ static int mp3_write_xing(AVFormatConte
int best_bitrate_error = INT_MAX;
int ret;
int ver = 0;
- int lsf, bytes_needed;
+ int bytes_needed;
- if (!s->pb->seekable || !mp3->write_xing)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) || !mp3->write_xing)
- return;
+ return 0;
for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) {
const uint16_t base_freq = avpriv_mpa_freq_tab[i];
diff --cc libavformat/mpc8.c
index 05d0c1a,bd17c19..180c554
--- a/libavformat/mpc8.c
+++ b/libavformat/mpc8.c
@@@ -261,10 -251,8 +261,10 @@@ static int mpc8_read_header(AVFormatCon
st->start_time = 0;
st->duration = c->samples / (1152 << (st->codecpar->extradata[1]&3)*2);
size -= avio_tell(pb) - pos;
+ if (size > 0)
+ avio_skip(pb, size);
- if (pb->seekable) {
+ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
int64_t pos = avio_tell(s->pb);
c->apetag_start = ff_ape_parse_tag(s);
avio_seek(s->pb, pos, SEEK_SET);
diff --cc libavformat/mpegts.c
index 590abb0,28b6d37..3eff152
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@@ -2599,15 -2062,6 +2599,15 @@@ static int parse_pcr(int64_t *ppcr_high
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");
++ av_log(s, (pb->seekable & AVIO_SEEKABLE_NORMAL) ? 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;
diff --cc libavformat/mxfdec.c
index 2ad0c28,1c7c280..f8d0f9e
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@@ -2590,8 -1933,8 +2590,8 @@@ static int mxf_parse_handle_essence(MXF
/* 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) {
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
- av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
+ av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing FooterPartition\n");
return -1;
}
@@@ -2774,10 -2077,10 +2774,10 @@@ static void mxf_read_random_index_pack(
{
MXFContext *mxf = s->priv_data;
uint32_t length;
- int64_t file_size;
+ int64_t file_size, max_rip_length, min_rip_length;
KLVPacket klv;
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return;
file_size = avio_size(s->pb);
diff --cc libavformat/mxfenc.c
index afea117,eb53dbf..12fc9ab
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@@ -2549,18 -1805,11 +2549,18 @@@ static int mxf_write_footer(AVFormatCon
mxf_write_klv_fill(s);
mxf_write_random_index_pack(s);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ if (s->oformat == &ff_mxf_opatom_muxer){
+ /* rewrite body partition to update lengths */
+ avio_seek(pb, mxf->body_partition_offset[0], SEEK_SET);
+ if ((err = mxf_write_opatom_body_partition(s)) < 0)
+ goto end;
+ }
+
avio_seek(pb, 0, SEEK_SET);
- if (mxf->edit_unit_byte_count) {
+ if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) {
if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
- return err;
+ goto end;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
} else {
diff --cc libavformat/oggdec.c
index edeae2b,5965a97..97ad1a2
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@@ -197,87 -153,23 +197,87 @@@ static const struct ogg_codec *ogg_find
return NULL;
}
-static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
+/**
+ * Replace the current stream with a new one. This is a typical webradio
+ * situation where a new audio stream spawn (identified with a new serial) and
+ * must replace the previous one (track switch).
+ */
+static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
{
struct ogg *ogg = s->priv_data;
- int idx = ogg->nstreams++;
- AVStream *st;
struct ogg_stream *os;
+ const struct ogg_codec *codec;
+ int i = 0;
+
- if (s->pb->seekable) {
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ uint8_t magic[8];
+ int64_t pos = avio_tell(s->pb);
+ avio_skip(s->pb, nsegs);
+ avio_read(s->pb, magic, sizeof(magic));
+ avio_seek(s->pb, pos, SEEK_SET);
+ codec = ogg_find_codec(magic, sizeof(magic));
+ if (!codec) {
+ av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < ogg->nstreams; i++) {
+ if (ogg->streams[i].codec == codec)
+ break;
+ }
+ if (i >= ogg->nstreams)
+ return ogg_new_stream(s, serial);
+ } else if (ogg->nstreams != 1) {
+ avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
+ return AVERROR_PATCHWELCOME;
+ }
- os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
+ os = &ogg->streams[i];
- if (!os)
- return AVERROR(ENOMEM);
+ os->serial = serial;
+ return i;
- ogg->streams = os;
+#if 0
+ buf = os->buf;
+ bufsize = os->bufsize;
+ codec = os->codec;
+
+ if (!ogg->state || ogg->state->streams[i].private != os->private)
+ av_freep(&ogg->streams[i].private);
+
+ /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
+ * also re-use the ogg_stream allocated buffer */
+ memset(os, 0, sizeof(*os));
+ os->serial = serial;
+ os->bufsize = bufsize;
+ os->buf = buf;
+ os->header = -1;
+ os->codec = codec;
+
+ return i;
+#endif
+}
+
+static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
+{
+ struct ogg *ogg = s->priv_data;
+ int idx = ogg->nstreams;
+ AVStream *st;
+ struct ogg_stream *os;
+ size_t size;
- memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
+ if (ogg->state) {
+ av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
+ "in between Ogg context save/restore operations.\n");
+ return AVERROR_BUG;
+ }
- os = ogg->streams + idx;
+ /* Allocate and init a new Ogg Stream */
+ if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
+ !(os = av_realloc(ogg->streams, size)))
+ return AVERROR(ENOMEM);
+ ogg->streams = os;
+ os = ogg->streams + idx;
+ memset(os, 0, sizeof(*os));
os->serial = serial;
os->bufsize = DECODER_BUFFER_SIZE;
os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
@@@ -355,15 -234,9 +355,15 @@@ static int ogg_read_page(AVFormatContex
sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
break;
- if(!i && bc->seekable && ogg->page_pos > 0) {
++ if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
+ memset(sync, 0, 4);
+ avio_seek(bc, ogg->page_pos+4, SEEK_SET);
+ ogg->page_pos = -1;
+ }
+
c = avio_r8(bc);
- if (bc->eof_reached)
+ if (avio_feof(bc))
return AVERROR_EOF;
sync[sp++ & 3] = c;
@@@ -611,9 -508,8 +611,9 @@@ static int ogg_get_length(AVFormatConte
struct ogg *ogg = s->priv_data;
int i, ret;
int64_t size, end;
+ int streams_left=0;
- if (!s->pb->seekable)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return 0;
// already set
diff --cc libavformat/rawenc.c
index 0edcd1c,60740fb..26baa85
--- a/libavformat/rawenc.c
+++ b/libavformat/rawenc.c
@@@ -59,25 -45,6 +59,25 @@@ AVOutputFormat ff_ac3_muxer =
#endif
#if CONFIG_ADX_MUXER
+
+static int adx_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ AVCodecParameters *par = s->streams[0]->codecpar;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ int64_t file_size = avio_tell(pb);
+ uint64_t sample_count = (file_size - 36) / par->channels / 18 * 32;
+ if (sample_count <= UINT32_MAX) {
+ avio_seek(pb, 12, SEEK_SET);
+ avio_wb32(pb, sample_count);
+ avio_seek(pb, file_size, SEEK_SET);
+ }
+ }
+
+ return 0;
+}
+
AVOutputFormat ff_adx_muxer = {
.name = "adx",
.long_name = NULL_IF_CONFIG_SMALL("CRI ADX"),
diff --cc libavformat/rmenc.c
index 0bc5bfd,6cbe700..f9821d1
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@@ -175,10 -175,10 +175,10 @@@ static int rv10_write_header(AVFormatCo
avio_wb32(s, 0); /* start time */
avio_wb32(s, BUFFER_DURATION); /* preroll */
/* duration */
- if (!s->seekable || !stream->total_frames)
+ if (!(s->seekable & AVIO_SEEKABLE_NORMAL) || !stream->total_frames)
avio_wb32(s, (int)(3600 * 1000));
else
- avio_wb32(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
+ avio_wb32(s, av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO));
put_str8(s, desc);
put_str8(s, mimetype);
avio_wb32(s, codec_data_size);
diff --cc libavformat/rsd.c
index 5a56e72,0000000..27a3d73
mode 100644,000000..100644
--- a/libavformat/rsd.c
+++ b/libavformat/rsd.c
@@@ -1,223 -1,0 +1,223 @@@
+/*
+ * RSD demuxer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "avio.h"
+#include "internal.h"
+
+static const AVCodecTag rsd_tags[] = {
+ { AV_CODEC_ID_ADPCM_PSX, MKTAG('V','A','G',' ') },
+ { AV_CODEC_ID_ADPCM_THP_LE, MKTAG('G','A','D','P') },
+ { AV_CODEC_ID_ADPCM_THP, MKTAG('W','A','D','P') },
+ { AV_CODEC_ID_ADPCM_IMA_RAD, MKTAG('R','A','D','P') },
+ { AV_CODEC_ID_ADPCM_IMA_WAV, MKTAG('X','A','D','P') },
+ { AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') },
+ { AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') },
+ { AV_CODEC_ID_XMA2, MKTAG('X','M','A',' ') },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
+static const uint32_t rsd_unsupported_tags[] = {
+ MKTAG('O','G','G',' '),
+};
+
+static int rsd_probe(AVProbeData *p)
+{
+ if (memcmp(p->buf, "RSD", 3) || p->buf[3] - '0' < 2 || p->buf[3] - '0' > 6)
+ return 0;
+ if (AV_RL32(p->buf + 8) > 256 || !AV_RL32(p->buf + 8))
+ return AVPROBE_SCORE_MAX / 8;
+ if (AV_RL32(p->buf + 16) > 8*48000 || !AV_RL32(p->buf + 16))
+ return AVPROBE_SCORE_MAX / 8;
+ return AVPROBE_SCORE_MAX;
+}
+
+static int rsd_read_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ int i, ret, version, start = 0x800;
+ AVCodecParameters *par;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 3); // "RSD"
+ version = avio_r8(pb) - '0';
+
+ par = st->codecpar;
+ par->codec_type = AVMEDIA_TYPE_AUDIO;
+ par->codec_tag = avio_rl32(pb);
+ par->codec_id = ff_codec_get_id(rsd_tags, par->codec_tag);
+ if (!par->codec_id) {
+ char tag_buf[32];
+
+ av_get_codec_tag_string(tag_buf, sizeof(tag_buf), par->codec_tag);
+ for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) {
+ if (par->codec_tag == rsd_unsupported_tags[i]) {
+ avpriv_request_sample(s, "Codec tag: %s", tag_buf);
+ return AVERROR_PATCHWELCOME;
+ }
+ }
+ av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf);
+ return AVERROR_INVALIDDATA;
+ }
+
+ par->channels = avio_rl32(pb);
+ if (par->channels <= 0 || par->channels > INT_MAX / 36) {
+ av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", par->channels);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 4); // Bit depth
+ par->sample_rate = avio_rl32(pb);
+ if (!par->sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(pb, 4); // Unknown
+
+ switch (par->codec_id) {
+ case AV_CODEC_ID_XMA2:
+ par->block_align = 2048;
+ ff_alloc_extradata(par, 34);
+ if (!par->extradata)
+ return AVERROR(ENOMEM);
+ memset(par->extradata, 0, 34);
+ break;
+ case AV_CODEC_ID_ADPCM_PSX:
+ par->block_align = 16 * par->channels;
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
+ break;
+ case AV_CODEC_ID_ADPCM_IMA_RAD:
+ par->block_align = 20 * par->channels;
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
+ break;
+ case AV_CODEC_ID_ADPCM_IMA_WAV:
+ if (version == 2)
+ start = avio_rl32(pb);
+
+ par->bits_per_coded_sample = 4;
+ par->block_align = 36 * par->channels;
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
+ break;
+ case AV_CODEC_ID_ADPCM_THP_LE:
+ /* RSD3GADP is mono, so only alloc enough memory
+ to store the coeff table for a single channel. */
+
+ start = avio_rl32(pb);
+
+ if ((ret = ff_get_extradata(s, par, s->pb, 32)) < 0)
+ return ret;
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = av_get_audio_frame_duration2(par, avio_size(pb) - start);
+ break;
+ case AV_CODEC_ID_ADPCM_THP:
+ par->block_align = 8 * par->channels;
+ avio_skip(s->pb, 0x1A4 - avio_tell(s->pb));
+
+ if ((ret = ff_alloc_extradata(st->codecpar, 32 * par->channels)) < 0)
+ return ret;
+
+ for (i = 0; i < par->channels; i++) {
+ avio_read(s->pb, st->codecpar->extradata + 32 * i, 32);
+ avio_skip(s->pb, 8);
+ }
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = (avio_size(pb) - start) / (8 * par->channels) * 14;
+ break;
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ if (version != 4)
+ start = avio_rl32(pb);
+
- if (pb->seekable)
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL)
+ st->duration = (avio_size(pb) - start) / 2 / par->channels;
+ break;
+ }
+
+ avio_skip(pb, start - avio_tell(pb));
+ if (par->codec_id == AV_CODEC_ID_XMA2) {
+ avio_skip(pb, avio_rb32(pb) + avio_rb32(pb));
+ st->duration = avio_rb32(pb);
+ }
+
+ avpriv_set_pts_info(st, 64, 1, par->sample_rate);
+
+ return 0;
+}
+
+static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVCodecParameters *par = s->streams[0]->codecpar;
+ int ret, size = 1024;
+ int64_t pos;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+
+ pos = avio_tell(s->pb);
+ if (par->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD ||
+ par->codec_id == AV_CODEC_ID_ADPCM_PSX ||
+ par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
+ par->codec_id == AV_CODEC_ID_XMA2) {
+ ret = av_get_packet(s->pb, pkt, par->block_align);
+ } else if (par->codec_tag == MKTAG('W','A','D','P') &&
+ par->channels > 1) {
+ int i, ch;
+
+ ret = av_new_packet(pkt, par->block_align);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < 4; i++) {
+ for (ch = 0; ch < par->channels; ch++) {
+ pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb);
+ pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb);
+ }
+ }
+ ret = 0;
+ } else {
+ ret = av_get_packet(s->pb, pkt, size);
+ }
+
+ if (par->codec_id == AV_CODEC_ID_XMA2 && pkt->size >= 1)
+ pkt->duration = (pkt->data[0] >> 2) * 512;
+
+ pkt->pos = pos;
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_rsd_demuxer = {
+ .name = "rsd",
+ .long_name = NULL_IF_CONFIG_SMALL("GameCube RSD"),
+ .read_probe = rsd_probe,
+ .read_header = rsd_read_header,
+ .read_packet = rsd_read_packet,
+ .extensions = "rsd",
+ .codec_tag = (const AVCodecTag* const []){rsd_tags, 0},
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --cc libavformat/tta.c
index 1447eff,091b502..ae90a85
--- a/libavformat/tta.c
+++ b/libavformat/tta.c
@@@ -136,11 -113,19 +136,11 @@@ static int tta_read_header(AVFormatCont
st->codecpar->sample_rate = samplerate;
st->codecpar->bits_per_coded_sample = bps;
- if (s->pb->seekable) {
- st->codecpar->extradata_size = avio_tell(s->pb) - start_offset;
- if (st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codecpar->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->codecpar->extradata = av_mallocz(st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codecpar->extradata) {
- st->codecpar->extradata_size = 0;
- return AVERROR(ENOMEM);
++ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ 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->codecpar->extradata, st->codecpar->extradata_size);
return 0;
}
diff --cc libavformat/utils.c
index 8227d1b,0e94b15..a059046
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@@ -2857,10 -1827,9 +2857,10 @@@ static void estimate_timings(AVFormatCo
if ((!strcmp(ic->iformat->name, "mpeg") ||
!strcmp(ic->iformat->name, "mpegts")) &&
- file_size && ic->pb->seekable) {
+ file_size && (ic->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
/* get accurate estimate from the PTSes */
estimate_timings_from_pts(ic, old_offset);
+ ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
} else if (has_duration(ic)) {
/* at least one component has timings - we use them for all
* the components */
diff --cc libavformat/voc_packet.c
index 4f60467,3865075..1e2e19e
--- a/libavformat/voc_packet.c
+++ b/libavformat/voc_packet.c
@@@ -46,10 -34,10 +46,10 @@@ ff_voc_get_packet(AVFormatContext *s, A
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)
+ if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
return AVERROR(EIO);
voc->remaining_size = avio_size(pb) - avio_tell(pb);
}
diff --cc libavformat/wavdec.c
index 0ca1ef4,8c78666..a3cd4ff
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@@ -400,17 -270,8 +400,17 @@@ static int wav_read_header(AVFormatCont
got_fmt = 1;
break;
+ case MKTAG('X', 'M', 'A', '2'):
+ /* only parse the first 'XMA2' tag found */
+ if (!got_fmt && !got_xma2 && (ret = wav_parse_xma2_tag(s, size, &st)) < 0) {
+ return ret;
+ } else if (got_xma2)
+ av_log(s, AV_LOG_WARNING, "found more than one 'XMA2' tag\n");
+
+ got_xma2 = 1;
+ break;
case MKTAG('d', 'a', 't', 'a'):
- if (!pb->seekable && !got_fmt && !got_xma2) {
- if (!got_fmt) {
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) && !got_fmt && !got_xma2) {
av_log(s, AV_LOG_ERROR,
"found no 'fmt ' tag before the 'data' tag\n");
return AVERROR_INVALIDDATA;
@@@ -796,82 -497,23 +796,82 @@@ static int w64_read_header(AVFormatCont
if (!st)
return AVERROR(ENOMEM);
- /* subtract chunk header size - normal wav file doesn't count it */
- ret = ff_get_wav_header(s, pb, st->codecpar, size - 24);
- if (ret < 0)
- return ret;
- avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
+ while (!avio_feof(pb)) {
+ if (avio_read(pb, guid, 16) != 16)
+ break;
+ size = avio_rl64(pb);
+ if (size <= 24 || INT64_MAX - size < avio_tell(pb))
+ return AVERROR_INVALIDDATA;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
+ /* subtract chunk header size - normal wav file doesn't count it */
+ ret = ff_get_wav_header(s, pb, st->codecpar, size - 24, 0);
+ if (ret < 0)
+ return ret;
+ avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
- avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+ } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
+ int64_t samples;
- size = find_guid(pb, guid_data);
- if (size < 0) {
- av_log(s, AV_LOG_ERROR, "could not find data guid\n");
- return AVERROR_INVALIDDATA;
+ samples = avio_rl64(pb);
+ if (samples > 0)
+ st->duration = samples;
+ } else if (!memcmp(guid, ff_w64_guid_data, 16)) {
+ wav->data_end = avio_tell(pb) + size - 24;
+
+ data_ofs = avio_tell(pb);
- if (!pb->seekable)
++ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
+ break;
+
+ avio_skip(pb, size - 24);
+ } else if (!memcmp(guid, ff_w64_guid_summarylist, 16)) {
+ int64_t start, end, cur;
+ uint32_t count, chunk_size, i;
+
+ start = avio_tell(pb);
+ end = start + FFALIGN(size, INT64_C(8)) - 24;
+ count = avio_rl32(pb);
+
+ for (i = 0; i < count; i++) {
+ char chunk_key[5], *value;
+
+ if (avio_feof(pb) || (cur = avio_tell(pb)) < 0 || cur > end - 8 /* = tag + size */)
+ break;
+
+ chunk_key[4] = 0;
+ avio_read(pb, chunk_key, 4);
+ chunk_size = avio_rl32(pb);
+
+ value = av_mallocz(chunk_size + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+
+ ret = avio_get_str16le(pb, chunk_size, value, chunk_size);
+ avio_skip(pb, chunk_size - ret);
+
+ av_dict_set(&s->metadata, chunk_key, value, AV_DICT_DONT_STRDUP_VAL);
+ }
+
+ 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, FFALIGN(size, INT64_C(8)) - 24);
+ }
}
- wav->data_end = avio_tell(pb) + size - 24;
- wav->w64 = 1;
+
+ if (!data_ofs)
+ return AVERROR_EOF;
+
+ ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
+ ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);
+
+ handle_stream_probing(st);
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+
+ avio_seek(pb, data_ofs, SEEK_SET);
+
+ set_spdif(s, wav);
return 0;
}
diff --cc libavformat/wavenc.c
index a21d4c5,fc7d49e..7f3059e
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@@ -308,43 -103,22 +308,43 @@@ static int wav_write_header(AVFormatCon
AVIOContext *pb = s->pb;
int64_t fmt;
- ffio_wfourcc(pb, "RIFF");
- avio_wl32(pb, 0); /* file length */
+ 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 */
+ } else {
+ ffio_wfourcc(pb, "RIFF");
+ avio_wl32(pb, -1); /* file length */
+ }
+
ffio_wfourcc(pb, "WAVE");
- /* format header */
- fmt = ff_start_tag(pb, "fmt ");
- if (ff_put_wav_header(s, pb, s->streams[0]->codecpar) < 0) {
- const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codecpar->codec_id);
- av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
- desc ? desc->name : "unknown");
- return AVERROR(ENOSYS);
+ if (wav->rf64 != RF64_NEVER) {
+ /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */
+ ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK");
+ avio_wl32(pb, 28); /* chunk size */
+ wav->ds64 = avio_tell(pb);
+ ffio_fill(pb, 0, 28);
+ }
+
+ if (wav->write_peak != 2) {
+ /* format header */
+ fmt = ff_start_tag(pb, "fmt ");
+ if (ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0) < 0) {
+ const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codecpar->codec_id);
+ av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
+ desc ? desc->name : "unknown");
+ return AVERROR(ENOSYS);
+ }
+ ff_end_tag(pb, fmt);
}
- ff_end_tag(pb, fmt);
if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */
- && s->pb->seekable) {
+ && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
wav->fact_pos = ff_start_tag(pb, "fact");
avio_wl32(pb, 0);
ff_end_tag(pb, wav->fact_pos);
@@@ -425,16 -164,8 +425,16 @@@ static int wav_write_trailer(AVFormatCo
avio_flush(pb);
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
- ff_end_tag(pb, wav->data);
+ if (wav->write_peak != 2 && avio_tell(pb) - wav->data < UINT32_MAX) {
+ ff_end_tag(pb, wav->data);
+ avio_flush(pb);
+ }
+
+ if (wav->write_peak && wav->peak_output) {
+ ret = peak_write_chunk(s);
+ avio_flush(pb);
+ }
/* update file size */
file_size = avio_tell(pb);
@@@ -540,102 -219,3 +540,102 @@@ AVOutputFormat ff_wav_muxer =
.codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
.priv_class = &wav_muxer_class,
};
+#endif /* CONFIG_WAV_MUXER */
+
+#if CONFIG_W64_MUXER
+#include "w64.h"
+
+static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos)
+{
+ *pos = avio_tell(pb);
+
+ avio_write(pb, guid, 16);
+ avio_wl64(pb, INT64_MAX);
+}
+
+static void end_guid(AVIOContext *pb, int64_t start)
+{
+ int64_t end, pos = avio_tell(pb);
+
+ end = FFALIGN(pos, 8);
+ ffio_fill(pb, 0, end - pos);
+ avio_seek(pb, start + 16, SEEK_SET);
+ avio_wl64(pb, end - start);
+ avio_seek(pb, end, SEEK_SET);
+}
+
+static int w64_write_header(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t start;
+ int ret;
+
+ avio_write(pb, ff_w64_guid_riff, sizeof(ff_w64_guid_riff));
+ avio_wl64(pb, -1);
+ avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave));
+ start_guid(pb, ff_w64_guid_fmt, &start);
+ if ((ret = ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0)) < 0) {
+ AVCodec *codec = avcodec_find_decoder(s->streams[0]->codecpar->codec_id);
+ av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
+ codec ? codec->name : "NONE");
+ return ret;
+ }
+ end_guid(pb, start);
+
+ if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */
- && s->pb->seekable) {
++ && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+ start_guid(pb, ff_w64_guid_fact, &wav->fact_pos);
+ avio_wl64(pb, 0);
+ end_guid(pb, wav->fact_pos);
+ }
+
+ start_guid(pb, ff_w64_guid_data, &wav->data);
+
+ return 0;
+}
+
+static int w64_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WAVMuxContext *wav = s->priv_data;
+ int64_t file_size;
+
- if (pb->seekable) {
++ if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
+ end_guid(pb, wav->data);
+
+ file_size = avio_tell(pb);
+ avio_seek(pb, 16, SEEK_SET);
+ avio_wl64(pb, file_size);
+
+ if (s->streams[0]->codecpar->codec_tag != 0x01) {
+ int64_t number_of_samples;
+
+ number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
+ s->streams[0]->codecpar->sample_rate * (int64_t)s->streams[0]->time_base.num,
+ s->streams[0]->time_base.den);
+ avio_seek(pb, wav->fact_pos + 24, SEEK_SET);
+ avio_wl64(pb, number_of_samples);
+ }
+
+ avio_seek(pb, file_size, SEEK_SET);
+ avio_flush(pb);
+ }
+
+ return 0;
+}
+
+AVOutputFormat ff_w64_muxer = {
+ .name = "w64",
+ .long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"),
+ .extensions = "w64",
+ .priv_data_size = sizeof(WAVMuxContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = w64_write_header,
+ .write_packet = wav_write_packet,
+ .write_trailer = w64_write_trailer,
+ .flags = AVFMT_TS_NONSTRICT,
+ .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+};
+#endif /* CONFIG_W64_MUXER */
diff --cc libavformat/wvdec.c
index 1ec52f6,717275c..261fcaf
--- a/libavformat/wvdec.c
+++ b/libavformat/wvdec.c
@@@ -238,10 -235,9 +238,10 @@@ static int wv_read_header(AVFormatConte
st->codecpar->bits_per_coded_sample = wc->bpp;
avpriv_set_pts_info(st, 64, 1, wc->rate);
st->start_time = 0;
- st->duration = wc->header.total_samples;
+ if (wc->header.total_samples != 0xFFFFFFFFu)
+ st->duration = wc->header.total_samples;
- if (s->pb->seekable) {
+ if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
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))
More information about the ffmpeg-cvslog
mailing list