Merge commit '83548fe894cdb455cc127f754d09905b6d23c173'
authorJames Almer <jamrial@gmail.com>
Tue, 21 Mar 2017 20:02:30 +0000 (17:02 -0300)
committerJames Almer <jamrial@gmail.com>
Tue, 21 Mar 2017 20:02:30 +0000 (17:02 -0300)
* commit '83548fe894cdb455cc127f754d09905b6d23c173':
  lavf: fix usage of AVIOContext.seekable

Merged-by: James Almer <jamrial@gmail.com>
65 files changed:
1  2 
libavformat/aacdec.c
libavformat/adp.c
libavformat/aiffdec.c
libavformat/aiffenc.c
libavformat/ape.c
libavformat/apngenc.c
libavformat/asfdec_o.c
libavformat/asfenc.c
libavformat/astenc.c
libavformat/au.c
libavformat/avidec.c
libavformat/avienc.c
libavformat/aviobuf.c
libavformat/bink.c
libavformat/bintext.c
libavformat/cafdec.c
libavformat/cafenc.c
libavformat/cinedec.c
libavformat/dsfdec.c
libavformat/dtshddec.c
libavformat/dv.c
libavformat/ffmdec.c
libavformat/filmstripdec.c
libavformat/flacenc.c
libavformat/flvdec.c
libavformat/gxfenc.c
libavformat/icoenc.c
libavformat/id3v1.c
libavformat/ivfenc.c
libavformat/matroskadec.c
libavformat/matroskaenc.c
libavformat/mlvdec.c
libavformat/mmf.c
libavformat/mov.c
libavformat/movenc.c
libavformat/mp3dec.c
libavformat/mp3enc.c
libavformat/mpc.c
libavformat/mpc8.c
libavformat/mpeg.c
libavformat/mpegts.c
libavformat/mvdec.c
libavformat/mxfdec.c
libavformat/mxfenc.c
libavformat/nutdec.c
libavformat/oggdec.c
libavformat/r3d.c
libavformat/rawenc.c
libavformat/rmdec.c
libavformat/rmenc.c
libavformat/rsd.c
libavformat/rsoenc.c
libavformat/smjpegenc.c
libavformat/soxenc.c
libavformat/swfenc.c
libavformat/takdec.c
libavformat/tta.c
libavformat/tty.c
libavformat/utils.c
libavformat/vc1testenc.c
libavformat/voc_packet.c
libavformat/wavdec.c
libavformat/wavenc.c
libavformat/wvdec.c
libavformat/wvenc.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);
index 9ab2ec4,0000000..7355503
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,98 @@@
-     if (s->pb->seekable)
 +/*
 + * 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 & 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",
 +};
@@@ -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;
              }
@@@ -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;
  
-     if (!pb->seekable)
 +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 & 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);
Simple merge
index 0c40be2,0000000..378a9b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,305 -1,0 +1,305 @@@
-     if (apng->acTL_offset && io_context->seekable) {
 +/*
 + * APNG muxer
 + * Copyright (c) 2015 Donny Yang
 + *
 + * first version by Donny Yang <work@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 & 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,
 +};
index 56f8446,0000000..f7000b0
mode 100644,000000..100644
--- /dev/null
@@@ -1,1790 -1,0 +1,1792 @@@
-     if (pb->seekable && !(asf->b_flags & ASF_FLAG_BROADCAST))
 +/*
 + * 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 (asf->data_reached && (!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 (pb->seekable)
++        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 & 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,
 +};
@@@ -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 */
index 11f8717,0000000..578e658
mode 100644,000000..100644
--- /dev/null
@@@ -1,214 -1,0 +1,214 @@@
-     if (s->pb->seekable) {
 +/*
 + * 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 & 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},
 +};
@@@ -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);
      }
@@@ -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;
@@@ -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)
  {
-                 if (pb->seekable && avist->pal_offset) {
 +    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 (s->pb->seekable) {
++                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 & 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;
      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;
  
-     if (pb->seekable) {
 +    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 & AVIO_SEEKABLE_NORMAL) {
          if (avi->riff_id == 1) {
              ff_end_tag(pb, avi->movi_list);
              res = avi_write_idx1(s);
      for (i = 0; i < s->nb_streams; i++) {
          AVIStream *avist = s->streams[i]->priv_data;
          for (j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++)
 -            av_free(avist->indexes.cluster[j]);
 +            av_freep(&avist->indexes.cluster[j]);
          av_freep(&avist->indexes.cluster);
          avist->indexes.ents_allocated = avist->indexes.entry = 0;
-         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;
@@@ -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);
Simple merge
index a264fd1,0000000..12e3bfd
mode 100644,000000..100644
--- /dev/null
@@@ -1,388 -1,0 +1,388 @@@
-     if (pb->seekable) {
 +/*
 + * Binary text demuxer
 + * eXtended BINary text (XBIN) demuxer
 + * Artworx Data Format demuxer
 + * iCEDraw File demuxer
 + * Copyright (c) 2010 Peter Ross <pross@xvid.org>
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +/**
 + * @file
 + * 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 & 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
Simple merge
index 5ea8e69,0000000..7aa9e8c
mode 100644,000000..100644
--- /dev/null
@@@ -1,273 -1,0 +1,273 @@@
-     if (!par->block_align && !pb->seekable) {
 +/*
 + * 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 (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 & 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},
 +};
index 32cccf5,0000000..763b93b
mode 100644,000000..100644
--- /dev/null
@@@ -1,325 -1,0 +1,325 @@@
-     if (!avctx->pb->seekable)
 +/*
 + * Phantom Cine demuxer
 + * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +/**
 + * @file
 + * Phantom Cine demuxer
 + * @author Peter Ross <pross@xvid.org>
 + */
 +
 +#include "libavutil/intreadwrite.h"
 +#include "libavcodec/bmp.h"
 +#include "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 & 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,
 +};
index f16b397,0000000..49ca336
mode 100644,000000..100644
--- /dev/null
@@@ -1,163 -1,0 +1,163 @@@
-     if (pb->seekable) {
 +/*
 + * 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 & 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,
 +};
index f5f0407,0000000..1bd403c
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,172 @@@
-             if (!pb->seekable)
 +/*
 + * 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 & 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,
 +};
@@@ -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;
  }
  
index f863bf7,0000000..de6ac27
mode 100644,000000..100644
--- /dev/null
@@@ -1,878 -1,0 +1,878 @@@
-     if (pb->seekable) {
 +/*
 + * 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 & 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,
 +};
Simple merge
Simple merge
@@@ -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
@@@ -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;
      }
  
index a7ada19,0000000..e641f7b
mode 100644,000000..100644
--- /dev/null
@@@ -1,203 -1,0 +1,203 @@@
-     if (!pb->seekable) {
 +/*
 + * 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 & 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,
 +};
Simple merge
@@@ -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 (pb->seekable && ctx->frame_cnt > 1) {
 +    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 & 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;
  }
@@@ -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++) {
@@@ -325,67 -264,11 +325,67 @@@ static void end_ebml_master(AVIOContex
      avio_seek(pb, pos, SEEK_SET);
  }
  
-     if (pb->seekable) {
 +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 & 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];
  
          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)
      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;
      }
      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;
index 665b28d,0000000..90c3779
mode 100644,000000..100644
--- /dev/null
@@@ -1,478 -1,0 +1,478 @@@
-     if (!avctx->pb->seekable)
 +/*
 + * 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 & 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,
 +};
Simple merge
@@@ -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 (pb->seekable) {
 +    if (!c->has_looked_for_mfra && c->use_mfra_for > 0) {
 +        c->has_looked_for_mfra = 1;
++        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;
          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);
      }
      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;
Simple merge
@@@ -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);
  
@@@ -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];
Simple merge
@@@ -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);
Simple merge
@@@ -2599,15 -2062,6 +2599,15 @@@ static int parse_pcr(int64_t *ppcr_high
      return 0;
  }
  
-         av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
 +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 & 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;
Simple merge
@@@ -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);
@@@ -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 {
Simple merge
@@@ -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;
-     if (s->pb->seekable) {
 +    const struct ogg_codec *codec;
 +    int i = 0;
 +
++    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
 +        uint8_t magic[8];
 +        int64_t pos = avio_tell(s->pb);
 +        avio_skip(s->pb, nsegs);
 +        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
Simple merge
@@@ -59,25 -45,6 +59,25 @@@ AVOutputFormat ff_ac3_muxer = 
  #endif
  
  #if CONFIG_ADX_MUXER
-     if (pb->seekable) {
 +
 +static int adx_write_trailer(AVFormatContext *s)
 +{
 +    AVIOContext *pb = s->pb;
 +    AVCodecParameters *par = s->streams[0]->codecpar;
 +
++    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"),
Simple merge
@@@ -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);
index 5a56e72,0000000..27a3d73
mode 100644,000000..100644
--- /dev/null
@@@ -1,223 -1,0 +1,223 @@@
-         if (pb->seekable)
 +/*
 + * 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 & 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,
 +};
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -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;
  }
Simple merge
@@@ -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 */
Simple merge
@@@ -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);
          }
@@@ -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;
  }
@@@ -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,
  };
-         && s->pb->seekable) {
 +#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 */
-     if (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 & AVIO_SEEKABLE_NORMAL) {
 +        end_guid(pb, wav->data);
 +
 +        file_size = avio_tell(pb);
 +        avio_seek(pb, 16, SEEK_SET);