Difference between revisions of "Vividas VIV"

From MultimediaWiki
Jump to navigation Jump to search
(Much improved description of file format)
Line 4: Line 4:
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD]
* Samples: [http://video.vividas.com/sales/Honda_CRV_TVC_sales_048i.viv TBD]


VIV is a proprietary web audio/video streaming format used by the Vividas Player. The player, available for Win32, Mac OSX and Sun platforms, is distributed as native binary and installed on-demand via Java or ActiveX.
==Overview==
A Vividas file consists of one or more "tracks", each comprising one or more audio
and/or video elementary streams.


Developer blog: "Vividas is the company behind 'Vividas Player' (Suprise!) which is a video streaming platform (powered by VP6/VP7) which is very much like (to dumb things down) quicktime or Windows Media Player for streaming content, only with a twist. Its ultra fast, compact, installation-requiremente-requireded-no and very bandwidth efficient... The decoder - written in C/C++ with a healthy mix of ASM - is around 250-300Kb. Most of the internals is hush hush so I cant reveal much, but what is interesting is the uptake of broadband across the globe and the future prospects of HD-Quality video streaming and where this technology is headed" [http://blogs.developerfusion.co.uk/blogs/thushan/archive/2005/08/11/821.aspx]
==Encryption==
All data relating to a track is encoded using a 32-bit key given in
obfuscated form in the file header.


Actually the decoder is a 800kb DLL.
===Keys===
The header contains, for each track, a 187-byte block, 32 bits of
which form the key.  The following C function will extract a key
from such a block.


The player has support for Speex, Vorbis and VP6.
<pre><nowiki>
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,
};


Layout of the file:
uint32_t decode_key(uint8_t *buf)
{| border="1" cellpadding="5" style="border-collapse: collapse; border-style: dashed; border-color: #2f6fab;"
{
|- bgcolor="#f0f0f0" |
    uint32_t key = 0;
! Size !! Meaning !! Default value
    int i;
|-
|9 bytes || Magic || "vividas03"
|-
|1 byte || Unknown || 84 or 85 in most files
|-
|1 byte || Unknown || 20, 62, 65 in most files
|-
|1 byte || Unknown || Always 1 ?
|-
|1 byte || Length of name field
|-
|x bytes || Name field
|-
| || Encrypted data here
|}


Altought data is encrypted, an index table is recognizable just after the header.
    for (i = 0; i < 32; i++) {
        unsigned p = keybits[i];
        key |= !!(buf[p>>3] & (1<<(p&7))) << i;
    }


===External Resources===
    return key;
}
</nowiki></pre>
 
===Decoding===
To decode a data block with a given key, this C function can be used:
 
<pre><nowiki>
void decode(uint32_t *d, unsigned size, uint32_t key)
{
    uint32_t k = key;
 
    size >>= 2;
 
    while (size--) {
        *d++ ^= k;
        k += key;
    }
}
</nowiki></pre>
 
==File Format==
 
===Data Types===
The following data types are used in the syntax description below.
;u(n) : n-byte unsigned little endian integer.
;v    : Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.
;a(n) : n-byte ASCII string.
;z    : NUL-terminated ASCII string.
;d(n) : n bytes unspecified data.
;'x'  : Literal byte with hex value <code>x</code>.
;"s"  : Literal ASCII string.
 
===Overall Structure===
<pre><nowiki>
vividas_file() {
    signature                          a(7)
    version                            a(2)
    file_header()
    if (skin_size > 0) {
        skin()
    }
    for (i = 0; i < num_tracks; i++) {
        reset_key()
        track_header()
        track_index()
    }
    for (;;) {
        reset_key()
        sb_block()
    }
}
</nowiki></pre>
 
;signature    : The string <code>vividas</code>.
;version      : File version as two decimal digits.  All known samples have the value <code>03</code>.
;file_header() : Sets <code>skin_size</code> and <code>num_tracks</code>.
;reset_key()  : The decoding key is reset to the value from the file_header.
 
===File Header===
<pre><nowiki>
file_header() {
    header_length                      v
    num_tracks                          u(1)
    for (i = 0; i < num_tracks; i++) {
        title_length                    u(1)
        track_title                    a(title_length)
        track_key                      d(187)
        track_header_length            d(4)
    }
    for (;;) {
        block_length                    v
        block_type                      u(1)
        if (block_type == 15) {
            key                        d(187)
            for (;;) {
                descriptor()
            }
        } else if (block_type == 22) {
            skin_key                    d(187)
            skin_size                  d(4)
        }
    }
}
</nowiki></pre>
 
;header_length      : Total length of the <code>file_header</code> element in bytes.
;num_tracks          : Number of tracks in the file.
;title_length        : Number of bytes in the immediately following title.
;track_title        : Title of track <code>i</code>.
;track_key          : Scrambled key for track <code>i</code>.
;track_header_length : Total size in bytes of track_header and track_index for track <code>i</code>.
;block_length        : Size in bytes of the following block, including this field.
 
===Skin===
<pre><nowiki>
skin() {
    length                              v
    'd'                                u(1)
    for (;;) {   
        size                            v
        tag                            u(1)
        data                            d(size)
    }           
}
</nowiki></pre>
 
;length : Total size of skin data including length field.
;size  : Size of data chunk.
;tag    : Unique identifier for data chunk.
;data  : XML or JPEG data.
 
===Track Header===
<pre><nowiki>
track_header() {
    track_header_length                v
    '1'                                u(1)
    val_1                              u(1)
    for (i = 0; i < val_1; i++) {
        val_2                          u(1)
        for (j = 0; j < val_2; j++) {
            val_3                      u(1)
            val_4                      u(1)
        }
    }
    num_streams                        u(1)
    size_1                              v
    '2'                                u(1)
    num_video                          u(1)
    def_video                          u(1)
    for (i = 0; i < num_video; i++) {
        length                          v
        '3'                            u(1)
        val_7                          u(1)
        frame_rate_den                  u(4)
        frame_rate_num                  u(4)
        num_frames                      u(4)
        width                          u(2)
        height                          u(2)
        val_8                          u(1)
        val_9                          u(4)
    }
    size_2                              v
    '4'                                u(1)
    num_audio                          u(1)
    def_audio                          u(1)
    for (i = 0; i < num_audio; i++) {
        length                          v
        '5'                            u(1)
        codec_id                        u(1)
        codec_subid                    u(2)
        channels                        u(2)
        sample_rate                    u(4)
        data_1                          d(10)
        len_2                          u(1)
        data_2                          d(len_2)
        junk                            d(1)
        val_13                          v
        '19'                            u(1)
        len_3                          v
        num_data                        u(1)
        for (i = 0; i < num_data; i++) {
            data_len[i]                v
        }
        for (i = 0; i < num_data; i++) {
            data                        d(data_len[i])
        }
    }
}
</nowiki></pre>
 
;track_header_length : Length in bytes of track header including this field.  Matches element of same name in file_header.
;num_streams        : Number of elementary streams in track.
;size_1              : Number of bytes preceding video streams loop, including this field.
;num_video          : Number of video streams.
;def_video_stream    : Default video stream number.
;size_2              : Number of bytes preceding audio streams loop, including this field.
;num_audio          : Number of audio streams.
;def_audio_stream    : Default audio stream number.
 
===Track Index===
<pre><nowiki>
track_index() {
    length                              v
    'c'                                u(1)
    num_sb_blocks                      v
    for (i = 0; i < count; i++) {
        size                            v
        num_chunks                      v
    }
}
</nowiki></pre>
 
;length        : Length in bytes of track index.
;num_sb_blocks : Number of entries in following table.
;size          : Size of a block.
;num_chunks    : Number of chunks in block.
 
==="SB" Block===
<pre><nowiki>
sb_block() {
    "SB"                                a(2)
    size                                v
    junk                                d(1)
    start_chunk                        v
    do {
        chunk_size                      v
        flag                            u(1)
    } while (chunk_size != 0)
}
</nowiki></pre>
 
;size : Total size of this block.
 
The chunks for which <code>flag</code> is 1 have the following structure:
 
<pre><nowiki>
chunk_1() {
    length                              v
    unknown_1                          d(length)
    unknown_2                          unknown
    do {
        offset                          v
        unknown_3                      v
    } while (offset != 0)
}
</nowiki></pre>
 
;offset : offset from end of table to start of elementary stream packet
 
==External Resources==
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].
Extended company and product description is available on [http://en.wikipedia.org/wiki/Vividas Wikipedia].



Revision as of 14:00, 10 December 2007

Overview

A Vividas file consists of one or more "tracks", each comprising one or more audio and/or video elementary streams.

Encryption

All data relating to a track is encoded using a 32-bit key given in obfuscated form in the file header.

Keys

The header contains, for each track, a 187-byte block, 32 bits of which form the key. The following C function will extract a key from such a block.

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,
};

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;
}

Decoding

To decode a data block with a given key, this C function can be used:

void decode(uint32_t *d, unsigned size, uint32_t key)
{
    uint32_t k = key;

    size >>= 2;

    while (size--) {
        *d++ ^= k;
        k += key;
    }
}

File Format

Data Types

The following data types are used in the syntax description below.

u(n)
n-byte unsigned little endian integer.
v
Variable-length integer, the 7 low bits of each byte being data bits, and the MSB indicating whether more bytes follow.
a(n)
n-byte ASCII string.
z
NUL-terminated ASCII string.
d(n)
n bytes unspecified data.
'x'
Literal byte with hex value x.
"s"
Literal ASCII string.

Overall Structure

vividas_file() {
    signature                           a(7)
    version                             a(2)
    file_header()
    if (skin_size > 0) {
        skin()
    }
    for (i = 0; i < num_tracks; i++) {
        reset_key()
        track_header()
        track_index()
    }
    for (;;) {
        reset_key()
        sb_block()
    }
}
signature
The string vividas.
version
File version as two decimal digits. All known samples have the value 03.
file_header()
Sets skin_size and num_tracks.
reset_key()
The decoding key is reset to the value from the file_header.

File Header

file_header() {
    header_length                       v
    num_tracks                          u(1)
    for (i = 0; i < num_tracks; i++) {
        title_length                    u(1)
        track_title                     a(title_length)
        track_key                       d(187)
        track_header_length             d(4)
    }
    for (;;) {
        block_length                    v
        block_type                      u(1)
        if (block_type == 15) {
            key                         d(187)
            for (;;) {
                descriptor()
            }
        } else if (block_type == 22) {
            skin_key                    d(187)
            skin_size                   d(4)
        }
    }
}
header_length
Total length of the file_header element in bytes.
num_tracks
Number of tracks in the file.
title_length
Number of bytes in the immediately following title.
track_title
Title of track i.
track_key
Scrambled key for track i.
track_header_length
Total size in bytes of track_header and track_index for track i.
block_length
Size in bytes of the following block, including this field.

Skin

skin() {
    length                              v
    'd'                                 u(1)
    for (;;) {    
        size                            v
        tag                             u(1)
        data                            d(size)
    }             
}
length
Total size of skin data including length field.
size
Size of data chunk.
tag
Unique identifier for data chunk.
data
XML or JPEG data.

Track Header

track_header() {
    track_header_length                 v
    '1'                                 u(1)
    val_1                               u(1)
    for (i = 0; i < val_1; i++) {
        val_2                           u(1)
        for (j = 0; j < val_2; j++) {
            val_3                       u(1)
            val_4                       u(1)
        }
    }
    num_streams                         u(1)
    size_1                              v
    '2'                                 u(1)
    num_video                           u(1)
    def_video                           u(1)
    for (i = 0; i < num_video; i++) {
        length                          v
        '3'                             u(1)
        val_7                           u(1)
        frame_rate_den                  u(4)
        frame_rate_num                  u(4)
        num_frames                      u(4)
        width                           u(2)
        height                          u(2)
        val_8                           u(1)
        val_9                           u(4)
    }
    size_2                              v
    '4'                                 u(1)
    num_audio                           u(1)
    def_audio                           u(1)
    for (i = 0; i < num_audio; i++) {
        length                          v
        '5'                             u(1)
        codec_id                        u(1)
        codec_subid                     u(2)
        channels                        u(2)
        sample_rate                     u(4)
        data_1                          d(10)
        len_2                           u(1)
        data_2                          d(len_2)
        junk                            d(1)
        val_13                          v
        '19'                            u(1)
        len_3                           v
        num_data                        u(1)
        for (i = 0; i < num_data; i++) {
            data_len[i]                 v
        }
        for (i = 0; i < num_data; i++) {
            data                        d(data_len[i])
        }
    }
}
track_header_length
Length in bytes of track header including this field. Matches element of same name in file_header.
num_streams
Number of elementary streams in track.
size_1
Number of bytes preceding video streams loop, including this field.
num_video
Number of video streams.
def_video_stream
Default video stream number.
size_2
Number of bytes preceding audio streams loop, including this field.
num_audio
Number of audio streams.
def_audio_stream
Default audio stream number.

Track Index

track_index() {
    length                              v
    'c'                                 u(1)
    num_sb_blocks                       v
    for (i = 0; i < count; i++) {
        size                            v
        num_chunks                      v
    }
}
length
Length in bytes of track index.
num_sb_blocks
Number of entries in following table.
size
Size of a block.
num_chunks
Number of chunks in block.

"SB" Block

sb_block() {
    "SB"                                a(2)
    size                                v
    junk                                d(1)
    start_chunk                         v
    do {
        chunk_size                      v
        flag                            u(1)
    } while (chunk_size != 0)
}
size
Total size of this block.

The chunks for which flag is 1 have the following structure:

chunk_1() {
    length                              v
    unknown_1                           d(length)
    unknown_2                           unknown
    do {
        offset                          v
        unknown_3                       v
    } while (offset != 0)
}
offset
offset from end of table to start of elementary stream packet

External Resources

Extended company and product description is available on Wikipedia.

"Vividas Licenses TrueMotion VP7 for Mass Distribution of High Quality Video" January 13th, 2005

Vividas - Open Source Acknowledgement