Created
September 23, 2012 13:31
-
-
Save kkszysiu/3770979 to your computer and use it in GitHub Desktop.
Vividas demuxer which is compiling with FFmpeg 0.11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
*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) | |
{ | |
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 = { | |
.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 | |
}; |
powinno działać, gdyż tyle co sprawdziłem z wersją 1.0.3 i funkcjonuje poprawnie. Panowie nie myślicie by spróbować ten kod dodać to samego ffmpeg przez ich mailistę czy inne sposób w jaki przyjmują patche?
Patch do wersji 1.0.3
http://pastebin.com/9bwHUJF2
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Czy to działa z ffmpeg 1:1.0.1? Pierwszy raz zmieniam cokolwiek w ffmpeg i nie mogę dojść z tym do ładu niestety...
Dodałem powyższą zawartość do pliku vividas.c w katalogu libavformat, dopisałem też w tamtejszym Makefile do OBJS wpis vividas.o. Wydaje się, że rekompilacja zadziałała - plik vividas.o powstał oraz miałem info, że przegenerowane zostało kilka libów (w tym libavformat.so).
Ale wywołanie "ffmpeg -formats" nie pokazuje mi wcale vividas jako obsługiwanego no i oczywiście nie mogę otwierać plików .viv. Sprawdziłem przy pomocy narzędzia ldd, że uruchamiany ffmpeg na pewno korzysta z nowoskompilowanych bibliotek, a nie z systemowych.
Co jeszcze mógłbym sprawdzić?
Z góry dzięki za pomoc!
tzok