2003-09-05 20:45:32 +02:00
/*
2004-04-03 23:00:14 +02:00
* " NUT " Container Format muxer and demuxer ( DRAFT - 200403 ? ? )
2003-09-05 20:45:32 +02:00
* Copyright ( c ) 2003 Alex Beregszaszi
2004-04-03 23:00:14 +02:00
* Copyright ( c ) 2004 Michael Niedermayer
2003-09-05 20:45:32 +02:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* NUT DRAFT can be found in MPlayer CVS at DOCS / tech / mpcf . txt
*
2003-10-03 00:41:08 +02:00
* AND http : //people.fsn.hu/~alex/nut/ (TeX, pdf, ps, dvi, ..)
2003-09-05 20:45:32 +02:00
*
*/
/*
* TODO :
* - index writing
2004-04-05 00:34:26 +02:00
* - index packet reading support
2003-09-05 20:45:32 +02:00
*/
//#define DEBUG 1
2004-04-03 23:00:14 +02:00
# include <limits.h>
2003-09-05 20:45:32 +02:00
# include "avformat.h"
# include "mpegaudio.h"
2003-09-08 22:00:13 +02:00
# include "avi.h"
2003-09-05 20:45:32 +02:00
2004-04-03 23:00:14 +02:00
# undef NDEBUG
# include <assert.h>
2003-09-06 16:03:35 +02:00
//from /dev/random
2004-04-03 23:00:14 +02:00
# define MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48))
# define STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48))
# define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48))
# define INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48))
# define INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48))
2004-05-02 03:03:55 +02:00
# define MAX_DISTANCE (1024*16-1)
# define MAX_SHORT_DISTANCE (1024*4-1)
2004-04-03 23:00:14 +02:00
# define MAX_PTS_LRU 3
2004-05-02 03:03:55 +02:00
# define FLAG_DATA_SIZE 4
# define FLAG_PTS 3
# define FLAG_KEY_FRAME 8
2004-04-03 23:00:14 +02:00
typedef struct {
uint8_t flags ;
uint8_t stream_id_plus1 ;
2004-05-02 03:03:55 +02:00
uint16_t size_mul ;
uint16_t size_lsb ;
2004-04-03 23:00:14 +02:00
} FrameCode ;
typedef struct {
int last_key_frame ;
int msb_timestamp_shift ;
int rate_num ;
int rate_den ;
int64_t last_pts ;
int lru_pts_delta [ MAX_PTS_LRU ] ;
int initial_pts_predictor [ MAX_PTS_LRU ] ;
2004-04-08 02:22:22 +02:00
int64_t last_sync_pos ; ///<pos of last 1/2 type frame
2004-05-02 03:03:55 +02:00
int decode_delay ;
2004-04-03 23:00:14 +02:00
} StreamContext ;
2003-09-06 16:03:35 +02:00
2003-09-05 20:45:32 +02:00
typedef struct {
2004-04-03 23:00:14 +02:00
AVFormatContext * avf ;
int written_packet_size ;
2004-05-02 03:03:55 +02:00
int64_t packet_start [ 3 ] ; //0-> startcode less, 1-> short startcode 2-> long startcodes
2004-04-03 23:00:14 +02:00
FrameCode frame_code [ 256 ] ;
2004-04-06 00:00:59 +02:00
int stream_count ;
2004-04-06 19:40:17 +02:00
uint64_t next_startcode ; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable
2004-04-03 23:00:14 +02:00
StreamContext * stream ;
2004-05-02 03:03:55 +02:00
int max_distance ;
2003-09-05 20:45:32 +02:00
} NUTContext ;
2004-04-05 00:34:26 +02:00
static char * info_table [ ] [ 2 ] = {
{ NULL , NULL } , // end
{ NULL , NULL } ,
{ NULL , " UTF8 " } ,
{ NULL , " v " } ,
{ NULL , " s " } ,
{ " StreamId " , " v " } ,
{ " SegmentId " , " v " } ,
{ " StartTimestamp " , " v " } ,
{ " EndTimestamp " , " v " } ,
{ " Author " , " UTF8 " } ,
2004-04-05 12:38:01 +02:00
{ " Title " , " UTF8 " } ,
2004-04-05 00:34:26 +02:00
{ " Description " , " UTF8 " } ,
{ " Copyright " , " UTF8 " } ,
{ " Encoder " , " UTF8 " } ,
{ " Keyword " , " UTF8 " } ,
{ " Cover " , " JPEG " } ,
{ " Cover " , " PNG " } ,
} ;
2004-04-03 23:00:14 +02:00
static void update_lru ( int * lru , int current , int count ) {
int i ;
for ( i = 0 ; i < count - 1 ; i + + ) {
if ( lru [ i ] = = current )
break ;
}
for ( ; i ; i - - ) {
lru [ i ] = lru [ i - 1 ] ;
}
lru [ 0 ] = current ;
}
static void update ( NUTContext * nut , int stream_index , int64_t frame_start , int frame_type , int frame_code , int key_frame , int size , int64_t pts ) {
StreamContext * stream = & nut - > stream [ stream_index ] ;
stream - > last_key_frame = key_frame ;
2004-05-02 03:03:55 +02:00
nut - > packet_start [ frame_type ] = frame_start ;
if ( stream - > last_pts ! = AV_NOPTS_VALUE ) {
assert ( frame_type < 2 ) ;
2004-04-06 19:40:17 +02:00
update_lru ( stream - > lru_pts_delta , pts - stream - > last_pts , 3 ) ;
2004-05-02 03:03:55 +02:00
}
2004-04-03 23:00:14 +02:00
stream - > last_pts = pts ;
}
static void reset ( AVFormatContext * s /*, int frame_type*/ ) {
NUTContext * nut = s - > priv_data ;
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
StreamContext * stream = & nut - > stream [ i ] ;
stream - > last_key_frame = 1 ;
2004-05-02 03:03:55 +02:00
stream - > last_pts = AV_NOPTS_VALUE ;
2004-04-03 23:00:14 +02:00
memcpy ( stream - > lru_pts_delta , stream - > initial_pts_predictor , sizeof ( int ) * MAX_PTS_LRU ) ;
}
}
static void build_frame_code ( AVFormatContext * s ) {
NUTContext * nut = s - > priv_data ;
2004-05-02 03:03:55 +02:00
int key_frame , index , pred , stream_id , full_pts ;
2004-04-03 23:00:14 +02:00
int start = 0 ;
int end = 255 ;
int keyframe_0_esc = s - > nb_streams > 2 ;
if ( keyframe_0_esc ) {
2004-05-02 03:03:55 +02:00
/* keyframe = 0 escape */
FrameCode * ft = & nut - > frame_code [ start ] ;
ft - > flags = FLAG_DATA_SIZE | FLAG_PTS ;
ft - > stream_id_plus1 = 0 ;
ft - > size_mul = 1 ;
start + + ;
2004-04-03 23:00:14 +02:00
}
for ( stream_id = 0 ; stream_id < s - > nb_streams ; stream_id + + ) {
int start2 = start + ( end - start ) * stream_id / s - > nb_streams ;
int end2 = start + ( end - start ) * ( stream_id + 1 ) / s - > nb_streams ;
AVCodecContext * codec = & s - > streams [ stream_id ] - > codec ;
int is_audio = codec - > codec_type = = CODEC_TYPE_AUDIO ;
int intra_only = /*codec->intra_only || */ is_audio ;
int pred_count ;
for ( key_frame = 0 ; key_frame < 2 ; key_frame + + ) {
if ( intra_only & & keyframe_0_esc & & key_frame = = 0 )
continue ;
2004-05-02 03:03:55 +02:00
{
FrameCode * ft = & nut - > frame_code [ start2 ] ;
ft - > flags = FLAG_KEY_FRAME * key_frame ;
ft - > flags | = FLAG_DATA_SIZE | FLAG_PTS ;
ft - > stream_id_plus1 = stream_id + 1 ;
ft - > size_mul = 1 ;
start2 + + ;
2004-04-03 23:00:14 +02:00
}
}
key_frame = intra_only ;
# if 1
if ( is_audio ) {
int frame_bytes = codec - > frame_size * ( int64_t ) codec - > bit_rate / ( 8 * codec - > sample_rate ) ;
2004-05-02 03:03:55 +02:00
for ( full_pts = 0 ; full_pts < 2 ; full_pts + + ) {
for ( pred = 0 ; pred < 2 ; pred + + ) {
2004-04-03 23:00:14 +02:00
FrameCode * ft = & nut - > frame_code [ start2 ] ;
2004-05-02 03:03:55 +02:00
ft - > flags = FLAG_KEY_FRAME * key_frame + FLAG_PTS * full_pts ;
2004-04-03 23:00:14 +02:00
ft - > stream_id_plus1 = stream_id + 1 ;
2004-05-02 03:03:55 +02:00
ft - > size_mul = frame_bytes + 2 ;
ft - > size_lsb = frame_bytes + pred ;
2004-04-03 23:00:14 +02:00
start2 + + ;
2004-05-02 03:03:55 +02:00
av_log ( NULL , AV_LOG_DEBUG , " %d \n " , frame_bytes + pred ) ;
2004-04-03 23:00:14 +02:00
}
}
} else {
FrameCode * ft = & nut - > frame_code [ start2 ] ;
ft - > flags = FLAG_KEY_FRAME | FLAG_DATA_SIZE ;
ft - > stream_id_plus1 = stream_id + 1 ;
ft - > size_mul = 1 ;
start2 + + ;
}
# endif
2004-04-04 20:37:41 +02:00
pred_count = 2 + codec - > has_b_frames + ( codec - > codec_id = = CODEC_ID_VORBIS ) ;
2004-04-03 23:00:14 +02:00
for ( pred = 0 ; pred < pred_count ; pred + + ) {
int start3 = start2 + ( end2 - start2 ) * pred / pred_count ;
int end3 = start2 + ( end2 - start2 ) * ( pred + 1 ) / pred_count ;
for ( index = start3 ; index < end3 ; index + + ) {
FrameCode * ft = & nut - > frame_code [ index ] ;
ft - > flags = FLAG_KEY_FRAME * key_frame + pred * 4 ;
ft - > flags | = FLAG_DATA_SIZE ;
ft - > stream_id_plus1 = stream_id + 1 ;
//FIXME use single byte size and pred from last
ft - > size_mul = end3 - start3 ;
ft - > size_lsb = index - start3 ;
}
nut - > stream [ stream_id ] . initial_pts_predictor [ pred ] = pred + 1 ;
}
}
memmove ( & nut - > frame_code [ ' N ' + 1 ] , & nut - > frame_code [ ' N ' ] , sizeof ( FrameCode ) * ( 255 - ' N ' ) ) ;
nut - > frame_code [ ' N ' ] . flags = 1 ;
}
2003-09-05 20:45:32 +02:00
static uint64_t get_v ( ByteIOContext * bc )
{
uint64_t val = 0 ;
2004-04-06 19:40:17 +02:00
for ( ; ; )
2003-09-05 20:45:32 +02:00
{
int tmp = get_byte ( bc ) ;
if ( tmp & 0x80 )
val = ( val < < 7 ) + tmp - 0x80 ;
2004-05-02 03:03:55 +02:00
else {
//av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp);
2003-09-05 20:45:32 +02:00
return ( val < < 7 ) + tmp ;
2004-05-02 03:03:55 +02:00
}
2003-09-05 20:45:32 +02:00
}
return - 1 ;
}
2004-04-05 00:34:26 +02:00
static int get_str ( ByteIOContext * bc , char * string , int maxlen ) {
int len = get_v ( bc ) ;
2003-09-05 20:45:32 +02:00
2004-04-05 00:34:26 +02:00
if ( len & & maxlen )
get_buffer ( bc , string , FFMIN ( len , maxlen ) ) ;
while ( len > maxlen ) {
get_byte ( bc ) ;
len - - ;
}
2003-09-10 15:00:24 +02:00
2004-04-05 00:34:26 +02:00
if ( maxlen )
string [ FFMIN ( len , maxlen - 1 ) ] = 0 ;
2003-09-10 15:00:24 +02:00
2004-04-05 00:34:26 +02:00
if ( maxlen = = len )
return - 1 ;
else
return 0 ;
2003-09-05 20:45:32 +02:00
}
2004-04-08 02:22:22 +02:00
static uint64_t get_vb ( ByteIOContext * bc ) {
uint64_t val = 0 ;
int i = get_v ( bc ) ;
if ( i > 8 )
return UINT64_MAX ;
while ( i - - )
val = ( val < < 8 ) + get_byte ( bc ) ;
2004-05-02 03:03:55 +02:00
//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val);
2004-04-08 02:22:22 +02:00
return val ;
}
2004-05-02 03:03:55 +02:00
static int get_packetheader ( NUTContext * nut , ByteIOContext * bc , int calculate_checksum )
2003-09-05 20:45:32 +02:00
{
2004-05-02 03:03:55 +02:00
int64_t start , size ;
start = url_ftell ( bc ) - 8 ;
2004-04-03 23:00:14 +02:00
2004-04-06 19:40:17 +02:00
init_checksum ( bc , calculate_checksum ? update_adler32 : NULL , 0 ) ;
2004-04-03 23:00:14 +02:00
size = get_v ( bc ) ;
2004-05-02 03:03:55 +02:00
nut - > packet_start [ 2 ] = start ;
2004-04-03 23:00:14 +02:00
nut - > written_packet_size = size ;
return size ;
2003-09-05 20:45:32 +02:00
}
2004-04-05 14:02:10 +02:00
static int check_checksum ( ByteIOContext * bc ) {
unsigned long checksum = get_checksum ( bc ) ;
return checksum ! = get_be32 ( bc ) ;
}
2003-09-06 18:29:05 +02:00
/**
*
*/
static int get_length ( uint64_t val ) {
int i ;
2003-09-05 20:45:32 +02:00
2004-04-08 02:22:22 +02:00
for ( i = 7 ; val > > i ; i + = 7 ) ;
2003-09-05 20:45:32 +02:00
2004-04-08 02:22:22 +02:00
return i ;
2003-09-05 20:45:32 +02:00
}
2004-04-06 00:00:59 +02:00
static uint64_t find_any_startcode ( ByteIOContext * bc , int64_t pos ) {
uint64_t state = 0 ;
if ( pos > = 0 )
url_fseek ( bc , pos , SEEK_SET ) ; //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently
2004-04-06 19:40:17 +02:00
while ( ! url_feof ( bc ) ) {
2004-04-06 00:00:59 +02:00
state = ( state < < 8 ) | get_byte ( bc ) ;
if ( ( state > > 56 ) ! = ' N ' )
continue ;
switch ( state ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case KEYFRAME_STARTCODE :
case INFO_STARTCODE :
case INDEX_STARTCODE :
return state ;
}
}
2004-04-08 02:22:22 +02:00
2004-04-06 00:00:59 +02:00
return 0 ;
}
2004-04-08 02:22:22 +02:00
/**
* find the given startcode .
* @ param code the startcode
* @ param pos the start position of the search , or - 1 if the current position
* @ returns the position of the startcode or - 1 if not found
*/
static int64_t find_startcode ( ByteIOContext * bc , uint64_t code , int64_t pos ) {
2004-04-06 00:00:59 +02:00
for ( ; ; ) {
uint64_t startcode = find_any_startcode ( bc , pos ) ;
if ( startcode = = code )
2004-04-08 02:22:22 +02:00
return url_ftell ( bc ) - 8 ;
2004-04-06 00:00:59 +02:00
else if ( startcode = = 0 )
return - 1 ;
pos = - 1 ;
}
}
2003-10-14 06:15:53 +02:00
# ifdef CONFIG_ENCODERS
2004-04-08 02:22:22 +02:00
static void put_v ( ByteIOContext * bc , uint64_t val )
2003-09-05 20:45:32 +02:00
{
int i ;
2004-05-02 03:03:55 +02:00
//av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val);
2003-09-05 20:45:32 +02:00
val & = 0x7FFFFFFFFFFFFFFFULL ; // FIXME can only encode upto 63 bits currently
2003-09-06 18:29:05 +02:00
i = get_length ( val ) ;
2003-09-05 20:45:32 +02:00
2003-09-06 16:03:35 +02:00
for ( i - = 7 ; i > 0 ; i - = 7 ) {
2003-09-05 20:45:32 +02:00
put_byte ( bc , 0x80 | ( val > > i ) ) ;
2003-09-06 16:03:35 +02:00
}
2003-09-05 20:45:32 +02:00
put_byte ( bc , val & 0x7f ) ;
}
2004-04-08 02:22:22 +02:00
/**
* stores a string as vb .
*/
static void put_str ( ByteIOContext * bc , const char * string ) {
2004-04-05 00:34:26 +02:00
int len = strlen ( string ) ;
2003-09-05 20:45:32 +02:00
put_v ( bc , len ) ;
2004-04-05 00:34:26 +02:00
put_buffer ( bc , string , len ) ;
2004-04-08 02:22:22 +02:00
}
static void put_vb ( ByteIOContext * bc , uint64_t val ) {
int i ;
2004-04-05 00:34:26 +02:00
2004-04-08 02:22:22 +02:00
for ( i = 8 ; val > > i ; i + = 8 ) ;
put_v ( bc , i > > 3 ) ;
for ( i - = 8 ; i > = 0 ; i - = 8 )
put_byte ( bc , ( val > > i ) & 0xFF ) ;
2003-09-08 22:00:13 +02:00
}
2004-04-05 14:02:10 +02:00
static int put_packetheader ( NUTContext * nut , ByteIOContext * bc , int max_size , int calculate_checksum )
2003-09-05 20:45:32 +02:00
{
put_flush_packet ( bc ) ;
2004-05-02 03:03:55 +02:00
nut - > packet_start [ 2 ] + = nut - > written_packet_size ;
assert ( url_ftell ( bc ) - 8 = = nut - > packet_start [ 2 ] ) ;
2004-04-03 23:00:14 +02:00
nut - > written_packet_size = max_size ;
2004-04-05 14:02:10 +02:00
if ( calculate_checksum )
init_checksum ( bc , update_adler32 , 0 ) ;
2004-04-03 23:00:14 +02:00
2003-09-05 20:45:32 +02:00
/* packet header */
2004-04-03 23:00:14 +02:00
put_v ( bc , nut - > written_packet_size ) ; /* forward ptr */
2003-09-05 20:45:32 +02:00
return 0 ;
}
2004-04-05 14:02:10 +02:00
static int update_packetheader ( NUTContext * nut , ByteIOContext * bc , int additional_size , int calculate_checksum ) {
2004-05-02 03:03:55 +02:00
int64_t start = nut - > packet_start [ 2 ] ;
2004-04-03 23:00:14 +02:00
int64_t cur = url_ftell ( bc ) ;
2003-09-06 18:29:05 +02:00
int size = cur - start + additional_size ;
2004-04-05 14:02:10 +02:00
if ( calculate_checksum )
size + = 4 ;
2004-04-03 23:00:14 +02:00
if ( size ! = nut - > written_packet_size ) {
int i ;
assert ( size < = nut - > written_packet_size ) ;
2003-09-06 18:29:05 +02:00
2004-05-02 03:03:55 +02:00
url_fseek ( bc , start + 8 , SEEK_SET ) ;
2004-04-03 23:00:14 +02:00
for ( i = get_length ( size ) ; i < get_length ( nut - > written_packet_size ) ; i + = 7 )
put_byte ( bc , 0x80 ) ;
put_v ( bc , size ) ;
url_fseek ( bc , cur , SEEK_SET ) ;
nut - > written_packet_size = size ; //FIXME may fail if multiple updates with differing sizes, as get_length may differ
2004-04-05 14:02:10 +02:00
if ( calculate_checksum )
put_be32 ( bc , get_checksum ( bc ) ) ;
2004-04-03 23:00:14 +02:00
}
2003-09-05 20:45:32 +02:00
return 0 ;
}
static int nut_write_header ( AVFormatContext * s )
{
NUTContext * nut = s - > priv_data ;
ByteIOContext * bc = & s - > pb ;
AVCodecContext * codec ;
2004-04-03 23:00:14 +02:00
int i , j ;
2003-09-05 20:45:32 +02:00
2004-04-03 23:00:14 +02:00
nut - > avf = s ;
nut - > stream =
av_mallocz ( sizeof ( StreamContext ) * s - > nb_streams ) ;
av_set_pts_info ( s , 60 , 1 , AV_TIME_BASE ) ;
2003-09-05 20:45:32 +02:00
/* main header */
2003-09-06 16:03:35 +02:00
put_be64 ( bc , MAIN_STARTCODE ) ;
2004-04-05 14:02:10 +02:00
put_packetheader ( nut , bc , 120 + 5 * 256 , 1 ) ;
2004-05-02 03:03:55 +02:00
put_v ( bc , 2 ) ; /* version */
2003-09-05 20:45:32 +02:00
put_v ( bc , s - > nb_streams ) ;
2004-05-02 03:03:55 +02:00
put_v ( bc , MAX_DISTANCE ) ;
2004-04-03 23:00:14 +02:00
build_frame_code ( s ) ;
assert ( nut - > frame_code [ ' N ' ] . flags = = 1 ) ;
for ( i = 0 ; i < 256 ; ) {
int tmp_flags = nut - > frame_code [ i ] . flags ;
int tmp_stream = nut - > frame_code [ i ] . stream_id_plus1 ;
int tmp_mul = nut - > frame_code [ i ] . size_mul ;
int tmp_size = nut - > frame_code [ i ] . size_lsb ;
put_v ( bc , tmp_flags ) ;
put_v ( bc , tmp_stream ) ;
put_v ( bc , tmp_mul ) ;
put_v ( bc , tmp_size ) ;
for ( j = 0 ; i < 256 ; j + + , i + + ) {
if ( nut - > frame_code [ i ] . flags ! = tmp_flags ) break ;
if ( nut - > frame_code [ i ] . stream_id_plus1 ! = tmp_stream ) break ;
if ( nut - > frame_code [ i ] . size_mul ! = tmp_mul ) break ;
if ( nut - > frame_code [ i ] . size_lsb ! = tmp_size ) break ;
if ( + + tmp_size > = tmp_mul ) {
tmp_size = 0 ;
tmp_stream + + ;
}
}
put_v ( bc , j ) ;
}
2004-04-05 14:02:10 +02:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-06 18:29:05 +02:00
2003-09-05 20:45:32 +02:00
/* stream headers */
for ( i = 0 ; i < s - > nb_streams ; i + + )
{
2004-04-03 23:00:14 +02:00
int nom , denom , gcd ;
2003-10-03 00:33:55 +02:00
2003-09-05 20:45:32 +02:00
codec = & s - > streams [ i ] - > codec ;
2003-09-06 16:03:35 +02:00
put_be64 ( bc , STREAM_STARTCODE ) ;
2004-04-05 14:02:10 +02:00
put_packetheader ( nut , bc , 120 + codec - > extradata_size , 1 ) ;
2003-09-07 01:17:17 +02:00
put_v ( bc , i /*s->streams[i]->index*/ ) ;
2003-09-05 20:45:32 +02:00
put_v ( bc , ( codec - > codec_type = = CODEC_TYPE_AUDIO ) ? 32 : 0 ) ;
if ( codec - > codec_tag )
2004-04-08 02:22:22 +02:00
put_vb ( bc , codec - > codec_tag ) ;
2003-09-05 20:45:32 +02:00
else if ( codec - > codec_type = = CODEC_TYPE_VIDEO )
{
2004-04-08 02:22:22 +02:00
put_vb ( bc , codec_get_bmp_tag ( codec - > codec_id ) ) ;
2003-09-05 20:45:32 +02:00
}
else if ( codec - > codec_type = = CODEC_TYPE_AUDIO )
{
2004-04-08 02:22:22 +02:00
put_vb ( bc , codec_get_wav_tag ( codec - > codec_id ) ) ;
2003-10-15 17:21:46 +02:00
}
2004-04-05 00:34:26 +02:00
else
2004-04-08 02:22:22 +02:00
put_vb ( bc , 0 ) ;
2003-10-15 17:21:46 +02:00
if ( codec - > codec_type = = CODEC_TYPE_VIDEO )
{
nom = codec - > frame_rate ;
denom = codec - > frame_rate_base ;
}
else
{
2004-04-03 23:00:14 +02:00
nom = codec - > sample_rate ;
if ( codec - > frame_size > 0 )
denom = codec - > frame_size ;
else
denom = 1 ; //unlucky
2003-09-05 20:45:32 +02:00
}
2004-04-03 23:00:14 +02:00
gcd = ff_gcd ( nom , denom ) ;
nom / = gcd ;
denom / = gcd ;
nut - > stream [ i ] . rate_num = nom ;
nut - > stream [ i ] . rate_den = denom ;
2003-09-05 20:45:32 +02:00
put_v ( bc , codec - > bit_rate ) ;
2004-04-08 02:22:22 +02:00
put_vb ( bc , 0 ) ; /* no language code */
2003-10-03 00:33:55 +02:00
put_v ( bc , nom ) ;
put_v ( bc , denom ) ;
2004-04-03 23:00:14 +02:00
if ( nom / denom < 1000 )
nut - > stream [ i ] . msb_timestamp_shift = 7 ;
else
nut - > stream [ i ] . msb_timestamp_shift = 14 ;
put_v ( bc , nut - > stream [ i ] . msb_timestamp_shift ) ;
for ( j = 0 ; j < 3 ; j + + )
put_v ( bc , nut - > stream [ i ] . initial_pts_predictor [ j ] ) ;
2004-05-02 03:03:55 +02:00
put_v ( bc , codec - > has_b_frames ) ;
2003-09-05 20:45:32 +02:00
put_byte ( bc , 0 ) ; /* flags: 0x1 - fixed_fps, 0x2 - index_present */
2004-04-03 23:00:14 +02:00
if ( codec - > extradata_size ) {
put_v ( bc , 1 ) ;
put_v ( bc , codec - > extradata_size ) ;
put_buffer ( bc , codec - > extradata , codec - > extradata_size ) ;
}
put_v ( bc , 0 ) ; /* end of codec specific headers */
2003-09-05 20:45:32 +02:00
switch ( codec - > codec_type )
{
case CODEC_TYPE_AUDIO :
2004-05-02 03:03:55 +02:00
put_v ( bc , codec - > sample_rate ) ;
put_v ( bc , 1 ) ;
2003-09-05 20:45:32 +02:00
put_v ( bc , codec - > channels ) ;
break ;
case CODEC_TYPE_VIDEO :
put_v ( bc , codec - > width ) ;
put_v ( bc , codec - > height ) ;
2004-04-03 23:00:14 +02:00
put_v ( bc , codec - > sample_aspect_ratio . num ) ;
put_v ( bc , codec - > sample_aspect_ratio . den ) ;
2003-09-05 20:45:32 +02:00
put_v ( bc , 0 ) ; /* csp type -- unknown */
break ;
2003-09-08 22:00:13 +02:00
default :
break ;
2003-09-05 20:45:32 +02:00
}
2004-04-05 14:02:10 +02:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-05 20:45:32 +02:00
}
/* info header */
2003-09-07 02:37:46 +02:00
put_be64 ( bc , INFO_STARTCODE ) ;
2004-04-05 00:34:26 +02:00
put_packetheader ( nut , bc , 30 + strlen ( s - > author ) + strlen ( s - > title ) +
2004-04-05 14:02:10 +02:00
strlen ( s - > comment ) + strlen ( s - > copyright ) + strlen ( LIBAVFORMAT_IDENT ) , 1 ) ;
2003-09-05 20:45:32 +02:00
if ( s - > author [ 0 ] )
{
2004-04-05 00:34:26 +02:00
put_v ( bc , 9 ) ; /* type */
put_str ( bc , s - > author ) ;
2003-09-05 20:45:32 +02:00
}
if ( s - > title [ 0 ] )
{
2004-04-05 00:34:26 +02:00
put_v ( bc , 10 ) ; /* type */
put_str ( bc , s - > title ) ;
2003-09-05 20:45:32 +02:00
}
if ( s - > comment [ 0 ] )
{
2004-04-05 00:34:26 +02:00
put_v ( bc , 11 ) ; /* type */
put_str ( bc , s - > comment ) ;
2003-09-05 20:45:32 +02:00
}
if ( s - > copyright [ 0 ] )
{
2004-04-05 00:34:26 +02:00
put_v ( bc , 12 ) ; /* type */
put_str ( bc , s - > copyright ) ;
2003-09-05 20:45:32 +02:00
}
/* encoder */
2004-04-12 22:06:23 +02:00
if ( ! ( s - > streams [ 0 ] - > codec . flags & CODEC_FLAG_BITEXACT ) ) {
put_v ( bc , 13 ) ; /* type */
put_str ( bc , LIBAVFORMAT_IDENT ) ;
}
2003-09-07 01:17:17 +02:00
put_v ( bc , 0 ) ; /* eof info */
2004-04-05 14:02:10 +02:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-05 20:45:32 +02:00
put_flush_packet ( bc ) ;
return 0 ;
}
2004-05-02 03:03:55 +02:00
static int64_t lsb2full ( StreamContext * stream , int64_t lsb ) {
int64_t mask = ( 1 < < stream - > msb_timestamp_shift ) - 1 ;
int64_t delta = stream - > last_pts - mask / 2 ;
return ( ( lsb - delta ) & mask ) + delta ;
}
2003-09-05 20:45:32 +02:00
static int nut_write_packet ( AVFormatContext * s , int stream_index ,
2003-09-11 00:37:33 +02:00
const uint8_t * buf , int size , int64_t pts )
2003-09-05 20:45:32 +02:00
{
NUTContext * nut = s - > priv_data ;
2004-04-03 23:00:14 +02:00
StreamContext * stream = & nut - > stream [ stream_index ] ;
2003-09-05 20:45:32 +02:00
ByteIOContext * bc = & s - > pb ;
2004-04-03 23:00:14 +02:00
int key_frame = 0 , full_pts = 0 ;
2003-09-05 20:45:32 +02:00
AVCodecContext * enc ;
2004-05-02 03:03:55 +02:00
int64_t coded_pts ;
2004-04-03 23:00:14 +02:00
int frame_type , best_length , frame_code , flags , i , size_mul , size_lsb ;
const int64_t frame_start = url_ftell ( bc ) ;
2003-09-05 20:45:32 +02:00
if ( stream_index > s - > nb_streams )
return 1 ;
2004-04-03 23:00:14 +02:00
pts = ( av_rescale ( pts , stream - > rate_num , stream - > rate_den ) + AV_TIME_BASE / 2 ) / AV_TIME_BASE ;
2003-09-05 20:45:32 +02:00
enc = & s - > streams [ stream_index ] - > codec ;
2004-04-03 23:00:14 +02:00
key_frame = enc - > coded_frame - > key_frame ;
2004-04-13 00:23:16 +02:00
if ( enc - > coded_frame - > pts ! = AV_NOPTS_VALUE )
pts = ( av_rescale ( enc - > coded_frame - > pts , stream - > rate_num , stream - > rate_den ) + AV_TIME_BASE / 2 ) / AV_TIME_BASE ; //FIXME XXX HACK
2004-04-03 23:00:14 +02:00
frame_type = 0 ;
2004-05-02 03:03:55 +02:00
if ( frame_start + size + 20 - FFMAX ( nut - > packet_start [ 1 ] , nut - > packet_start [ 2 ] ) > MAX_DISTANCE )
frame_type = 2 ;
if ( key_frame & & ! stream - > last_key_frame )
frame_type = 2 ;
2003-09-05 20:45:32 +02:00
2004-05-02 03:03:55 +02:00
if ( frame_type > 1 )
2004-04-03 23:00:14 +02:00
reset ( s ) ;
2004-05-02 03:03:55 +02:00
if ( stream - > last_pts = = AV_NOPTS_VALUE )
2004-04-03 23:00:14 +02:00
full_pts = 1 ;
2004-05-02 03:03:55 +02:00
else {
coded_pts = pts & ( ( 1 < < stream - > msb_timestamp_shift ) - 1 ) ;
if ( lsb2full ( stream , coded_pts ) ! = pts )
full_pts = 1 ;
2004-04-03 23:00:14 +02:00
}
2004-05-02 03:03:55 +02:00
if ( full_pts )
coded_pts = pts + ( 1 < < stream - > msb_timestamp_shift ) ;
2004-04-03 23:00:14 +02:00
best_length = INT_MAX ;
frame_code = - 1 ;
for ( i = 0 ; i < 256 ; i + + ) {
int stream_id_plus1 = nut - > frame_code [ i ] . stream_id_plus1 ;
2004-04-09 18:46:12 +02:00
int fc_key_frame ;
2004-04-03 23:00:14 +02:00
int length = 0 ;
size_mul = nut - > frame_code [ i ] . size_mul ;
size_lsb = nut - > frame_code [ i ] . size_lsb ;
flags = nut - > frame_code [ i ] . flags ;
2004-05-02 03:03:55 +02:00
assert ( size_mul > size_lsb ) ;
2004-04-03 23:00:14 +02:00
if ( stream_id_plus1 = = 0 ) length + = get_length ( stream_index ) ;
else if ( stream_id_plus1 - 1 ! = stream_index )
continue ;
2004-04-09 18:46:12 +02:00
fc_key_frame = ! ! ( flags & FLAG_KEY_FRAME ) ;
2004-04-03 23:00:14 +02:00
assert ( key_frame = = 0 | | key_frame = = 1 ) ;
if ( fc_key_frame ! = key_frame )
continue ;
2004-05-02 03:03:55 +02:00
if ( flags & FLAG_DATA_SIZE ) {
2004-04-03 23:00:14 +02:00
if ( size % size_mul ! = size_lsb )
continue ;
2004-05-02 03:03:55 +02:00
length + = get_length ( size / size_mul ) ;
} else if ( size ! = size_lsb )
continue ;
2004-04-03 23:00:14 +02:00
2004-05-02 03:03:55 +02:00
if ( full_pts & & ( flags & FLAG_PTS ) ! = FLAG_PTS )
2004-04-03 23:00:14 +02:00
continue ;
if ( flags & FLAG_PTS ) {
2004-05-02 03:03:55 +02:00
length + = get_length ( coded_pts ) ;
2004-04-03 23:00:14 +02:00
} else {
2004-05-02 03:03:55 +02:00
int delta = stream - > lru_pts_delta [ flags & FLAG_PTS ] ;
2004-04-03 23:00:14 +02:00
if ( delta ! = pts - stream - > last_pts )
continue ;
2004-05-02 03:03:55 +02:00
assert ( frame_type < 2 ) ;
2004-04-03 23:00:14 +02:00
}
if ( length < best_length ) {
best_length = length ;
frame_code = i ;
}
// av_log(s, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d %d %d\n", key_frame, frame_type, full_pts, size, stream_index, flags, size_mul, size_lsb, stream_id_plus1, length);
}
2003-09-06 16:03:35 +02:00
2004-04-03 23:00:14 +02:00
assert ( frame_code ! = - 1 ) ;
flags = nut - > frame_code [ frame_code ] . flags ;
size_mul = nut - > frame_code [ frame_code ] . size_mul ;
size_lsb = nut - > frame_code [ frame_code ] . size_lsb ;
#if 0
best_length / = 7 ;
best_length + + ; //frame_code
2004-05-02 03:03:55 +02:00
if ( frame_type = = 2 ) {
best_length + = 8 ; // startcode
2004-04-03 23:00:14 +02:00
}
2004-05-02 03:03:55 +02:00
av_log ( s , AV_LOG_DEBUG , " kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%lld \n " , key_frame , frame_type , full_pts ? 2 : ( ( flags & FLAG_PTS ) = = FLAG_PTS ? 1 : 0 ) , frame_code , best_length , size , stream_index , flags , size_mul , size_lsb , nut - > frame_code [ frame_code ] . stream_id_plus1 , ( int ) ( pts - stream - > last_pts ) , pts ) ;
// av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
2004-04-03 23:00:14 +02:00
# endif
if ( frame_type = = 2 )
2003-12-08 18:54:40 +01:00
put_be64 ( bc , KEYFRAME_STARTCODE ) ;
2004-05-02 03:03:55 +02:00
assert ( frame_type ! = 1 ) ; //short startcode not implemented yet
2004-04-03 23:00:14 +02:00
put_byte ( bc , frame_code ) ;
if ( nut - > frame_code [ frame_code ] . stream_id_plus1 = = 0 )
put_v ( bc , stream_index ) ;
2004-05-02 03:03:55 +02:00
if ( ( flags & FLAG_PTS ) = = FLAG_PTS ) {
put_v ( bc , coded_pts ) ;
2004-04-03 23:00:14 +02:00
}
if ( flags & FLAG_DATA_SIZE )
put_v ( bc , size / size_mul ) ;
2004-05-02 03:03:55 +02:00
if ( size > MAX_DISTANCE ) {
assert ( frame_type > 1 ) ;
2004-04-03 23:00:14 +02:00
}
2003-09-05 20:45:32 +02:00
put_buffer ( bc , buf , size ) ;
2004-04-03 23:00:14 +02:00
update ( nut , stream_index , frame_start , frame_type , frame_code , key_frame , size , pts ) ;
2003-09-05 20:45:32 +02:00
return 0 ;
}
static int nut_write_trailer ( AVFormatContext * s )
{
2003-12-08 18:54:40 +01:00
NUTContext * nut = s - > priv_data ;
2003-09-05 20:45:32 +02:00
ByteIOContext * bc = & s - > pb ;
2004-04-03 23:00:14 +02:00
2003-09-05 20:45:32 +02:00
#if 0
int i ;
/* WRITE INDEX */
for ( i = 0 ; s - > nb_streams ; i + + )
{
2003-09-06 16:03:35 +02:00
put_be64 ( bc , INDEX_STARTCODE ) ;
2004-04-05 14:02:10 +02:00
put_packetheader ( nut , bc , 64 , 1 ) ;
2003-09-05 20:45:32 +02:00
put_v ( bc , s - > streams [ i ] - > id ) ;
put_v ( bc , . . . ) ;
2004-04-05 14:02:10 +02:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-05 20:45:32 +02:00
}
# endif
put_flush_packet ( bc ) ;
2003-12-08 18:54:40 +01:00
2004-04-03 23:00:14 +02:00
av_freep ( & nut - > stream ) ;
2003-09-05 20:45:32 +02:00
return 0 ;
}
2003-10-14 06:15:53 +02:00
# endif //CONFIG_ENCODERS
2003-09-05 20:45:32 +02:00
static int nut_probe ( AVProbeData * p )
{
2003-09-06 16:03:35 +02:00
int i ;
2004-05-02 03:03:55 +02:00
uint64_t code = 0xff ;
2003-09-06 16:03:35 +02:00
for ( i = 0 ; i < p - > buf_size ; i + + ) {
2004-05-02 03:03:55 +02:00
code = ( code < < 8 ) | p - > buf [ i ] ;
2003-09-06 16:03:35 +02:00
if ( code = = MAIN_STARTCODE )
return AVPROBE_SCORE_MAX ;
}
return 0 ;
2003-09-05 20:45:32 +02:00
}
2004-04-06 00:00:59 +02:00
static int decode_main_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2003-09-05 20:45:32 +02:00
ByteIOContext * bc = & s - > pb ;
2003-09-06 16:03:35 +02:00
uint64_t tmp ;
2004-04-06 00:00:59 +02:00
int i , j ;
2003-09-05 20:45:32 +02:00
2004-05-02 03:03:55 +02:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 00:00:59 +02:00
2003-09-05 20:45:32 +02:00
tmp = get_v ( bc ) ;
2004-05-02 03:03:55 +02:00
if ( tmp ! = 2 ) {
2004-03-03 16:41:21 +01:00
av_log ( s , AV_LOG_ERROR , " bad version (%Ld) \n " , tmp ) ;
2004-04-06 00:00:59 +02:00
return - 1 ;
}
2003-09-05 20:45:32 +02:00
2004-04-06 00:00:59 +02:00
nut - > stream_count = get_v ( bc ) ;
2004-05-02 03:03:55 +02:00
nut - > max_distance = get_v ( bc ) ;
2004-04-03 23:00:14 +02:00
for ( i = 0 ; i < 256 ; ) {
int tmp_flags = get_v ( bc ) ;
int tmp_stream = get_v ( bc ) ;
int tmp_mul = get_v ( bc ) ;
int tmp_size = get_v ( bc ) ;
int count = get_v ( bc ) ;
if ( count = = 0 | | i + count > 256 ) {
av_log ( s , AV_LOG_ERROR , " illegal count %d at %d \n " , count , i ) ;
return - 1 ;
}
for ( j = 0 ; j < count ; j + + , i + + ) {
2004-04-06 00:00:59 +02:00
if ( tmp_stream > nut - > stream_count + 1 ) {
2004-04-03 23:00:14 +02:00
av_log ( s , AV_LOG_ERROR , " illegal stream number \n " ) ;
return - 1 ;
}
nut - > frame_code [ i ] . flags = tmp_flags ;
nut - > frame_code [ i ] . stream_id_plus1 = tmp_stream ;
nut - > frame_code [ i ] . size_mul = tmp_mul ;
nut - > frame_code [ i ] . size_lsb = tmp_size ;
if ( + + tmp_size > = tmp_mul ) {
tmp_size = 0 ;
tmp_stream + + ;
}
}
}
if ( nut - > frame_code [ ' N ' ] . flags ! = 1 ) {
av_log ( s , AV_LOG_ERROR , " illegal frame_code table \n " ) ;
return - 1 ;
}
2004-04-06 00:00:59 +02:00
2004-04-05 14:02:10 +02:00
if ( check_checksum ( bc ) ) {
av_log ( s , AV_LOG_ERROR , " Main header checksum missmatch \n " ) ;
return - 1 ;
}
2003-12-08 18:54:40 +01:00
2004-04-06 00:00:59 +02:00
return 0 ;
}
static int decode_stream_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
int class , nom , denom , stream_id , i ;
uint64_t tmp ;
AVStream * st ;
2004-05-02 03:03:55 +02:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 00:00:59 +02:00
stream_id = get_v ( bc ) ;
if ( stream_id > = nut - > stream_count | | s - > streams [ stream_id ] )
return - 1 ;
2003-09-05 20:45:32 +02:00
2004-04-06 00:00:59 +02:00
st = av_new_stream ( s , stream_id ) ;
if ( ! st )
return AVERROR_NOMEM ;
class = get_v ( bc ) ;
2004-04-08 02:22:22 +02:00
tmp = get_vb ( bc ) ;
2004-04-10 22:11:00 +02:00
st - > codec . codec_tag = tmp ;
2004-04-06 00:00:59 +02:00
switch ( class )
2003-09-05 20:45:32 +02:00
{
2004-04-06 00:00:59 +02:00
case 0 :
st - > codec . codec_type = CODEC_TYPE_VIDEO ;
st - > codec . codec_id = codec_get_bmp_id ( tmp ) ;
if ( st - > codec . codec_id = = CODEC_ID_NONE )
av_log ( s , AV_LOG_ERROR , " Unknown codec?! \n " ) ;
break ;
case 32 :
st - > codec . codec_type = CODEC_TYPE_AUDIO ;
st - > codec . codec_id = codec_get_wav_id ( tmp ) ;
if ( st - > codec . codec_id = = CODEC_ID_NONE )
av_log ( s , AV_LOG_ERROR , " Unknown codec?! \n " ) ;
break ;
default :
av_log ( s , AV_LOG_ERROR , " Unknown stream class (%d) \n " , class ) ;
2004-04-05 14:02:10 +02:00
return - 1 ;
2004-04-05 00:34:26 +02:00
}
2004-04-06 00:00:59 +02:00
s - > bit_rate + = get_v ( bc ) ;
2004-04-08 02:22:22 +02:00
get_vb ( bc ) ; /* language code */
2004-04-06 00:00:59 +02:00
nom = get_v ( bc ) ;
denom = get_v ( bc ) ;
nut - > stream [ stream_id ] . msb_timestamp_shift = get_v ( bc ) ;
for ( i = 0 ; i < 3 ; i + + )
2004-05-02 03:03:55 +02:00
nut - > stream [ stream_id ] . initial_pts_predictor [ i ] = get_v ( bc ) ;
nut - > stream [ stream_id ] . decode_delay = get_v ( bc ) ;
2004-04-06 00:00:59 +02:00
get_byte ( bc ) ; /* flags */
/* codec specific data headers */
while ( get_v ( bc ) ! = 0 ) {
st - > codec . extradata_size = get_v ( bc ) ;
st - > codec . extradata = av_mallocz ( st - > codec . extradata_size ) ;
get_buffer ( bc , st - > codec . extradata , st - > codec . extradata_size ) ;
// url_fskip(bc, get_v(bc));
}
2004-04-05 00:34:26 +02:00
2004-04-06 00:00:59 +02:00
if ( class = = 0 ) /* VIDEO */
{
st - > codec . width = get_v ( bc ) ;
st - > codec . height = get_v ( bc ) ;
st - > codec . sample_aspect_ratio . num = get_v ( bc ) ;
st - > codec . sample_aspect_ratio . den = get_v ( bc ) ;
get_v ( bc ) ; /* csp type */
st - > codec . frame_rate = nom ;
st - > codec . frame_rate_base = denom ;
}
if ( class = = 32 ) /* AUDIO */
{
2004-05-02 03:03:55 +02:00
st - > codec . sample_rate = get_v ( bc ) ;
get_v ( bc ) ; // samplerate_den
2004-04-06 00:00:59 +02:00
st - > codec . channels = get_v ( bc ) ;
}
if ( check_checksum ( bc ) ) {
av_log ( s , AV_LOG_ERROR , " Stream header %d checksum missmatch \n " , stream_id ) ;
return - 1 ;
}
nut - > stream [ stream_id ] . rate_num = nom ;
nut - > stream [ stream_id ] . rate_den = denom ;
return 0 ;
}
2004-04-05 00:34:26 +02:00
2004-04-06 00:00:59 +02:00
static int decode_info_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
2004-05-02 03:03:55 +02:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 00:00:59 +02:00
for ( ; ; ) {
int id = get_v ( bc ) ;
char * name , * type , custom_name [ 256 ] , custom_type [ 256 ] ;
if ( ! id )
break ;
else if ( id > = sizeof ( info_table ) / sizeof ( info_table [ 0 ] ) ) {
av_log ( s , AV_LOG_ERROR , " info id is too large %d %d \n " , id , sizeof ( info_table ) / sizeof ( info_table [ 0 ] ) ) ;
return - 1 ;
}
2004-04-05 00:34:26 +02:00
2004-04-06 00:00:59 +02:00
type = info_table [ id ] [ 1 ] ;
name = info_table [ id ] [ 0 ] ;
2004-04-05 00:34:26 +02:00
//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);
2004-04-06 00:00:59 +02:00
if ( ! type ) {
get_str ( bc , custom_type , sizeof ( custom_type ) ) ;
type = custom_type ;
}
if ( ! name ) {
get_str ( bc , custom_name , sizeof ( custom_name ) ) ;
name = custom_name ;
2004-04-05 00:34:26 +02:00
}
2004-04-06 00:00:59 +02:00
if ( ! strcmp ( type , " v " ) ) {
int value = get_v ( bc ) ;
} else {
if ( ! strcmp ( name , " Author " ) )
get_str ( bc , s - > author , sizeof ( s - > author ) ) ;
else if ( ! strcmp ( name , " Title " ) )
get_str ( bc , s - > title , sizeof ( s - > title ) ) ;
else if ( ! strcmp ( name , " Copyright " ) )
get_str ( bc , s - > copyright , sizeof ( s - > copyright ) ) ;
else if ( ! strcmp ( name , " Description " ) )
get_str ( bc , s - > comment , sizeof ( s - > comment ) ) ;
else
get_str ( bc , NULL , 0 ) ;
2004-04-05 14:02:10 +02:00
}
2004-04-06 00:00:59 +02:00
}
if ( check_checksum ( bc ) ) {
av_log ( s , AV_LOG_ERROR , " Info header checksum missmatch \n " ) ;
return - 1 ;
}
return 0 ;
}
static int nut_read_header ( AVFormatContext * s , AVFormatParameters * ap )
{
NUTContext * nut = s - > priv_data ;
ByteIOContext * bc = & s - > pb ;
int64_t pos ;
int inited_stream_count ;
nut - > avf = s ;
2003-09-05 20:45:32 +02:00
2004-04-06 00:00:59 +02:00
av_set_pts_info ( s , 60 , 1 , AV_TIME_BASE ) ;
/* main header */
pos = 0 ;
for ( ; ; ) {
2004-04-08 02:22:22 +02:00
pos = find_startcode ( bc , MAIN_STARTCODE , pos ) + 1 ;
if ( pos < 0 ) {
2004-04-06 00:00:59 +02:00
av_log ( s , AV_LOG_ERROR , " no main startcode found \n " ) ;
return - 1 ;
}
if ( decode_main_header ( nut ) > = 0 )
break ;
}
s - > bit_rate = 0 ;
nut - > stream = av_malloc ( sizeof ( StreamContext ) * nut - > stream_count ) ;
/* stream headers */
pos = 0 ;
for ( inited_stream_count = 0 ; inited_stream_count < nut - > stream_count ; ) {
2004-04-08 02:22:22 +02:00
pos = find_startcode ( bc , STREAM_STARTCODE , pos ) + 1 ;
if ( pos < 0 ) {
2004-04-06 00:00:59 +02:00
av_log ( s , AV_LOG_ERROR , " not all stream headers found \n " ) ;
return - 1 ;
}
if ( decode_stream_header ( nut ) > = 0 )
inited_stream_count + + ;
}
/* info headers */
pos = 0 ;
for ( ; ; ) {
uint64_t startcode = find_any_startcode ( bc , pos ) ;
pos = url_ftell ( bc ) ;
if ( startcode = = 0 ) {
av_log ( s , AV_LOG_ERROR , " EOF before video frames \n " ) ;
return - 1 ;
} else if ( startcode = = KEYFRAME_STARTCODE ) {
2004-04-06 19:40:17 +02:00
nut - > next_startcode = startcode ;
2004-04-06 00:00:59 +02:00
break ;
} else if ( startcode ! = INFO_STARTCODE ) {
continue ;
}
decode_info_header ( nut ) ;
}
2003-09-05 20:45:32 +02:00
return 0 ;
}
2004-05-02 03:03:55 +02:00
static int decode_frame_header ( NUTContext * nut , int * key_frame_ret , int64_t * pts_ret , int * stream_id_ret , int frame_code , int frame_type ) {
2004-04-06 19:40:17 +02:00
AVFormatContext * s = nut - > avf ;
2004-04-03 23:00:14 +02:00
StreamContext * stream ;
2003-09-05 20:45:32 +02:00
ByteIOContext * bc = & s - > pb ;
2004-04-06 19:40:17 +02:00
int size , flags , size_mul , size_lsb , stream_id ;
2003-12-08 18:54:40 +01:00
int64_t pts = 0 ;
2004-04-06 19:40:17 +02:00
const int prefix_len = frame_type = = 2 ? 8 + 1 : 1 ;
2004-04-08 02:22:22 +02:00
const int64_t frame_start = url_ftell ( bc ) - prefix_len ;
2003-09-05 20:45:32 +02:00
2004-05-02 03:03:55 +02:00
if ( frame_type < 2 & & frame_start - nut - > packet_start [ 2 ] > nut - > max_distance ) {
av_log ( s , AV_LOG_ERROR , " last frame must have been damaged \n " ) ;
return - 1 ;
}
if ( frame_type )
nut - > packet_start [ frame_type ] = frame_start ; //otherwise 1 goto 1 may happen
2004-04-03 23:00:14 +02:00
flags = nut - > frame_code [ frame_code ] . flags ;
size_mul = nut - > frame_code [ frame_code ] . size_mul ;
size_lsb = nut - > frame_code [ frame_code ] . size_lsb ;
stream_id = nut - > frame_code [ frame_code ] . stream_id_plus1 - 1 ;
2004-05-02 03:03:55 +02:00
if ( frame_type = = 2 )
2004-04-03 23:00:14 +02:00
reset ( s ) ;
if ( stream_id = = - 1 )
stream_id = get_v ( bc ) ;
if ( stream_id > = s - > nb_streams ) {
av_log ( s , AV_LOG_ERROR , " illegal stream_id \n " ) ;
return - 1 ;
}
stream = & nut - > stream [ stream_id ] ;
2004-04-06 19:40:17 +02:00
// av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
2004-05-02 03:03:55 +02:00
* key_frame_ret = ! ! ( flags & FLAG_KEY_FRAME ) ;
if ( ( flags & FLAG_PTS ) = = FLAG_PTS ) {
int64_t mask = ( 1 < < stream - > msb_timestamp_shift ) - 1 ;
pts = get_v ( bc ) ;
if ( pts > mask ) {
pts - = mask + 1 ;
2004-04-03 23:00:14 +02:00
} else {
2004-05-02 03:03:55 +02:00
if ( stream - > last_pts = = AV_NOPTS_VALUE ) {
av_log ( s , AV_LOG_ERROR , " no reference pts available \n " ) ;
return - 1 ;
}
pts = lsb2full ( stream , pts ) ;
2004-04-03 23:00:14 +02:00
}
} else {
2004-05-02 03:03:55 +02:00
if ( stream - > last_pts = = AV_NOPTS_VALUE ) {
av_log ( s , AV_LOG_ERROR , " no reference pts available \n " ) ;
return - 1 ;
}
pts = stream - > last_pts + stream - > lru_pts_delta [ flags & FLAG_PTS ] ;
2004-04-03 23:00:14 +02:00
}
2004-05-02 03:03:55 +02:00
if ( * key_frame_ret ) {
int64_t av_pts = pts * AV_TIME_BASE * stream - > rate_den / stream - > rate_num ;
// av_log(s, AV_LOG_DEBUG, "stream:%d start:%lld pts:%lld length:%lld\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos);
av_add_index_entry (
s - > streams [ stream_id ] ,
frame_start ,
av_pts ,
frame_start - nut - > stream [ stream_id ] . last_sync_pos ,
AVINDEX_KEYFRAME ) ;
nut - > stream [ stream_id ] . last_sync_pos = frame_start ;
// assert(nut->packet_start == frame_start);
2004-04-03 23:00:14 +02:00
}
2004-05-02 03:03:55 +02:00
assert ( size_mul > size_lsb ) ;
size = size_lsb ;
if ( flags & FLAG_DATA_SIZE )
size + = size_mul * get_v ( bc ) ;
2004-04-03 23:00:14 +02:00
2004-04-06 19:40:17 +02:00
//av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d\n", frame_start, frame_code, frame_type, key_frame, pts, size);
2004-05-02 03:03:55 +02:00
if ( frame_type = = 0 & & url_ftell ( bc ) - nut - > packet_start [ 2 ] + size > nut - > max_distance ) {
2004-04-06 19:40:17 +02:00
av_log ( s , AV_LOG_ERROR , " frame size too large \n " ) ;
return - 1 ;
}
2004-04-03 23:00:14 +02:00
2004-05-02 03:03:55 +02:00
* stream_id_ret = stream_id ;
* pts_ret = pts * AV_TIME_BASE * stream - > rate_den / stream - > rate_num ;
update ( nut , stream_id , frame_start , frame_type , frame_code , * key_frame_ret , size , pts ) ;
return size ;
}
static int decode_frame ( NUTContext * nut , AVPacket * pkt , int frame_code , int frame_type ) {
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
int size , stream_id , key_frame ;
int64_t pts ;
size = decode_frame_header ( nut , & key_frame , & pts , & stream_id , frame_code , frame_type ) ;
if ( size < 0 )
return - 1 ;
2003-09-05 20:45:32 +02:00
av_new_packet ( pkt , size ) ;
get_buffer ( bc , pkt - > data , size ) ;
2004-04-03 23:00:14 +02:00
pkt - > stream_index = stream_id ;
2003-09-05 20:45:32 +02:00
if ( key_frame )
pkt - > flags | = PKT_FLAG_KEY ;
2004-05-02 03:03:55 +02:00
pkt - > pts = pts ;
2004-04-03 23:00:14 +02:00
return 0 ;
}
2004-04-06 19:40:17 +02:00
static int nut_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
NUTContext * nut = s - > priv_data ;
ByteIOContext * bc = & s - > pb ;
2004-05-02 03:03:55 +02:00
int i , frame_code = 0 ;
2004-04-06 19:40:17 +02:00
for ( ; ; ) {
2004-04-08 02:22:22 +02:00
int frame_type = 0 ;
2004-04-06 19:40:17 +02:00
uint64_t tmp = nut - > next_startcode ;
nut - > next_startcode = 0 ;
if ( url_feof ( bc ) )
return - 1 ;
if ( ! tmp ) {
frame_code = get_byte ( bc ) ;
if ( frame_code = = ' N ' ) {
tmp = frame_code ;
2004-04-08 02:22:22 +02:00
for ( i = 1 ; i < 8 ; i + + )
tmp = ( tmp < < 8 ) + get_byte ( bc ) ;
2004-04-06 19:40:17 +02:00
}
}
switch ( tmp ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case INDEX_STARTCODE :
2004-05-02 03:03:55 +02:00
get_packetheader ( nut , bc , 0 ) ;
url_fseek ( bc , nut - > written_packet_size + nut - > packet_start [ 2 ] , SEEK_SET ) ;
2004-04-06 19:40:17 +02:00
break ;
case INFO_STARTCODE :
if ( decode_info_header ( nut ) < 0 )
goto resync ;
break ;
2004-04-08 02:22:22 +02:00
case KEYFRAME_STARTCODE :
frame_type = 2 ;
frame_code = get_byte ( bc ) ;
2004-04-06 19:40:17 +02:00
case 0 :
if ( decode_frame ( nut , pkt , frame_code , frame_type ) > = 0 )
return 0 ;
default :
resync :
2004-05-02 03:03:55 +02:00
av_log ( s , AV_LOG_DEBUG , " syncing from %lld \n " , nut - > packet_start [ 2 ] + 1 ) ;
tmp = find_any_startcode ( bc , nut - > packet_start [ 2 ] + 1 ) ;
2004-04-06 19:40:17 +02:00
if ( tmp = = 0 )
return - 1 ;
av_log ( s , AV_LOG_DEBUG , " sync \n " ) ;
2004-05-02 03:03:55 +02:00
nut - > next_startcode = tmp ;
2004-04-08 02:22:22 +02:00
}
}
}
2004-04-12 18:50:03 +02:00
static int64_t nut_read_timestamp ( AVFormatContext * s , int stream_index , int64_t * pos_arg , int64_t pos_limit ) {
2004-04-08 02:22:22 +02:00
NUTContext * nut = s - > priv_data ;
2004-04-12 18:50:03 +02:00
StreamContext * stream ;
2004-04-08 02:22:22 +02:00
ByteIOContext * bc = & s - > pb ;
int64_t pos , pts ;
uint64_t code ;
2004-05-02 03:03:55 +02:00
int frame_code , step , stream_id , i , size , key_frame ;
2004-04-08 02:22:22 +02:00
av_log ( s , AV_LOG_DEBUG , " read_timestamp(X,%d,%lld,%lld) \n " , stream_index , * pos_arg , pos_limit ) ;
if ( * pos_arg < 0 )
return AV_NOPTS_VALUE ;
pos = * pos_arg ;
step = FFMIN ( 16 * 1024 , pos ) ;
do {
pos - = step ;
code = find_any_startcode ( bc , pos ) ;
2004-05-02 03:03:55 +02:00
if ( code & & url_ftell ( bc ) - 8 < = * pos_arg )
2004-04-08 02:22:22 +02:00
break ;
step = FFMIN ( 2 * step , pos ) ;
} while ( step ) ;
if ( ! code ) //nothing found, not even after pos_arg
return AV_NOPTS_VALUE ;
url_fseek ( bc , - 8 , SEEK_CUR ) ;
for ( i = 0 ; i < s - > nb_streams ; i + + )
nut - > stream [ i ] . last_sync_pos = url_ftell ( bc ) ;
for ( ; ; ) {
2004-05-02 03:03:55 +02:00
int frame_type = 0 ;
2004-04-08 02:22:22 +02:00
int64_t pos = url_ftell ( bc ) ;
uint64_t tmp = 0 ;
2004-05-02 03:03:55 +02:00
if ( pos > pos_limit | | url_feof ( bc ) )
2004-04-08 02:22:22 +02:00
return AV_NOPTS_VALUE ;
frame_code = get_byte ( bc ) ;
if ( frame_code = = ' N ' ) {
tmp = frame_code ;
for ( i = 1 ; i < 8 ; i + + )
tmp = ( tmp < < 8 ) + get_byte ( bc ) ;
}
//av_log(s, AV_LOG_DEBUG, "before switch %llX at=%lld\n", tmp, pos);
switch ( tmp ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case INDEX_STARTCODE :
case INFO_STARTCODE :
2004-05-02 03:03:55 +02:00
get_packetheader ( nut , bc , 0 ) ;
assert ( nut - > packet_start [ 2 ] = = pos ) ;
url_fseek ( bc , nut - > written_packet_size + pos , SEEK_SET ) ;
2004-04-08 02:22:22 +02:00
break ;
case KEYFRAME_STARTCODE :
2004-05-02 03:03:55 +02:00
frame_type = 2 ;
2004-04-08 02:22:22 +02:00
frame_code = get_byte ( bc ) ;
case 0 :
2004-05-02 03:03:55 +02:00
size = decode_frame_header ( nut , & key_frame , & pts , & stream_id , frame_code , frame_type ) ;
if ( size < 0 )
2004-04-08 02:22:22 +02:00
goto resync ;
2004-04-12 18:50:03 +02:00
stream = & nut - > stream [ stream_id ] ;
2004-05-02 03:03:55 +02:00
if ( stream_id ! = stream_index | | ! key_frame | | pos < * pos_arg ) {
url_fseek ( bc , size , SEEK_CUR ) ;
2004-04-08 02:22:22 +02:00
break ;
}
2004-05-02 03:03:55 +02:00
* pos_arg = pos ;
2004-04-08 02:22:22 +02:00
return pts ;
default :
resync :
2004-05-02 03:03:55 +02:00
av_log ( s , AV_LOG_DEBUG , " syncing from %lld \n " , nut - > packet_start [ 2 ] + 1 ) ;
if ( ! find_any_startcode ( bc , nut - > packet_start [ 2 ] + 1 ) )
2004-04-08 02:22:22 +02:00
return AV_NOPTS_VALUE ;
url_fseek ( bc , - 8 , SEEK_CUR ) ;
2004-04-06 19:40:17 +02:00
}
}
2004-04-08 02:22:22 +02:00
return AV_NOPTS_VALUE ;
}
static int nut_read_seek ( AVFormatContext * s , int stream_index , int64_t target_ts ) {
2004-05-02 03:03:55 +02:00
// NUTContext *nut = s->priv_data;
2004-04-12 18:50:03 +02:00
int64_t pos ;
2004-04-08 02:22:22 +02:00
2004-04-12 18:50:03 +02:00
if ( av_seek_frame_binary ( s , stream_index , target_ts ) < 0 )
return - 1 ;
2004-04-08 02:22:22 +02:00
2004-04-12 18:50:03 +02:00
pos = url_ftell ( & s - > pb ) ;
2004-05-02 03:03:55 +02:00
nut_read_timestamp ( s , stream_index , & pos , pos - 1 ) ;
2004-04-08 02:22:22 +02:00
return 0 ;
2004-04-06 19:40:17 +02:00
}
2004-04-03 23:00:14 +02:00
static int nut_read_close ( AVFormatContext * s )
{
NUTContext * nut = s - > priv_data ;
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
av_freep ( & s - > streams [ i ] - > codec . extradata ) ;
}
av_freep ( & nut - > stream ) ;
2003-09-05 20:45:32 +02:00
return 0 ;
}
static AVInputFormat nut_iformat = {
" nut " ,
" nut format " ,
sizeof ( NUTContext ) ,
nut_probe ,
nut_read_header ,
nut_read_packet ,
2004-04-03 23:00:14 +02:00
nut_read_close ,
2004-04-08 02:22:22 +02:00
nut_read_seek ,
2004-04-12 18:50:03 +02:00
nut_read_timestamp ,
2003-09-05 20:45:32 +02:00
. extensions = " nut " ,
} ;
2003-10-14 06:15:53 +02:00
# ifdef CONFIG_ENCODERS
2003-09-05 20:45:32 +02:00
static AVOutputFormat nut_oformat = {
" nut " ,
" nut format " ,
" video/x-nut " ,
" nut " ,
sizeof ( NUTContext ) ,
2004-04-04 22:24:28 +02:00
# ifdef CONFIG_VORBIS
2003-09-05 20:45:32 +02:00
CODEC_ID_VORBIS ,
# elif defined(CONFIG_MP3LAME)
2003-09-09 00:04:29 +02:00
CODEC_ID_MP3 ,
2003-09-05 20:45:32 +02:00
# else
2003-09-07 02:37:46 +02:00
CODEC_ID_MP2 , /* AC3 needs liba52 decoder */
2003-09-05 20:45:32 +02:00
# endif
CODEC_ID_MPEG4 ,
nut_write_header ,
nut_write_packet ,
nut_write_trailer ,
} ;
2003-10-14 06:15:53 +02:00
# endif //CONFIG_ENCODERS
2003-09-05 20:45:32 +02:00
int nut_init ( void )
{
av_register_input_format ( & nut_iformat ) ;
2003-10-14 06:15:53 +02:00
# ifdef CONFIG_ENCODERS
2003-09-05 20:45:32 +02:00
av_register_output_format ( & nut_oformat ) ;
2003-10-14 06:15:53 +02:00
# endif //CONFIG_ENCODERS
2003-09-05 20:45:32 +02:00
return 0 ;
}