From patchwork Mon Dec 10 12:05:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 11360 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 3FB1944D5BE for ; Mon, 10 Dec 2018 14:05:25 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8734A68AB1F; Mon, 10 Dec 2018 14:05:15 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f68.google.com (mail-wm1-f68.google.com [209.85.128.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EC8E368AAD3 for ; Mon, 10 Dec 2018 14:05:08 +0200 (EET) Received: by mail-wm1-f68.google.com with SMTP id y139so10596467wmc.5 for ; Mon, 10 Dec 2018 04:05:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Q+rGKe1QcOcWRT6b4gcdNxb1u0Q0A7YLLGyx+WQTbWY=; b=BwkjGj8TuNzgJv7aRXbUqAewUidcWp9DsIuk4PEO5dGK7tJnK5Nj385mptEBkb9TMv WMf2b9oeETj8zWxGnQwJ/umUxuF7x1xbXwJviG2+DSHmFUobiqGtQUiNS1n4dErSlQfN 90e6yaWS+TuO2yAiHCLj1hWenGKp64QXlcHeu/FfQEmdKKn/XHZtnOh1ec+SZmI4NJSm Nq1/Jy9UBTPF2VLdaLPQus7YQD9pWgzlc7W0Txr3+anByYsYi/41kF9gmhLERfFPb8aR DP8QJeelJu1XLT6kybl2UMTa1XNDJ+4nxCu+62fmQcFzyKaCnRaB0hyfhi7WjKB0JVvj XbuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Q+rGKe1QcOcWRT6b4gcdNxb1u0Q0A7YLLGyx+WQTbWY=; b=EXahy8FA6KN6R8sT6Z9BWRWcrjcUkoR/1dbPtqUheG1lbB6luvpkqqtlyNQxrnNHP/ opwupPjuTfyqO7xmyFd77CNUKlAySRxqVqBFZ0OqXbg8GtTN9R4GjQ5NhvIh5rbFtIZQ /8hwll8UjmcKyHdQXGFnuKNLuKDqmiTLVFmg8nWEQGy+9/uEY9lI/HApOFUOBnTTKa08 73En4uw6ltION4z2RMpkoXO20IuVA/tvhkFTg2u/mCh2Vm2Z57ZnORFcIKjAn6awu8Xs qXxp/SGT0sQpclggfNl+WvmSCqN5epjgM2icL5DA46jqY/vAtsz4Eag+DagU2WjEZxLN yYlw== X-Gm-Message-State: AA+aEWbu3xF1zrV0kNnK8i5VHXlSd0ZjZ13pZoTSDY7k5lnWa68ztfoi 8WNvtmR2nZlRrFuhte18nVhqtJsB X-Google-Smtp-Source: AFSGD/UOMvVrp+jUeukXlIvvm0ThVKhqd6gDTv1+nawI85LW5P1NCcTEeX0X36Z6hWRpir/5BrUHlg== X-Received: by 2002:a1c:8851:: with SMTP id k78mr10596144wmd.51.1544443518906; Mon, 10 Dec 2018 04:05:18 -0800 (PST) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id f192sm12081657wmd.12.2018.12.10.04.05.17 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Dec 2018 04:05:18 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Mon, 10 Dec 2018 13:05:05 +0100 Message-Id: <20181210120505.6387-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat: add vividas demuxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/vividas.c | 708 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 710 insertions(+) create mode 100644 libavformat/vividas.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 0e43a12df5..c42ceb40c5 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -522,6 +522,7 @@ OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o vc1dec.o OBJS-$(CONFIG_VC1_MUXER) += rawenc.o OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o +OBJS-$(CONFIG_VIVIDAS_DEMUXER) += vividas.o OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o OBJS-$(CONFIG_VOBSUB_DEMUXER) += subtitles.o # mpeg demuxer is in the dependencies diff --git a/libavformat/allformats.c b/libavformat/allformats.c index df83b04484..399625fd78 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -422,6 +422,7 @@ extern AVInputFormat ff_vc1_demuxer; extern AVOutputFormat ff_vc1_muxer; extern AVInputFormat ff_vc1t_demuxer; extern AVOutputFormat ff_vc1t_muxer; +extern AVInputFormat ff_vividas_demuxer; extern AVInputFormat ff_vivo_demuxer; extern AVInputFormat ff_vmd_demuxer; extern AVInputFormat ff_vobsub_demuxer; diff --git a/libavformat/vividas.c b/libavformat/vividas.c new file mode 100644 index 0000000000..86748dd780 --- /dev/null +++ b/libavformat/vividas.c @@ -0,0 +1,708 @@ +/* + * Vividas VIV format Demuxer + * Copyright (c) 2012 Krzysztof Klinikowski + * 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 + */ + +#include "libavutil/intreadwrite.h" +#include "avio_internal.h" +#include "avformat.h" + +#define MAX_AUDIO_SUBPACKETS 100 + +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 VividasDemuxContext { + 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]; +} VividasDemuxContext; + +static int viv_probe(AVProbeData *p) +{ + if (memcmp(p->buf, "vividas03", 9)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static 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; +} + +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(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size) +{ + int i,j; + int64_t off; + int val_1; + int num_video, num_audio; + AVIOContext *pb; + + pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return; + + ffio_read_varlen(pb); // track_header_len + avio_r8(pb); // '1' + + val_1 = ffio_read_varlen(pb); + + for (i=0;iid = i; + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_VP6; + + off = avio_tell(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 + st->codecpar->width = avio_rl16(pb); // width + st->codecpar->height = avio_rl16(pb); // height + avio_r8(pb); // val_8 + avio_rl32(pb); // val_9 + + avio_seek(pb, off, SEEK_SET); + } + + off = avio_tell(pb); + 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, "number of audio tracks %d is not 1\n", num_audio); + + for(i=0;iid = num_video + i; + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_VORBIS; + + off = avio_tell(pb); + off += ffio_read_varlen(pb); // length + avio_r8(pb); // '5' + avio_r8(pb); //codec_id + avio_rl16(pb); //codec_subid + st->codecpar->channels = avio_rl16(pb); // channels + st->codecpar->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; + ffio_read_varlen(pb); // val_13 + avio_r8(pb); // '19' + ffio_read_varlen(pb); // len_3 + num_data = avio_r8(pb); + for(j=0;jcodecpar->extradata_size = 64 + xd_size + xd_size / 255; + st->codecpar->extradata = (uint8_t*)av_mallocz(st->codecpar->extradata_size); + + p = st->codecpar->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]; + } + + st->codecpar->extradata_size = offset; + } + } + + av_free(pb); +} + +static void track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size) +{ + int i; + int64_t off; + int poff; + int maxnp=0; + AVIOContext *pb; + + pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return; + + ffio_read_varlen(pb); // track_index_len + avio_r8(pb); // 'c' + 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 = 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, VividasDemuxContext *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); + if (!pb) + return; + + viv->sb_pb = pb; + + avio_r8(pb); // 'S' + avio_r8(pb); // 'B' + ffio_read_varlen(pb); // size + avio_r8(pb); // junk + 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 = ffio_read_varlen(pb); + viv->sb_entries[i].flag = avio_r8(pb); + } + + ffio_read_varlen(pb); + avio_r8(pb); + + viv->current_sb_entry = 0; +} + +static int viv_read_header(AVFormatContext *s) +{ + VividasDemuxContext *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; + + avio_skip(pb, 9); + + header_end = avio_tell(pb); + + header_end += ffio_read_varlen(pb); + + 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); + + for (;;) { + int64_t here = avio_tell(pb); + int block_len, block_type; + + if (here >= header_end) + break; + + 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) +{ + VividasDemuxContext *viv = s->priv_data; + AVIOContext *pb; + int64_t off; + + if (avio_feof(viv->sb_pb)) + return AVERROR_EOF; + + if (viv->current_audio_subpacket < viv->n_audio_subpackets) { + 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 = av_rescale(viv->audio_sample, astream->time_base.den, astream->time_base.num) / astream->codecpar->sample_rate; + viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codecpar->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) { + int i, v_size = ffio_read_varlen(pb); + 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 = 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 { + 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) +{ + VividasDemuxContext *viv = s->priv_data; + + av_freep(&viv->sb_pb); + av_freep(&viv->sb_buf); + av_freep(&viv->sb_blocks); + av_freep(&viv->sb_entries); + + return 0; +} + +static int viv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +{ + VividasDemuxContext *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;in_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 * av_rescale(s->streams[1]->codecpar->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]->codecpar->sample_rate / 1000; + viv->current_sb_entry = 0; + return 1; + } + } + return 0; +} + +AVInputFormat ff_vividas_demuxer = { + .name = "vividas", + .long_name = NULL_IF_CONFIG_SMALL("Vividas VIV"), + .priv_data_size = sizeof(VividasDemuxContext), + .read_probe = viv_probe, + .read_header = viv_read_header, + .read_packet = viv_read_packet, + .read_close = viv_read_close, + .read_seek = viv_read_seek, + .flags = AVFMT_GLOBALHEADER, +};