From ec459ccb9a7eadee41afd4da2b71a52e18dceae6 Mon Sep 17 00:00:00 2001
From: Tomasz Jezierski <tomasz.jezierski@tefnet.pl>
Date: Thu, 6 Sep 2012 20:14:27 +0200
Subject: [PATCH] Vividas support for IPLEX for current ffmpeg
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ported to current ffmpeg version
Copyright (c) 2010 Andrzej Szombierski
based on vivparse Copyright (c) 2007 Måns Rullgård
---
 libavformat/Makefile               |    1 +
 libavformat/allformats.c           |    1 +
 libavformat/vividas.c              |  740 ++++++++++++++++++++++++
 patches/0110-vividas-support.patch |  770 +++++++++++++++++++++++++
 4 files changed, 1512 insertions(+)
 create mode 100644 libavformat/vividas.c
 create mode 100644 patches/0110-vividas-support.patch

diff --git a/libavformat/Makefile b/libavformat/Makefile
index bd2b17b..6642498 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -315,6 +315,7 @@ OBJS-$(CONFIG_TXD_DEMUXER)               += txd.o
 OBJS-$(CONFIG_VC1_DEMUXER)               += rawdec.o
 OBJS-$(CONFIG_VC1T_DEMUXER)              += vc1test.o
 OBJS-$(CONFIG_VC1T_MUXER)                += vc1testenc.o
+OBJS-$(CONFIG_VIVIDAS_DEMUXER)           += vividas.o
 OBJS-$(CONFIG_VMD_DEMUXER)               += sierravmd.o
 OBJS-$(CONFIG_VOC_DEMUXER)               += vocdec.o voc.o
 OBJS-$(CONFIG_VOC_MUXER)                 += vocenc.o voc.o
diff --git a/libavformat/allformats.c b/lib/ffmpeg/libavformat/allformats.c
index 134839f..0af5ba9 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -232,6 +232,7 @@ void av_register_all(void)
     REGISTER_DEMUXER  (TTY, tty);
     REGISTER_DEMUXER  (VC1, vc1);
     REGISTER_MUXDEMUX (VC1T, vc1t);
+    REGISTER_DEMUXER  (VIVIDAS, vividas);
     REGISTER_DEMUXER  (VMD, vmd);
     REGISTER_MUXDEMUX (VOC, voc);
     REGISTER_DEMUXER  (VQF, vqf);
diff --git a/libavformat/vividas.c b/libavformat/vividas.c
new file mode 100644
index 0000000..2d3ba27
--- /dev/null
+++ b/libavformat/vividas.c
@@ -0,0 +1,740 @@
+/*
+ * Vividas VIV format Demuxer
+ * Copyright (c) 2010 Andrzej Szombierski
+ * based on vivparse Copyright (c) 2007 Måns Rullgård
+ *
+ * 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
+ * @brief Vividas VIV (.viv) file demuxer
+ * @author Andrzej Szombierski [qq at kuku eu org] (2010-07)
+ * @sa http://wiki.multimedia.cx/index.php?title=Vividas_VIV
+ */
+
+#define AV_PKT_FLAG_KEY   0x0001
+
+#include "libavutil/intreadwrite.h"
+#include "avio_internal.h"
+#include "avformat.h"
+
+#define MAX_AUDIO_SUBPACKETS 100
+#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
+#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO
+
+typedef struct VIV_SB_block {
+    int size, n_packets;
+    int64_t byte_offset;
+    int packet_offset;
+} VIV_SB_block;
+
+typedef struct VIV_SB_entry {
+    int size, flag;
+} VIV_SB_entry;
+
+typedef struct VIV_AudioSubpacket {
+    int start, pcm_bytes;
+} VIV_AudioSubpacket;
+
+typedef struct VIV_DemuxContext
+{
+    int n_sb_blocks;
+    VIV_SB_block *sb_blocks;
+
+    uint32_t sb_key;
+    int64_t sb_offset;
+
+    int current_sb, current_sb_entry;
+    uint8_t *sb_buf;
+    AVIOContext *sb_pb;
+    int n_sb_entries;
+    VIV_SB_entry *sb_entries;
+
+    int n_audio_subpackets;
+    int current_audio_subpacket;
+
+    int audio_sample;
+
+    VIV_AudioSubpacket audio_subpackets[MAX_AUDIO_SUBPACKETS];
+} VIV_DemuxContext;
+
+static int viv_probe(AVProbeData *p)
+{
+    if(strncmp((char*)p->buf, "vividas03", 9))
+        return 0;
+
+    return AVPROBE_SCORE_MAX;
+}
+
+const unsigned short keybits[32] = {
+     163,  416,  893,   82,  223,  572, 1137,  430,
+     659, 1104,   13,  626,  695,  972, 1465,  686,
+     843, 1216,  317, 1122, 1383,   92,  513, 1158,
+    1243,   48,  573, 1306, 1495,  396, 1009,  350,
+};
+
+static uint32_t decode_key(uint8_t  *buf)
+{
+    uint32_t key = 0;
+    int i;
+
+    for (i = 0; i < 32; i++) {
+        unsigned p = keybits[i];
+        key |= !!(buf[p>>3] & (1<<(p&7))) << i;
+    }
+
+    return key;
+}
+
+static void put_v(uint8_t *p, int v)
+{
+	if(v>>28) 
+		*p++ = ((v>>28)&0x7f)|0x80;
+	if(v>>21)
+		*p++ = ((v>>21)&0x7f)|0x80;
+	if(v>>14)
+		*p++ = ((v>>14)&0x7f)|0x80;
+	if(v>>7)
+		*p++ = ((v>>7)&0x7f)|0x80;
+	*p++ = v&0x7f;
+}
+
+static unsigned int recover_key(unsigned char sample[4], int expected_size) 
+{
+	unsigned char plaintext[8] = { 'S', 'B' };
+	put_v(plaintext+2, expected_size);
+
+	return (sample[0]^plaintext[0])|
+		((sample[1]^plaintext[1])<<8)|
+		((sample[2]^plaintext[2])<<16)|
+		((sample[3]^plaintext[3])<<24);
+}
+
+static void xor_block(void *p1, void *p2, int size, int key, int *key_ptr)
+{
+	int *d1 = p1;
+	int *d2 = p2;
+	int k = *key_ptr;
+
+	size >>= 2;
+
+	while (size--) {
+		*d2 = *d1 ^ k;
+		k += key;
+		d1++;
+		d2++;
+	}
+
+	*key_ptr = k;
+}
+
+static void decode_block(uint8_t *src, uint8_t *dest, int size,
+				  uint32_t key, uint32_t *key_ptr,
+				  int align)
+{
+	int s = size;
+	char tmp[4];
+	int a2;
+
+	if (!size)
+		return;
+
+	align &= 3;
+	a2 = (4 - align) & 3;
+
+	if (align) {
+		uint32_t tmpkey = *key_ptr - key;
+		memcpy(tmp + align, src, a2);
+		xor_block(tmp, tmp, 4, key, &tmpkey);
+		memcpy(dest, tmp + align, a2);
+		s -= a2;
+	}
+
+	if (s >= 4) {
+		if (!align)
+			align = 4;
+		xor_block(src + a2, dest + a2, s & ~3,
+				  key, key_ptr);
+		s &= 3;
+	}
+
+	if (s) {
+		size -= s;
+		memcpy(tmp, src + size, s);
+		xor_block(&tmp, &tmp, 4, key, key_ptr);
+		memcpy(dest + size, tmp, s);
+	}
+}
+
+static uint32_t get_v(uint8_t *p)
+{
+	uint32_t v = 0;
+
+	do {
+		v <<= 7;
+		v += *p & 0x7f;
+	} while (*p++ & 0x80);
+
+	return v;
+}
+
+static uint8_t *read_vblock(AVIOContext *src, uint32_t *size, uint32_t key, uint32_t *k2, int align)
+{
+	uint8_t tmp[4];
+	uint8_t *buf;
+	unsigned n;
+
+	if(avio_read(src, tmp, 4) != 4)
+        return NULL;
+
+	decode_block(tmp, tmp, 4, key, k2, align);
+
+	n = get_v(tmp);
+
+	buf = av_malloc(n);
+	if (!buf)
+		return NULL;
+
+	*size = n;
+	n -= 4;
+
+	memcpy(buf, tmp, 4);
+
+	if (avio_read(src, buf + 4, n) == n) {
+		decode_block(buf + 4, buf + 4, n, key, k2, align + 4);
+	} else {
+		av_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, uint32_t *key, int expected_size)
+{
+	uint8_t *buf;
+	uint8_t ibuf[8], sbuf[8];
+	uint32_t k2;
+	int n;
+
+	if (avio_read(src, ibuf, 8) < 8)
+		return NULL;
+
+	k2 = *key;
+	decode_block(ibuf, sbuf, 8, *key, &k2, 0);
+
+	n = get_v(sbuf+2);
+
+	if (sbuf[0] != 'S' || sbuf[1] != 'B' || (expected_size>0 && n != expected_size)) {
+        uint32_t tmpkey = recover_key(ibuf, expected_size);
+        k2 = tmpkey;
+	    decode_block(ibuf, sbuf, 8, tmpkey, &k2, 0);
+	    n = get_v(sbuf+2);
+        if(sbuf[0] != 'S' || sbuf[1] != 'B' || expected_size != n)
+            return NULL;
+        *key = tmpkey;
+	}
+
+	buf = av_malloc(n);
+	if (!buf)
+		return NULL;
+
+	memcpy(buf, sbuf, 8);
+
+	*size = n;
+	n -= 8;
+
+	if (avio_read(src, buf+8, n) < n) {
+		av_free(buf);
+		return NULL;
+	}
+
+	decode_block(buf + 8, buf + 8, n, *key, &k2, 0);
+
+	return buf;
+}
+
+static void track_header(VIV_DemuxContext *viv, AVFormatContext *s,  uint8_t *buf, int size) 
+{
+    int i,j;
+    int64_t off;
+    int val_1;
+    int num_video, num_audio;
+    AVIOContext *pb=0;
+
+    pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL);
+    //ff_get_v(pb); // track_header_len
+    ffio_read_varlen(pb); // track_header_len
+    avio_r8(pb); // '1'
+
+    //val_1 = ff_get_v(pb);
+    val_1 = ffio_read_varlen(pb);
+
+    for(i=0;i<val_1;i++) {
+        int c = avio_r8(pb);
+        for(j=0;j<c;j++) {
+            avio_r8(pb); // val_3
+            avio_r8(pb); // val_4
+        }
+    }
+
+    avio_r8(pb); // num_streams
+
+    off = avio_tell(pb);
+    //off += ff_get_v(pb); // val_5
+    off += ffio_read_varlen(pb); // val_5
+
+    avio_r8(pb); // '2'
+    num_video = avio_r8(pb);
+    
+    avio_seek(pb, off, SEEK_SET);
+    if(num_video != 1) 
+        av_log(s, AV_LOG_WARNING, "viv: number of video tracks %d is not 1\n", num_video);
+
+    for(i=0;i<num_video;i++) {
+        AVStream *st = avformat_new_stream(s, NULL);
+        AVCodecContext *vcodec = st->codec;
+
+        st->id = i;
+		
+        vcodec->codec_type = CODEC_TYPE_VIDEO;
+		vcodec->codec_id = CODEC_ID_VP6;
+
+        off = avio_tell(pb);
+        //off += ff_get_v(pb);
+        off += ffio_read_varlen(pb);
+        avio_r8(pb); // '3'
+        avio_r8(pb); // val_7
+        st->time_base.num = avio_rl32(pb); // frame_time
+        st->time_base.den = avio_rl32(pb); // time_base
+        st->nb_frames = avio_rl32(pb); // n frames
+        vcodec->width = avio_rl16(pb); // width
+        vcodec->height = avio_rl16(pb); // height
+        avio_r8(pb); // val_8
+        avio_rl32(pb); // val_9
+
+		vcodec->flags |= CODEC_FLAG_GLOBAL_HEADER; // ?
+
+        avio_seek(pb, off, SEEK_SET);
+    }
+
+    off = avio_tell(pb);
+    //off += ff_get_v(pb); // val_10
+    off += ffio_read_varlen(pb); // val_10
+    avio_r8(pb); // '4'
+    num_audio = avio_r8(pb);
+    avio_seek(pb, off, SEEK_SET);
+
+    if(num_audio != 1) 
+        av_log(s, AV_LOG_WARNING, "viv: number of audio tracks %d is not 1\n", num_audio);
+
+    for(i=0;i<num_audio;i++) {
+        int q;
+        AVStream *st = avformat_new_stream(s, NULL);
+        AVCodecContext *acodec = st->codec;
+
+        st->id = num_video + i;
+        
+        acodec->codec_type = CODEC_TYPE_AUDIO;
+		acodec->codec_id = CODEC_ID_VORBIS;
+		acodec->flags |= CODEC_FLAG_GLOBAL_HEADER; // ?
+
+        off = avio_tell(pb);
+        //off += ff_get_v(pb); // length
+        off += ffio_read_varlen(pb); // length
+        avio_r8(pb); // '5'
+        avio_r8(pb); //codec_id
+        avio_rl16(pb); //codec_subid
+        acodec->channels = avio_rl16(pb); // channels
+        acodec->sample_rate = avio_rl32(pb); // sample_rate
+        avio_seek(pb, 10, SEEK_CUR); // data_1
+        q = avio_r8(pb);
+        avio_seek(pb, q, SEEK_CUR); // data_2
+        avio_r8(pb); // zeropad
+
+        if(avio_tell(pb) < off) {
+            int num_data;
+		    int xd_size = 0;
+            int data_len[256];
+		    uint8_t * p;
+            int offset = 1;
+            //ff_get_v(pb); // val_13
+            ffio_read_varlen(pb); // val_13
+            avio_r8(pb); // '19'
+            //ff_get_v(pb); // len_3
+            ffio_read_varlen(pb); // len_3
+            num_data = avio_r8(pb);
+            for(j=0;j<num_data;j++) {
+                //data_len[j] = ff_get_v(pb);
+                data_len[j] = ffio_read_varlen(pb);
+                xd_size += data_len[j];
+            }
+		
+            acodec->extradata_size = 64 + xd_size + xd_size / 255;
+            acodec->extradata = (uint8_t*)av_mallocz(acodec->extradata_size);
+            
+            p = acodec->extradata;
+		    p[0] = 2;
+
+            for(j=0;j<num_data-1;j++)
+			    offset += av_xiphlacing(&p[offset], data_len[j]);
+
+            for(j=0;j<num_data;j++) {
+                avio_read(pb, &p[offset], data_len[j]);
+    			offset += data_len[j];
+            }
+
+		    acodec->extradata_size = offset;
+        }
+    }
+
+    av_free(pb);
+}
+
+static void track_index(VIV_DemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size)
+{
+    int i;
+    int64_t off;
+    int poff;
+    int maxnp=0;
+    AVIOContext *pb=0;
+
+    pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL);
+    //ff_get_v(pb); // track_index_len
+    ffio_read_varlen(pb); // track_index_len
+    avio_r8(pb); // 'c'
+    //viv->n_sb_blocks = ff_get_v(pb);
+    viv->n_sb_blocks = ffio_read_varlen(pb);
+    viv->sb_blocks = av_mallocz(sizeof(VIV_SB_block) * viv->n_sb_blocks);
+    if(!viv->sb_blocks) {
+        viv->n_sb_blocks = 0;
+        av_free(pb);
+        return;
+    }
+
+    off = 0;
+    poff = 0;
+
+    for(i=0;i<viv->n_sb_blocks;i++) {
+        viv->sb_blocks[i].byte_offset = off;
+        viv->sb_blocks[i].packet_offset = poff;
+
+        //viv->sb_blocks[i].size = ff_get_v(pb);
+        //viv->sb_blocks[i].n_packets = ff_get_v(pb);
+        viv->sb_blocks[i].size = ffio_read_varlen(pb);
+        viv->sb_blocks[i].n_packets = ffio_read_varlen(pb);
+
+        off += viv->sb_blocks[i].size;
+        poff += viv->sb_blocks[i].n_packets;
+
+
+        if(maxnp < viv->sb_blocks[i].n_packets)
+            maxnp = viv->sb_blocks[i].n_packets;
+    }
+
+    viv->sb_entries = av_mallocz(maxnp * sizeof(VIV_SB_entry));
+    av_free(pb);
+}
+
+static void load_sb_block(AVFormatContext *s, VIV_DemuxContext *viv, int expected_size)
+{
+    uint32_t size=0;
+    int i;
+    AVIOContext *pb = 0;
+    if(viv->sb_pb) {
+        av_free(viv->sb_pb);
+        viv->sb_pb = NULL;
+    }
+    
+    if(viv->sb_buf) 
+        av_free(viv->sb_buf);
+
+    viv->sb_buf = read_sb_block(s->pb, &size, &viv->sb_key, expected_size);
+    if(!viv->sb_buf) {
+        return;
+    }
+
+    pb = avio_alloc_context(viv->sb_buf, size, 0, NULL, NULL, NULL, NULL);
+    viv->sb_pb = pb;
+    
+    avio_r8(pb); //  'S'
+    avio_r8(pb); //  'B'
+    //ff_get_v(pb); //  size
+    ffio_read_varlen(pb); //  size
+    avio_r8(pb); //  junk
+    //ff_get_v(pb); // first packet
+    ffio_read_varlen(pb); // first packet
+
+    viv->n_sb_entries = viv->sb_blocks[viv->current_sb].n_packets;
+
+    for(i=0;i<viv->n_sb_entries;i++) {
+        //viv->sb_entries[i].size = ff_get_v(pb);
+        viv->sb_entries[i].size = ffio_read_varlen(pb);
+        viv->sb_entries[i].flag = avio_r8(pb);
+    }
+
+    //ff_get_v(pb); // 0
+    ffio_read_varlen(pb); // 0
+    avio_r8(pb); // 0
+
+    viv->current_sb_entry = 0;
+}
+
+static int viv_read_header(AVFormatContext *s,
+                            AVFormatParameters *ap)
+{
+    VIV_DemuxContext *viv = s->priv_data;
+    AVIOContext *pb = s->pb;
+    int64_t header_end;
+    int num_tracks;
+    uint32_t key, k2;
+    uint32_t v;
+    uint8_t keybuffer[187];
+    uint32_t b22_size = 0;
+	uint32_t b22_key = 0;
+    uint8_t *buf = 0;
+
+    // string "vividas03"
+    avio_seek(pb, 9, SEEK_CUR);
+
+    header_end = avio_tell(pb);
+
+    // v: header size
+    //header_end += ff_get_v(pb);
+    header_end += ffio_read_varlen(pb);
+
+    // u8: n tracks
+    num_tracks = avio_r8(pb);
+
+    if(num_tracks != 1) {
+        av_log(s, AV_LOG_ERROR, "number of tracks %d is not 1\n", num_tracks);
+        return AVERROR(EINVAL);
+    }
+
+    v = avio_r8(pb);
+    avio_seek(pb, v, SEEK_CUR);
+
+    avio_read(pb, keybuffer, 187);
+    key = decode_key(keybuffer);
+    viv->sb_key = key;
+
+    avio_rl32(pb); // track_header_len
+	
+    for(;;) {
+        int64_t here = avio_tell(pb);
+        int block_len, block_type;
+
+        if(here >= header_end)
+            break;
+
+        //block_len = ff_get_v(pb);
+        block_len = ffio_read_varlen(pb);
+        block_type = avio_r8(pb);
+
+        if(block_type == 22) {
+            avio_read(pb, keybuffer, 187);
+            b22_key = decode_key(keybuffer);
+            b22_size = avio_rl32(pb);
+        }
+
+        avio_seek(pb, here + block_len, SEEK_SET);
+    }
+
+    if(b22_size) {
+        k2 = b22_key;
+        buf = read_vblock(pb, &v, b22_key, &k2, 0);
+        if(!buf)
+            return AVERROR(EIO);
+
+        av_free(buf);
+    }
+
+    k2 = key;
+    buf = read_vblock(pb, &v, key, &k2, 0);
+    if(!buf)
+        return AVERROR(EIO);
+    track_header(viv, s, buf, v);
+    av_free(buf);
+
+    buf = read_vblock(pb, &v, key, &k2, v);
+    if(!buf)
+        return AVERROR(EIO);
+    track_index(viv, s, buf, v);
+    av_free(buf);
+
+    viv->sb_offset = avio_tell(pb);
+    if(viv->n_sb_blocks > 0) {
+        viv->current_sb = 0;
+        load_sb_block(s, viv, viv->sb_blocks[0].size);
+    } else {
+        viv->current_sb = -1;
+    }
+
+    return 0;
+}
+
+static int viv_read_packet(AVFormatContext *s,
+                           AVPacket *pkt)
+{
+    VIV_DemuxContext *viv = s->priv_data;
+    AVIOContext *pb;
+    int64_t off;
+
+    if(viv->current_audio_subpacket < viv->n_audio_subpackets) {
+        // audio packets
+        AVStream *astream;
+        int size = viv->audio_subpackets[viv->current_audio_subpacket+1].start - viv->audio_subpackets[viv->current_audio_subpacket].start;
+        pb = viv->sb_pb;
+        av_get_packet(pb, pkt, size);
+        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
+
+        pkt->stream_index = 1;
+        astream = s->streams[pkt->stream_index];
+
+        pkt->pts = viv->audio_sample * (long long)astream->time_base.den / (long long)astream->time_base.num / (long long)astream->codec->sample_rate;
+        viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codec->channels;
+        pkt->flags |= AV_PKT_FLAG_KEY;
+        viv->current_audio_subpacket++;
+        return 0;
+    }
+
+    if(viv->current_sb_entry >= viv->n_sb_entries) {
+        if(viv->current_sb+1 >= viv->n_sb_blocks)
+            return AVERROR(EIO);
+        viv->current_sb++;
+
+        load_sb_block(s, viv, 0);
+        viv->current_sb_entry = 0;
+    }
+   
+    pb = viv->sb_pb;
+    off = avio_tell(pb);
+    off += viv->sb_entries[viv->current_sb_entry].size;
+
+    if(viv->sb_entries[viv->current_sb_entry].flag == 0) {
+        // A/V packet
+        int i;
+        //int v_size = ff_get_v(pb);
+        int v_size = ffio_read_varlen(pb);
+        ///*int a_size = */ff_get_v(pb);
+        /*int a_size = */ffio_read_varlen(pb);
+        av_get_packet(pb, pkt, v_size);
+        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
+     
+        pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry;
+        pkt->flags |= (pkt->data[0]&0x80)?0:AV_PKT_FLAG_KEY;
+        pkt->stream_index = 0;
+
+        for(i=0;i<MAX_AUDIO_SUBPACKETS-1;i++) {
+            int start, pcm_bytes;
+            //start = ff_get_v(pb);
+            //pcm_bytes = ff_get_v(pb);
+            start = ffio_read_varlen(pb);
+            pcm_bytes = ffio_read_varlen(pb);
+
+            if(i > 0 && start == 0)
+                break;
+
+            viv->n_audio_subpackets = i+1;
+            viv->audio_subpackets[i].start = start;
+            viv->audio_subpackets[i].pcm_bytes = pcm_bytes;
+        }
+        viv->audio_subpackets[viv->n_audio_subpackets].start = (int)(off - avio_tell(pb));
+        viv->current_audio_subpacket = 0;
+        //viv->n_audio_subpackets = 0;
+        //avio_seek(pb, off, SEEK_SET);
+        
+    } else {
+        // V packet
+        //int v_size = ff_get_v(pb);
+        int v_size = ffio_read_varlen(pb);
+        av_get_packet(pb, pkt, v_size);
+        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
+        pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry;
+        pkt->flags |= (pkt->data[0]&0x80)?0:AV_PKT_FLAG_KEY;
+        pkt->stream_index = 0;
+    }
+
+    viv->current_sb_entry++;
+
+//    avio_seek(pb, off, SEEK_SET);
+
+    return 0;
+}
+
+static int viv_read_close(AVFormatContext *s)
+{
+    VIV_DemuxContext *viv = s->priv_data;
+    if(viv->sb_pb) 
+        av_free(viv->sb_pb);
+    
+    if(viv->sb_buf) 
+        av_free(viv->sb_buf);
+
+    if(viv->sb_blocks)
+        av_free(viv->sb_blocks);
+   
+    if(viv->sb_entries)
+        av_free(viv->sb_entries);
+
+    return 0;
+}
+
+static int viv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+    VIV_DemuxContext *viv = s->priv_data;
+    int frame = 0;
+    int i;
+
+    if(stream_index == 0) 
+        frame = (int)timestamp;
+    else 
+        frame = (int)timestamp * s->streams[stream_index]->time_base.den * s->streams[0]->time_base.num / s->streams[stream_index]->time_base.num / s->streams[0]->time_base.den;
+
+    for(i=0;i<viv->n_sb_blocks;i++) {
+        if(frame >= viv->sb_blocks[i].packet_offset && frame < viv->sb_blocks[i].packet_offset + viv->sb_blocks[i].n_packets) {
+            // flush audio packet queue
+            viv->current_audio_subpacket = 0;
+            viv->n_audio_subpackets = 0;
+            viv->current_sb = i;
+            // seek to ith sb block
+            avio_seek(s->pb, viv->sb_offset + viv->sb_blocks[i].byte_offset, SEEK_SET);
+            // load the block
+            load_sb_block(s, viv, 0);
+            // most problematic part: guess audio offset
+            viv->audio_sample = (int64_t)viv->sb_blocks[i].packet_offset * (int64_t)s->streams[1]->codec->sample_rate * s->streams[0]->time_base.num / s->streams[0]->time_base.den;
+            // hand-tuned 1.3s a/v offset
+            viv->audio_sample += 1300 * s->streams[1]->codec->sample_rate / 1000;
+            viv->current_sb_entry = 0;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+AVInputFormat ff_vividas_demuxer = {
+    "vividas",
+    "Vividas VIV format",
+    sizeof(VIV_DemuxContext),
+    viv_probe,
+    viv_read_header,
+    viv_read_packet,
+    viv_read_close,
+    viv_read_seek
+};
+
diff --git a/patches/0110-vividas-support.patch b/patches/0110-vividas-support.patch
new file mode 100644
index 0000000..713a0a5
--- /dev/null
+++ b/patches/0110-vividas-support.patch
@@ -0,0 +1,770 @@
+diff --git a/lib/ffmpeg/libavformat/Makefile b/lib/ffmpeg/libavformat/Makefile
+index bd2b17b..6642498 100644
+--- a/lib/ffmpeg/libavformat/Makefile
++++ b/lib/ffmpeg/libavformat/Makefile
+@@ -315,6 +315,7 @@ OBJS-$(CONFIG_TXD_DEMUXER)               += txd.o
+ OBJS-$(CONFIG_VC1_DEMUXER)               += rawdec.o
+ OBJS-$(CONFIG_VC1T_DEMUXER)              += vc1test.o
+ OBJS-$(CONFIG_VC1T_MUXER)                += vc1testenc.o
++OBJS-$(CONFIG_VIVIDAS_DEMUXER)           += vividas.o
+ OBJS-$(CONFIG_VMD_DEMUXER)               += sierravmd.o
+ OBJS-$(CONFIG_VOC_DEMUXER)               += vocdec.o voc.o
+ OBJS-$(CONFIG_VOC_MUXER)                 += vocenc.o voc.o
+diff --git a/lib/ffmpeg/libavformat/allformats.c b/lib/ffmpeg/libavformat/allformats.c
+index 134839f..0af5ba9 100644
+--- a/lib/ffmpeg/libavformat/allformats.c
++++ b/lib/ffmpeg/libavformat/allformats.c
+@@ -232,6 +232,7 @@ void av_register_all(void)
+     REGISTER_DEMUXER  (TTY, tty);
+     REGISTER_DEMUXER  (VC1, vc1);
+     REGISTER_MUXDEMUX (VC1T, vc1t);
++    REGISTER_DEMUXER  (VIVIDAS, vividas);
+     REGISTER_DEMUXER  (VMD, vmd);
+     REGISTER_MUXDEMUX (VOC, voc);
+     REGISTER_DEMUXER  (VQF, vqf);
+diff --git a/lib/ffmpeg/libavformat/vividas.c b/lib/ffmpeg/libavformat/vividas.c
+new file mode 100644
+index 0000000..2d3ba27
+--- /dev/null
++++ b/lib/ffmpeg/libavformat/vividas.c
+@@ -0,0 +1,740 @@
++/*
++ * Vividas VIV format Demuxer
++ * Copyright (c) 2010 Andrzej Szombierski
++ * based on vivparse Copyright (c) 2007 Måns Rullgård
++ *
++ * 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
++ * @brief Vividas VIV (.viv) file demuxer
++ * @author Andrzej Szombierski [qq at kuku eu org] (2010-07)
++ * @sa http://wiki.multimedia.cx/index.php?title=Vividas_VIV
++ */
++
++#define AV_PKT_FLAG_KEY   0x0001
++
++#include "libavutil/intreadwrite.h"
++#include "avio_internal.h"
++#include "avformat.h"
++
++#define MAX_AUDIO_SUBPACKETS 100
++#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
++#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO
++
++typedef struct VIV_SB_block {
++    int size, n_packets;
++    int64_t byte_offset;
++    int packet_offset;
++} VIV_SB_block;
++
++typedef struct VIV_SB_entry {
++    int size, flag;
++} VIV_SB_entry;
++
++typedef struct VIV_AudioSubpacket {
++    int start, pcm_bytes;
++} VIV_AudioSubpacket;
++
++typedef struct VIV_DemuxContext
++{
++    int n_sb_blocks;
++    VIV_SB_block *sb_blocks;
++
++    uint32_t sb_key;
++    int64_t sb_offset;
++
++    int current_sb, current_sb_entry;
++    uint8_t *sb_buf;
++    AVIOContext *sb_pb;
++    int n_sb_entries;
++    VIV_SB_entry *sb_entries;
++
++    int n_audio_subpackets;
++    int current_audio_subpacket;
++
++    int audio_sample;
++
++    VIV_AudioSubpacket audio_subpackets[MAX_AUDIO_SUBPACKETS];
++} VIV_DemuxContext;
++
++static int viv_probe(AVProbeData *p)
++{
++    if(strncmp((char*)p->buf, "vividas03", 9))
++        return 0;
++
++    return AVPROBE_SCORE_MAX;
++}
++
++const unsigned short keybits[32] = {
++     163,  416,  893,   82,  223,  572, 1137,  430,
++     659, 1104,   13,  626,  695,  972, 1465,  686,
++     843, 1216,  317, 1122, 1383,   92,  513, 1158,
++    1243,   48,  573, 1306, 1495,  396, 1009,  350,
++};
++
++static uint32_t decode_key(uint8_t  *buf)
++{
++    uint32_t key = 0;
++    int i;
++
++    for (i = 0; i < 32; i++) {
++        unsigned p = keybits[i];
++        key |= !!(buf[p>>3] & (1<<(p&7))) << i;
++    }
++
++    return key;
++}
++
++static void put_v(uint8_t *p, int v)
++{
++	if(v>>28) 
++		*p++ = ((v>>28)&0x7f)|0x80;
++	if(v>>21)
++		*p++ = ((v>>21)&0x7f)|0x80;
++	if(v>>14)
++		*p++ = ((v>>14)&0x7f)|0x80;
++	if(v>>7)
++		*p++ = ((v>>7)&0x7f)|0x80;
++	*p++ = v&0x7f;
++}
++
++static unsigned int recover_key(unsigned char sample[4], int expected_size) 
++{
++	unsigned char plaintext[8] = { 'S', 'B' };
++	put_v(plaintext+2, expected_size);
++
++	return (sample[0]^plaintext[0])|
++		((sample[1]^plaintext[1])<<8)|
++		((sample[2]^plaintext[2])<<16)|
++		((sample[3]^plaintext[3])<<24);
++}
++
++static void xor_block(void *p1, void *p2, int size, int key, int *key_ptr)
++{
++	int *d1 = p1;
++	int *d2 = p2;
++	int k = *key_ptr;
++
++	size >>= 2;
++
++	while (size--) {
++		*d2 = *d1 ^ k;
++		k += key;
++		d1++;
++		d2++;
++	}
++
++	*key_ptr = k;
++}
++
++static void decode_block(uint8_t *src, uint8_t *dest, int size,
++				  uint32_t key, uint32_t *key_ptr,
++				  int align)
++{
++	int s = size;
++	char tmp[4];
++	int a2;
++
++	if (!size)
++		return;
++
++	align &= 3;
++	a2 = (4 - align) & 3;
++
++	if (align) {
++		uint32_t tmpkey = *key_ptr - key;
++		memcpy(tmp + align, src, a2);
++		xor_block(tmp, tmp, 4, key, &tmpkey);
++		memcpy(dest, tmp + align, a2);
++		s -= a2;
++	}
++
++	if (s >= 4) {
++		if (!align)
++			align = 4;
++		xor_block(src + a2, dest + a2, s & ~3,
++				  key, key_ptr);
++		s &= 3;
++	}
++
++	if (s) {
++		size -= s;
++		memcpy(tmp, src + size, s);
++		xor_block(&tmp, &tmp, 4, key, key_ptr);
++		memcpy(dest + size, tmp, s);
++	}
++}
++
++static uint32_t get_v(uint8_t *p)
++{
++	uint32_t v = 0;
++
++	do {
++		v <<= 7;
++		v += *p & 0x7f;
++	} while (*p++ & 0x80);
++
++	return v;
++}
++
++static uint8_t *read_vblock(AVIOContext *src, uint32_t *size, uint32_t key, uint32_t *k2, int align)
++{
++	uint8_t tmp[4];
++	uint8_t *buf;
++	unsigned n;
++
++	if(avio_read(src, tmp, 4) != 4)
++        return NULL;
++
++	decode_block(tmp, tmp, 4, key, k2, align);
++
++	n = get_v(tmp);
++
++	buf = av_malloc(n);
++	if (!buf)
++		return NULL;
++
++	*size = n;
++	n -= 4;
++
++	memcpy(buf, tmp, 4);
++
++	if (avio_read(src, buf + 4, n) == n) {
++		decode_block(buf + 4, buf + 4, n, key, k2, align + 4);
++	} else {
++		av_free(buf);
++		buf = NULL;
++	}
++
++	return buf;
++}
++
++static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, uint32_t *key, int expected_size)
++{
++	uint8_t *buf;
++	uint8_t ibuf[8], sbuf[8];
++	uint32_t k2;
++	int n;
++
++	if (avio_read(src, ibuf, 8) < 8)
++		return NULL;
++
++	k2 = *key;
++	decode_block(ibuf, sbuf, 8, *key, &k2, 0);
++
++	n = get_v(sbuf+2);
++
++	if (sbuf[0] != 'S' || sbuf[1] != 'B' || (expected_size>0 && n != expected_size)) {
++        uint32_t tmpkey = recover_key(ibuf, expected_size);
++        k2 = tmpkey;
++	    decode_block(ibuf, sbuf, 8, tmpkey, &k2, 0);
++	    n = get_v(sbuf+2);
++        if(sbuf[0] != 'S' || sbuf[1] != 'B' || expected_size != n)
++            return NULL;
++        *key = tmpkey;
++	}
++
++	buf = av_malloc(n);
++	if (!buf)
++		return NULL;
++
++	memcpy(buf, sbuf, 8);
++
++	*size = n;
++	n -= 8;
++
++	if (avio_read(src, buf+8, n) < n) {
++		av_free(buf);
++		return NULL;
++	}
++
++	decode_block(buf + 8, buf + 8, n, *key, &k2, 0);
++
++	return buf;
++}
++
++static void track_header(VIV_DemuxContext *viv, AVFormatContext *s,  uint8_t *buf, int size) 
++{
++    int i,j;
++    int64_t off;
++    int val_1;
++    int num_video, num_audio;
++    AVIOContext *pb=0;
++
++    pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL);
++    //ff_get_v(pb); // track_header_len
++    ffio_read_varlen(pb); // track_header_len
++    avio_r8(pb); // '1'
++
++    //val_1 = ff_get_v(pb);
++    val_1 = ffio_read_varlen(pb);
++
++    for(i=0;i<val_1;i++) {
++        int c = avio_r8(pb);
++        for(j=0;j<c;j++) {
++            avio_r8(pb); // val_3
++            avio_r8(pb); // val_4
++        }
++    }
++
++    avio_r8(pb); // num_streams
++
++    off = avio_tell(pb);
++    //off += ff_get_v(pb); // val_5
++    off += ffio_read_varlen(pb); // val_5
++
++    avio_r8(pb); // '2'
++    num_video = avio_r8(pb);
++    
++    avio_seek(pb, off, SEEK_SET);
++    if(num_video != 1) 
++        av_log(s, AV_LOG_WARNING, "viv: number of video tracks %d is not 1\n", num_video);
++
++    for(i=0;i<num_video;i++) {
++        AVStream *st = avformat_new_stream(s, NULL);
++        AVCodecContext *vcodec = st->codec;
++
++        st->id = i;
++		
++        vcodec->codec_type = CODEC_TYPE_VIDEO;
++		vcodec->codec_id = CODEC_ID_VP6;
++
++        off = avio_tell(pb);
++        //off += ff_get_v(pb);
++        off += ffio_read_varlen(pb);
++        avio_r8(pb); // '3'
++        avio_r8(pb); // val_7
++        st->time_base.num = avio_rl32(pb); // frame_time
++        st->time_base.den = avio_rl32(pb); // time_base
++        st->nb_frames = avio_rl32(pb); // n frames
++        vcodec->width = avio_rl16(pb); // width
++        vcodec->height = avio_rl16(pb); // height
++        avio_r8(pb); // val_8
++        avio_rl32(pb); // val_9
++
++		vcodec->flags |= CODEC_FLAG_GLOBAL_HEADER; // ?
++
++        avio_seek(pb, off, SEEK_SET);
++    }
++
++    off = avio_tell(pb);
++    //off += ff_get_v(pb); // val_10
++    off += ffio_read_varlen(pb); // val_10
++    avio_r8(pb); // '4'
++    num_audio = avio_r8(pb);
++    avio_seek(pb, off, SEEK_SET);
++
++    if(num_audio != 1) 
++        av_log(s, AV_LOG_WARNING, "viv: number of audio tracks %d is not 1\n", num_audio);
++
++    for(i=0;i<num_audio;i++) {
++        int q;
++        AVStream *st = avformat_new_stream(s, NULL);
++        AVCodecContext *acodec = st->codec;
++
++        st->id = num_video + i;
++        
++        acodec->codec_type = CODEC_TYPE_AUDIO;
++		acodec->codec_id = CODEC_ID_VORBIS;
++		acodec->flags |= CODEC_FLAG_GLOBAL_HEADER; // ?
++
++        off = avio_tell(pb);
++        //off += ff_get_v(pb); // length
++        off += ffio_read_varlen(pb); // length
++        avio_r8(pb); // '5'
++        avio_r8(pb); //codec_id
++        avio_rl16(pb); //codec_subid
++        acodec->channels = avio_rl16(pb); // channels
++        acodec->sample_rate = avio_rl32(pb); // sample_rate
++        avio_seek(pb, 10, SEEK_CUR); // data_1
++        q = avio_r8(pb);
++        avio_seek(pb, q, SEEK_CUR); // data_2
++        avio_r8(pb); // zeropad
++
++        if(avio_tell(pb) < off) {
++            int num_data;
++		    int xd_size = 0;
++            int data_len[256];
++		    uint8_t * p;
++            int offset = 1;
++            //ff_get_v(pb); // val_13
++            ffio_read_varlen(pb); // val_13
++            avio_r8(pb); // '19'
++            //ff_get_v(pb); // len_3
++            ffio_read_varlen(pb); // len_3
++            num_data = avio_r8(pb);
++            for(j=0;j<num_data;j++) {
++                //data_len[j] = ff_get_v(pb);
++                data_len[j] = ffio_read_varlen(pb);
++                xd_size += data_len[j];
++            }
++		
++            acodec->extradata_size = 64 + xd_size + xd_size / 255;
++            acodec->extradata = (uint8_t*)av_mallocz(acodec->extradata_size);
++            
++            p = acodec->extradata;
++		    p[0] = 2;
++
++            for(j=0;j<num_data-1;j++)
++			    offset += av_xiphlacing(&p[offset], data_len[j]);
++
++            for(j=0;j<num_data;j++) {
++                avio_read(pb, &p[offset], data_len[j]);
++    			offset += data_len[j];
++            }
++
++		    acodec->extradata_size = offset;
++        }
++    }
++
++    av_free(pb);
++}
++
++static void track_index(VIV_DemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size)
++{
++    int i;
++    int64_t off;
++    int poff;
++    int maxnp=0;
++    AVIOContext *pb=0;
++
++    pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL);
++    //ff_get_v(pb); // track_index_len
++    ffio_read_varlen(pb); // track_index_len
++    avio_r8(pb); // 'c'
++    //viv->n_sb_blocks = ff_get_v(pb);
++    viv->n_sb_blocks = ffio_read_varlen(pb);
++    viv->sb_blocks = av_mallocz(sizeof(VIV_SB_block) * viv->n_sb_blocks);
++    if(!viv->sb_blocks) {
++        viv->n_sb_blocks = 0;
++        av_free(pb);
++        return;
++    }
++
++    off = 0;
++    poff = 0;
++
++    for(i=0;i<viv->n_sb_blocks;i++) {
++        viv->sb_blocks[i].byte_offset = off;
++        viv->sb_blocks[i].packet_offset = poff;
++
++        //viv->sb_blocks[i].size = ff_get_v(pb);
++        //viv->sb_blocks[i].n_packets = ff_get_v(pb);
++        viv->sb_blocks[i].size = ffio_read_varlen(pb);
++        viv->sb_blocks[i].n_packets = ffio_read_varlen(pb);
++
++        off += viv->sb_blocks[i].size;
++        poff += viv->sb_blocks[i].n_packets;
++
++
++        if(maxnp < viv->sb_blocks[i].n_packets)
++            maxnp = viv->sb_blocks[i].n_packets;
++    }
++
++    viv->sb_entries = av_mallocz(maxnp * sizeof(VIV_SB_entry));
++    av_free(pb);
++}
++
++static void load_sb_block(AVFormatContext *s, VIV_DemuxContext *viv, int expected_size)
++{
++    uint32_t size=0;
++    int i;
++    AVIOContext *pb = 0;
++    if(viv->sb_pb) {
++        av_free(viv->sb_pb);
++        viv->sb_pb = NULL;
++    }
++    
++    if(viv->sb_buf) 
++        av_free(viv->sb_buf);
++
++    viv->sb_buf = read_sb_block(s->pb, &size, &viv->sb_key, expected_size);
++    if(!viv->sb_buf) {
++        return;
++    }
++
++    pb = avio_alloc_context(viv->sb_buf, size, 0, NULL, NULL, NULL, NULL);
++    viv->sb_pb = pb;
++    
++    avio_r8(pb); //  'S'
++    avio_r8(pb); //  'B'
++    //ff_get_v(pb); //  size
++    ffio_read_varlen(pb); //  size
++    avio_r8(pb); //  junk
++    //ff_get_v(pb); // first packet
++    ffio_read_varlen(pb); // first packet
++
++    viv->n_sb_entries = viv->sb_blocks[viv->current_sb].n_packets;
++
++    for(i=0;i<viv->n_sb_entries;i++) {
++        //viv->sb_entries[i].size = ff_get_v(pb);
++        viv->sb_entries[i].size = ffio_read_varlen(pb);
++        viv->sb_entries[i].flag = avio_r8(pb);
++    }
++
++    //ff_get_v(pb); // 0
++    ffio_read_varlen(pb); // 0
++    avio_r8(pb); // 0
++
++    viv->current_sb_entry = 0;
++}
++
++static int viv_read_header(AVFormatContext *s,
++                            AVFormatParameters *ap)
++{
++    VIV_DemuxContext *viv = s->priv_data;
++    AVIOContext *pb = s->pb;
++    int64_t header_end;
++    int num_tracks;
++    uint32_t key, k2;
++    uint32_t v;
++    uint8_t keybuffer[187];
++    uint32_t b22_size = 0;
++	uint32_t b22_key = 0;
++    uint8_t *buf = 0;
++
++    // string "vividas03"
++    avio_seek(pb, 9, SEEK_CUR);
++
++    header_end = avio_tell(pb);
++
++    // v: header size
++    //header_end += ff_get_v(pb);
++    header_end += ffio_read_varlen(pb);
++
++    // u8: n tracks
++    num_tracks = avio_r8(pb);
++
++    if(num_tracks != 1) {
++        av_log(s, AV_LOG_ERROR, "number of tracks %d is not 1\n", num_tracks);
++        return AVERROR(EINVAL);
++    }
++
++    v = avio_r8(pb);
++    avio_seek(pb, v, SEEK_CUR);
++
++    avio_read(pb, keybuffer, 187);
++    key = decode_key(keybuffer);
++    viv->sb_key = key;
++
++    avio_rl32(pb); // track_header_len
++	
++    for(;;) {
++        int64_t here = avio_tell(pb);
++        int block_len, block_type;
++
++        if(here >= header_end)
++            break;
++
++        //block_len = ff_get_v(pb);
++        block_len = ffio_read_varlen(pb);
++        block_type = avio_r8(pb);
++
++        if(block_type == 22) {
++            avio_read(pb, keybuffer, 187);
++            b22_key = decode_key(keybuffer);
++            b22_size = avio_rl32(pb);
++        }
++
++        avio_seek(pb, here + block_len, SEEK_SET);
++    }
++
++    if(b22_size) {
++        k2 = b22_key;
++        buf = read_vblock(pb, &v, b22_key, &k2, 0);
++        if(!buf)
++            return AVERROR(EIO);
++
++        av_free(buf);
++    }
++
++    k2 = key;
++    buf = read_vblock(pb, &v, key, &k2, 0);
++    if(!buf)
++        return AVERROR(EIO);
++    track_header(viv, s, buf, v);
++    av_free(buf);
++
++    buf = read_vblock(pb, &v, key, &k2, v);
++    if(!buf)
++        return AVERROR(EIO);
++    track_index(viv, s, buf, v);
++    av_free(buf);
++
++    viv->sb_offset = avio_tell(pb);
++    if(viv->n_sb_blocks > 0) {
++        viv->current_sb = 0;
++        load_sb_block(s, viv, viv->sb_blocks[0].size);
++    } else {
++        viv->current_sb = -1;
++    }
++
++    return 0;
++}
++
++static int viv_read_packet(AVFormatContext *s,
++                           AVPacket *pkt)
++{
++    VIV_DemuxContext *viv = s->priv_data;
++    AVIOContext *pb;
++    int64_t off;
++
++    if(viv->current_audio_subpacket < viv->n_audio_subpackets) {
++        // audio packets
++        AVStream *astream;
++        int size = viv->audio_subpackets[viv->current_audio_subpacket+1].start - viv->audio_subpackets[viv->current_audio_subpacket].start;
++        pb = viv->sb_pb;
++        av_get_packet(pb, pkt, size);
++        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
++
++        pkt->stream_index = 1;
++        astream = s->streams[pkt->stream_index];
++
++        pkt->pts = viv->audio_sample * (long long)astream->time_base.den / (long long)astream->time_base.num / (long long)astream->codec->sample_rate;
++        viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codec->channels;
++        pkt->flags |= AV_PKT_FLAG_KEY;
++        viv->current_audio_subpacket++;
++        return 0;
++    }
++
++    if(viv->current_sb_entry >= viv->n_sb_entries) {
++        if(viv->current_sb+1 >= viv->n_sb_blocks)
++            return AVERROR(EIO);
++        viv->current_sb++;
++
++        load_sb_block(s, viv, 0);
++        viv->current_sb_entry = 0;
++    }
++   
++    pb = viv->sb_pb;
++    off = avio_tell(pb);
++    off += viv->sb_entries[viv->current_sb_entry].size;
++
++    if(viv->sb_entries[viv->current_sb_entry].flag == 0) {
++        // A/V packet
++        int i;
++        //int v_size = ff_get_v(pb);
++        int v_size = ffio_read_varlen(pb);
++        ///*int a_size = */ff_get_v(pb);
++        /*int a_size = */ffio_read_varlen(pb);
++        av_get_packet(pb, pkt, v_size);
++        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
++     
++        pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry;
++        pkt->flags |= (pkt->data[0]&0x80)?0:AV_PKT_FLAG_KEY;
++        pkt->stream_index = 0;
++
++        for(i=0;i<MAX_AUDIO_SUBPACKETS-1;i++) {
++            int start, pcm_bytes;
++            //start = ff_get_v(pb);
++            //pcm_bytes = ff_get_v(pb);
++            start = ffio_read_varlen(pb);
++            pcm_bytes = ffio_read_varlen(pb);
++
++            if(i > 0 && start == 0)
++                break;
++
++            viv->n_audio_subpackets = i+1;
++            viv->audio_subpackets[i].start = start;
++            viv->audio_subpackets[i].pcm_bytes = pcm_bytes;
++        }
++        viv->audio_subpackets[viv->n_audio_subpackets].start = (int)(off - avio_tell(pb));
++        viv->current_audio_subpacket = 0;
++        //viv->n_audio_subpackets = 0;
++        //avio_seek(pb, off, SEEK_SET);
++        
++    } else {
++        // V packet
++        //int v_size = ff_get_v(pb);
++        int v_size = ffio_read_varlen(pb);
++        av_get_packet(pb, pkt, v_size);
++        pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset;
++        pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry;
++        pkt->flags |= (pkt->data[0]&0x80)?0:AV_PKT_FLAG_KEY;
++        pkt->stream_index = 0;
++    }
++
++    viv->current_sb_entry++;
++
++//    avio_seek(pb, off, SEEK_SET);
++
++    return 0;
++}
++
++static int viv_read_close(AVFormatContext *s)
++{
++    VIV_DemuxContext *viv = s->priv_data;
++    if(viv->sb_pb) 
++        av_free(viv->sb_pb);
++    
++    if(viv->sb_buf) 
++        av_free(viv->sb_buf);
++
++    if(viv->sb_blocks)
++        av_free(viv->sb_blocks);
++   
++    if(viv->sb_entries)
++        av_free(viv->sb_entries);
++
++    return 0;
++}
++
++static int viv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
++{
++    VIV_DemuxContext *viv = s->priv_data;
++    int frame = 0;
++    int i;
++
++    if(stream_index == 0) 
++        frame = (int)timestamp;
++    else 
++        frame = (int)timestamp * s->streams[stream_index]->time_base.den * s->streams[0]->time_base.num / s->streams[stream_index]->time_base.num / s->streams[0]->time_base.den;
++
++    for(i=0;i<viv->n_sb_blocks;i++) {
++        if(frame >= viv->sb_blocks[i].packet_offset && frame < viv->sb_blocks[i].packet_offset + viv->sb_blocks[i].n_packets) {
++            // flush audio packet queue
++            viv->current_audio_subpacket = 0;
++            viv->n_audio_subpackets = 0;
++            viv->current_sb = i;
++            // seek to ith sb block
++            avio_seek(s->pb, viv->sb_offset + viv->sb_blocks[i].byte_offset, SEEK_SET);
++            // load the block
++            load_sb_block(s, viv, 0);
++            // most problematic part: guess audio offset
++            viv->audio_sample = (int64_t)viv->sb_blocks[i].packet_offset * (int64_t)s->streams[1]->codec->sample_rate * s->streams[0]->time_base.num / s->streams[0]->time_base.den;
++            // hand-tuned 1.3s a/v offset
++            viv->audio_sample += 1300 * s->streams[1]->codec->sample_rate / 1000;
++            viv->current_sb_entry = 0;
++            return 1;
++        }
++    }
++    return 0;
++}
++
++AVInputFormat ff_vividas_demuxer = {
++    "vividas",
++    "Vividas VIV format",
++    sizeof(VIV_DemuxContext),
++    viv_probe,
++    viv_read_header,
++    viv_read_packet,
++    viv_read_close,
++    viv_read_seek
++};
++
-- 
1.7.9.5

