diff -Naur ffmpeg-1.0.3.old/libavformat/allformats.c ffmpeg-1.0.3/libavformat/allformats.c --- ffmpeg-1.0.3.old/libavformat/allformats.c 2013-01-31 13:25:30.076977988 +0100 +++ ffmpeg-1.0.3/libavformat/allformats.c 2013-01-31 13:26:27.280976325 +0100 @@ -245,6 +245,7 @@ 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 -Naur ffmpeg-1.0.3.old/libavformat/Makefile ffmpeg-1.0.3/libavformat/Makefile --- ffmpeg-1.0.3.old/libavformat/Makefile 2013-01-31 13:25:30.063977989 +0100 +++ ffmpeg-1.0.3/libavformat/Makefile 2013-01-31 13:26:55.569975502 +0100 @@ -344,6 +344,7 @@ 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 -Naur ffmpeg-1.0.3.old/libavformat/vividas.c ffmpeg-1.0.3/libavformat/vividas.c --- ffmpeg-1.0.3.old/libavformat/vividas.c 1970-01-01 01:00:00.000000000 +0100 +++ ffmpeg-1.0.3/libavformat/vividas.c 2013-01-31 13:28:01.641973581 +0100 @@ -0,0 +1,739 @@ +/* + * 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 + */ + +#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; +} + +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 + avio_r8(pb); // '1' + + //val_1 = ff_get_v(pb); + val_1 = ffio_read_varlen(pb); + + for(i=0;icodec; + + 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;icodec; + + 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;jextradata_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;jextradata_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;in_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;in_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) +{ + 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 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;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 * (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 = { + .name = "vividas", + .long_name = NULL_IF_CONFIG_SMALL("Vividas VIV format"), + .priv_data_size = sizeof(VIV_DemuxContext), + .read_probe = viv_probe, + .read_header = viv_read_header, + .read_packet = viv_read_packet, + .read_close = viv_read_close, + .read_seek = viv_read_seek +};