https://wiki.multimedia.cx/api.php?action=feedcontributions&user=Anszom&feedformat=atomMultimediaWiki - User contributions [en]2024-03-29T15:10:17ZUser contributionsMediaWiki 1.39.5https://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12798Vividas VIV2010-07-05T20:35:27Z<p>Anszom: /* Tools */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv] [http://video.vividas.com/CDN2/samples/HighDef/4820_CasinoRoyale/viv/casinoHD_1305.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<br />
;Note: for some .viv files (like the ones used in the polish VOD service [http://iplex.pl iplex]) the key used to encrypt SB blocks is different from the track key, it is received from the server at runtime in an unknown form. It can however be recovered from the .viv file with a simple known-plaintext attack. We know that the first bytes after the track index will begin with "SB" followed by the size of the first SB block (available in the track index). By XOR-ing the expected first four bytes with the encrypted 4 bytes from the viv file, we recover the "secret" SB key.<br />
<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
start_of_packet[i] v<br />
uncompressed_size[i] v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(start_of_packet[i+1] - start_of_packet[i])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
;uncompressed_size : the size (in bytes) of raw PCM samples produced from this audio packet after decompression<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
<br />
It seems that always the first chunk of a SB block is a keyframe, the others are not. A more reliable method to find the keyframes is to test the MSB of the first byte of a VP6-encoded packet - the bit is set for non-keyframes and cleared for keyframes.<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
FFmpeg demuxer based on the above code is available [http://kuku.eu.org/vividas.c here].<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12748Vividas VIV2010-06-27T16:11:16Z<p>Anszom: one more sample file</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv] [http://video.vividas.com/CDN2/samples/HighDef/4820_CasinoRoyale/viv/casinoHD_1305.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<br />
;Note: for some .viv files (like the ones used in the polish VOD service [http://iplex.pl iplex]) the key used to encrypt SB blocks is different from the track key, it is received from the server at runtime in an unknown form. It can however be recovered from the .viv file with a simple known-plaintext attack. We know that the first bytes after the track index will begin with "SB" followed by the size of the first SB block (available in the track index). By XOR-ing the expected first four bytes with the encrypted 4 bytes from the viv file, we recover the "secret" SB key.<br />
<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
start_of_packet[i] v<br />
uncompressed_size[i] v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(start_of_packet[i+1] - start_of_packet[i])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
;uncompressed_size : the size (in bytes) of raw PCM samples produced from this audio packet after decompression<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
<br />
It seems that always the first chunk of a SB block is a keyframe, the others are not. A more reliable method to find the keyframes is to test the MSB of the first byte of a VP6-encoded packet - the bit is set for non-keyframes and cleared for keyframes.<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12747Vividas VIV2010-06-26T20:34:41Z<p>Anszom: /* "SB" Block */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<br />
;Note: for some .viv files (like the ones used in the polish VOD service [http://iplex.pl iplex]) the key used to encrypt SB blocks is different from the track key, it is received from the server at runtime in an unknown form. It can however be recovered from the .viv file with a simple known-plaintext attack. We know that the first bytes after the track index will begin with "SB" followed by the size of the first SB block (available in the track index). By XOR-ing the expected first four bytes with the encrypted 4 bytes from the viv file, we recover the "secret" SB key.<br />
<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
start_of_packet[i] v<br />
uncompressed_size[i] v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(start_of_packet[i+1] - start_of_packet[i])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
;uncompressed_size : the size (in bytes) of raw PCM samples produced from this audio packet after decompression<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
<br />
It seems that always the first chunk of a SB block is a keyframe, the others are not. A more reliable method to find the keyframes is to test the MSB of the first byte of a VP6-encoded packet - the bit is set for non-keyframes and cleared for keyframes.<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12744Vividas VIV2010-06-26T13:57:00Z<p>Anszom: /* "SB" Block */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<br />
;Note: for some .viv files (like the ones used in the polish VOD service [http://iplex.pl iplex]) the key used to encrypt SB blocks is different from the track key, it is received from the server at runtime in an unknown form. It can however be recovered from the .viv file with a simple known-plaintext attack. We know that the first bytes after the track index will begin with "SB" followed by the size of the first SB block (available in the track index). By XOR-ing the expected first four bytes with the encrypted 4 bytes from the viv file, we recover the "secret" SB key.<br />
<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet<br />
<br />
It seems that always the first chunk of a SB block is a keyframe, the others are not. A more reliable method to find the keyframes is to test the MSB of the first byte of a VP6-encoded packet - the bit is set for non-keyframes and cleared for keyframes.<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12740Vividas VIV2010-06-24T21:39:15Z<p>Anszom: /* "SB" Block */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<br />
;Note: for some .viv files (like the ones used in the polish VOD service [http://iplex.pl iplex]) the key used to encrypt SB blocks is different from the track key, it is received from the server at runtime in an unknown form. It can however be recovered from the .viv file with a simple known-plaintext attack. We know that the first bytes after the track index will begin with "SB" followed by the size of the first SB block (available in the track index). By XOR-ing the expected first four bytes with the encrypted 4 bytes from the viv file, we recover the "secret" SB key.<br />
<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always a keyframe?)<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always non-keyframe?)<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12739Vividas VIV2010-06-24T21:30:31Z<p>Anszom: added a working link to sample video file</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD] [http://www.iupui.edu/~nmstream/hd/vividas/4000/nz4000.viv]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always a keyframe?)<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always non-keyframe?)<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12738Vividas VIV2010-06-24T21:27:53Z<p>Anszom: /* "SB" Block */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
for(int i=0;i<n_packets;i++)<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always a keyframe?)<br />
;audio_data : multiple Vorbis(or speex?)-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always non-keyframe?)<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12737Vividas VIV2010-06-24T21:26:01Z<p>Anszom: /* Track Header */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data[i] d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
;data[i] : Vorbis (or speex?) header packets<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always a keyframe?)<br />
;audio_data : multiple Vorbis-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always non-keyframe?)<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszomhttps://wiki.multimedia.cx/index.php?title=Vividas_VIV&diff=12736Vividas VIV2010-06-24T21:24:39Z<p>Anszom: /* "SB" Block */</p>
<hr />
<div>* Extension: viv<br />
* MIME type: video/vividas<br />
* Company: [http://www.vividas.com/ Vividas Pty Ltd]<br />
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD]<br />
<br />
==Overview==<br />
A Vividas file consists of one or more "tracks", each comprising one or more audio<br />
and/or video elementary streams.<br />
<br />
==Encryption==<br />
All data relating to a track is encoded using a 32-bit key given in<br />
obfuscated form in the file header.<br />
<br />
===Keys===<br />
The header contains, for each track, a 187-byte block, 32 bits of<br />
which form the key. The following C function will extract a key<br />
from such a block.<br />
<br />
<pre><nowiki><br />
const unsigned short keybits[32] = {<br />
163, 416, 893, 82, 223, 572, 1137, 430,<br />
659, 1104, 13, 626, 695, 972, 1465, 686,<br />
843, 1216, 317, 1122, 1383, 92, 513, 1158,<br />
1243, 48, 573, 1306, 1495, 396, 1009, 350,<br />
};<br />
<br />
uint32_t decode_key(uint8_t *buf)<br />
{<br />
uint32_t key = 0;<br />
int i;<br />
<br />
for (i = 0; i < 32; i++) {<br />
unsigned p = keybits[i];<br />
key |= !!(buf[p>>3] & (1<<(p&7))) << i;<br />
}<br />
<br />
return key;<br />
}<br />
</nowiki></pre><br />
<br />
===Decoding===<br />
To decode a data block with a given key, this C function can be used:<br />
<br />
<pre><nowiki><br />
void decode(uint32_t *d, unsigned size, uint32_t key)<br />
{<br />
uint32_t k = key;<br />
<br />
size >>= 2;<br />
<br />
while (size--) {<br />
*d++ ^= k;<br />
k += key;<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
==File Format==<br />
<br />
===Data Types===<br />
The following data types are used in the syntax description below.<br />
;u(n) : n-byte unsigned little endian integer.<br />
;v : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.<br />
;a(n) : n-byte ASCII string.<br />
;z : NUL-terminated ASCII string.<br />
;d(n) : n bytes unspecified data.<br />
;'x' : Literal byte with hex value <code>x</code>.<br />
;"s" : Literal ASCII string.<br />
<br />
===Overall Structure===<br />
<pre><nowiki><br />
vividas_file() {<br />
signature a(7)<br />
version a(2)<br />
file_header()<br />
if (skin_size > 0) {<br />
skin()<br />
}<br />
for (i = 0; i < num_tracks; i++) {<br />
reset_key()<br />
track_header()<br />
track_index()<br />
}<br />
for (;;) {<br />
reset_key()<br />
sb_block()<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;signature : The string <code>vividas</code>.<br />
;version : File version as two decimal digits. All known samples have the value <code>03</code>.<br />
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.<br />
;reset_key() : The decoding key is reset to the value from the file_header.<br />
<br />
===File Header===<br />
<pre><nowiki><br />
file_header() {<br />
header_length v<br />
num_tracks u(1)<br />
for (i = 0; i < num_tracks; i++) {<br />
title_length u(1)<br />
track_title a(title_length)<br />
track_key d(187)<br />
track_header_length d(4)<br />
}<br />
for (;;) {<br />
block_length v<br />
block_type u(1)<br />
if (block_type == 15) {<br />
key d(187)<br />
for (;;) {<br />
descriptor()<br />
}<br />
} else if (block_type == 22) {<br />
skin_key d(187)<br />
skin_size d(4)<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;header_length : Total length of the <code>file_header</code> element in bytes.<br />
;num_tracks : Number of tracks in the file.<br />
;title_length : Number of bytes in the immediately following title.<br />
;track_title : Title of track <code>i</code>.<br />
;track_key : Scrambled key for track <code>i</code>.<br />
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.<br />
;block_length : Size in bytes of the following block, including this field.<br />
<br />
===Skin===<br />
<pre><nowiki><br />
skin() {<br />
length v<br />
'd' u(1)<br />
for (;;) { <br />
size v<br />
tag u(1)<br />
data d(size)<br />
} <br />
}<br />
</nowiki></pre><br />
<br />
;length : Total size of skin data including length field.<br />
;size : Size of data chunk.<br />
;tag : Unique identifier for data chunk.<br />
;data : XML or JPEG data.<br />
<br />
===Track Header===<br />
<pre><nowiki><br />
track_header() {<br />
track_header_length v<br />
'1' u(1)<br />
val_1 u(1)<br />
for (i = 0; i < val_1; i++) {<br />
val_2 u(1)<br />
for (j = 0; j < val_2; j++) {<br />
val_3 u(1)<br />
val_4 u(1)<br />
}<br />
}<br />
num_streams u(1)<br />
size_1 v<br />
'2' u(1)<br />
num_video u(1)<br />
def_video u(1)<br />
for (i = 0; i < num_video; i++) {<br />
length v<br />
'3' u(1)<br />
val_7 u(1)<br />
frame_rate_den u(4)<br />
frame_rate_num u(4)<br />
num_frames u(4)<br />
width u(2)<br />
height u(2)<br />
val_8 u(1)<br />
val_9 u(4)<br />
}<br />
size_2 v<br />
'4' u(1)<br />
num_audio u(1)<br />
def_audio u(1)<br />
for (i = 0; i < num_audio; i++) {<br />
length v<br />
'5' u(1)<br />
codec_id u(1)<br />
codec_subid u(2)<br />
channels u(2)<br />
sample_rate u(4)<br />
data_1 d(10)<br />
len_2 u(1)<br />
data_2 d(len_2)<br />
junk d(1)<br />
val_13 v<br />
'19' u(1)<br />
len_3 v<br />
num_data u(1)<br />
for (i = 0; i < num_data; i++) {<br />
data_len[i] v<br />
}<br />
for (i = 0; i < num_data; i++) {<br />
data d(data_len[i])<br />
}<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;track_header_length : Length in bytes of track header including this field. Matches element of same name in file_header.<br />
;num_streams : Number of elementary streams in track.<br />
;size_1 : Number of bytes preceding video streams loop, including this field.<br />
;num_video : Number of video streams.<br />
;def_video_stream : Default video stream number.<br />
;size_2 : Number of bytes preceding audio streams loop, including this field.<br />
;num_audio : Number of audio streams.<br />
;def_audio_stream : Default audio stream number.<br />
<br />
===Track Index===<br />
<pre><nowiki><br />
track_index() {<br />
length v<br />
'c' u(1)<br />
num_sb_blocks v<br />
for (i = 0; i < count; i++) {<br />
size v<br />
num_chunks v<br />
}<br />
}<br />
</nowiki></pre><br />
<br />
;length : Length in bytes of track index.<br />
;num_sb_blocks : Number of entries in following table.<br />
;size : Size of a block.<br />
;num_chunks : Number of chunks in block.<br />
<br />
==="SB" Block===<br />
<pre><nowiki><br />
sb_block() {<br />
"SB" a(2)<br />
size v<br />
junk d(1)<br />
start_chunk v<br />
do {<br />
chunk_size v<br />
flag u(1)<br />
} while (chunk_size != 0)<br />
}<br />
</nowiki></pre><br />
<br />
;size : Total size of this block.<br />
<br />
The chunks for which <code>flag</code> is 0 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
video_length v<br />
audio_length v<br />
video_data d(video_length)<br />
do {<br />
end_of_packet[i] v<br />
unknown v<br />
} while(end_of_packet != 0)<br />
<br />
audio_data[i] d(end_of_packet[i] - end_of_packet[i-1])<br />
<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always a keyframe?)<br />
;audio_data : multiple Vorbis-encoded audio packets<br />
<br />
The chunks for which <code>flag</code> is 1 have the following structure:<br />
<br />
<pre><nowiki><br />
chunk_1() {<br />
length v<br />
video_data d(length)<br />
}<br />
</nowiki></pre><br />
<br />
;video_data : VP6-encoded video packet (always non-keyframe?)<br />
<br />
==Tools==<br />
A decrypter and parser is available from git://git.mansr.com/vividas (gitweb http://git.mansr.com/?p=vividas).<br />
<br />
==External Resources==<br />
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].<br />
<br />
[http://www.on2.com/company/news-room/press-releases/?id=254 "Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video"] January 13th, 2005<br />
<br />
[http://web.archive.org/web/20071213111002/http://www.vividas.com/footer/opensource.html Vividas - Open Source Acknowledgement]<br />
[[Category:Container Formats]]</div>Anszom