2003-09-05 21:45:32 +03:00
/*
2004-04-04 00:00:14 +03:00
* " NUT " Container Format muxer and demuxer ( DRAFT - 200403 ? ? )
2003-09-05 21:45:32 +03:00
* Copyright ( c ) 2003 Alex Beregszaszi
2004-04-04 00:00:14 +03:00
* Copyright ( c ) 2004 Michael Niedermayer
2003-09-05 21:45:32 +03: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
2006-01-13 00:43:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2003-09-05 21:45:32 +03:00
*
*
2005-06-08 00:21:54 +03:00
* Visit the official site at http : //www.nut.hu/
2003-09-05 21:45:32 +03:00
*
*/
/*
* TODO :
* - index writing
2004-04-05 01:34:26 +03:00
* - index packet reading support
2003-09-05 21:45:32 +03:00
*/
//#define DEBUG 1
2004-04-04 00:00:14 +03:00
# include <limits.h>
2003-09-05 21:45:32 +03:00
# include "avformat.h"
# include "mpegaudio.h"
2003-09-08 23:00:13 +03:00
# include "avi.h"
2003-09-05 21:45:32 +03:00
2004-04-04 00:00:14 +03:00
# undef NDEBUG
# include <assert.h>
2004-05-20 19:00:22 +03:00
//#define TRACE
2003-09-06 17:03:35 +03:00
//from /dev/random
2005-12-17 20:14:38 +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-04-04 00:00:14 +03:00
2004-06-15 00:30:36 +03:00
# define ID_STRING "nut / multimedia container\0"
2004-05-02 04:03:55 +03:00
# define MAX_DISTANCE (1024*16-1)
# define MAX_SHORT_DISTANCE (1024*4-1)
2004-04-04 00:00:14 +03:00
2004-05-20 19:00:22 +03:00
# define FLAG_DATA_SIZE 1
# define FLAG_KEY_FRAME 2
# define FLAG_INVALID 4
2004-04-04 00:00:14 +03:00
typedef struct {
uint8_t flags ;
uint8_t stream_id_plus1 ;
2004-05-02 04:03:55 +03:00
uint16_t size_mul ;
uint16_t size_lsb ;
2004-05-20 19:00:22 +03:00
int16_t timestamp_delta ;
uint8_t reserved_count ;
2004-04-04 00:00:14 +03:00
} FrameCode ;
typedef struct {
int last_key_frame ;
int msb_timestamp_shift ;
int rate_num ;
int rate_den ;
int64_t last_pts ;
2004-04-08 03:22:22 +03:00
int64_t last_sync_pos ; ///<pos of last 1/2 type frame
2004-05-02 04:03:55 +03:00
int decode_delay ;
2004-04-04 00:00:14 +03:00
} StreamContext ;
2003-09-06 17:03:35 +03:00
2003-09-05 21:45:32 +03:00
typedef struct {
2004-04-04 00:00:14 +03:00
AVFormatContext * avf ;
int written_packet_size ;
2004-05-02 04:03:55 +03:00
int64_t packet_start [ 3 ] ; //0-> startcode less, 1-> short startcode 2-> long startcodes
2004-04-04 00:00:14 +03:00
FrameCode frame_code [ 256 ] ;
2005-01-08 16:21:33 +02:00
unsigned int stream_count ;
2004-04-06 20:40:17 +03:00
uint64_t next_startcode ; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable
2004-04-04 00:00:14 +03:00
StreamContext * stream ;
2004-05-02 04:03:55 +03:00
int max_distance ;
2004-06-15 00:30:36 +03:00
int max_short_distance ;
2004-05-20 19:00:22 +03:00
int rate_num ;
int rate_den ;
int short_startcode ;
2003-09-05 21:45:32 +03:00
} NUTContext ;
2004-04-05 01:34:26 +03:00
static char * info_table [ ] [ 2 ] = {
2005-12-22 03:10:11 +02:00
{ NULL , NULL } , // end
{ NULL , NULL } ,
{ NULL , " UTF8 " } ,
{ NULL , " v " } ,
{ NULL , " s " } ,
{ " StreamId " , " v " } ,
{ " SegmentId " , " v " } ,
{ " StartTimestamp " , " v " } ,
{ " EndTimestamp " , " v " } ,
{ " Author " , " UTF8 " } ,
{ " Title " , " UTF8 " } ,
{ " Description " , " UTF8 " } ,
{ " Copyright " , " UTF8 " } ,
{ " Encoder " , " UTF8 " } ,
{ " Keyword " , " UTF8 " } ,
{ " Cover " , " JPEG " } ,
{ " Cover " , " PNG " } ,
2004-04-05 01:34:26 +03:00
} ;
2005-06-03 11:54:32 +03:00
void ff_parse_specific_params ( AVCodecContext * stream , int * au_rate , int * au_ssize , int * au_scale ) ;
2004-04-04 00:00:14 +03:00
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 ] ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
stream - > last_key_frame = key_frame ;
2004-05-02 04:03:55 +03:00
nut - > packet_start [ frame_type ] = frame_start ;
2004-04-04 00:00:14 +03:00
stream - > last_pts = pts ;
}
2004-05-20 19:00:22 +03:00
static void reset ( AVFormatContext * s , int64_t global_ts ) {
2004-04-04 00:00:14 +03:00
NUTContext * nut = s - > priv_data ;
int i ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
StreamContext * stream = & nut - > stream [ i ] ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
stream - > last_key_frame = 1 ;
2004-05-20 19:00:22 +03:00
stream - > last_pts = av_rescale ( global_ts , stream - > rate_num * ( int64_t ) nut - > rate_den , stream - > rate_den * ( int64_t ) nut - > rate_num ) ;
2004-04-04 00:00:14 +03:00
}
}
static void build_frame_code ( AVFormatContext * s ) {
NUTContext * nut = s - > priv_data ;
2004-05-20 19:00:22 +03:00
int key_frame , index , pred , stream_id ;
2004-04-04 00:00:14 +03:00
int start = 0 ;
int end = 255 ;
int keyframe_0_esc = s - > nb_streams > 2 ;
2004-05-20 19:00:22 +03:00
int pred_table [ 10 ] ;
2004-04-04 00:00:14 +03:00
if ( keyframe_0_esc ) {
2004-05-02 04:03:55 +03:00
/* keyframe = 0 escape */
FrameCode * ft = & nut - > frame_code [ start ] ;
2004-05-20 19:00:22 +03:00
ft - > flags = FLAG_DATA_SIZE ;
2004-05-02 04:03:55 +03:00
ft - > stream_id_plus1 = 0 ;
ft - > size_mul = 1 ;
2004-05-20 19:00:22 +03:00
ft - > timestamp_delta = 0 ;
2004-05-02 04:03:55 +03:00
start + + ;
2004-04-04 00:00:14 +03: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 ;
2005-07-18 01:24:36 +03:00
AVCodecContext * codec = s - > streams [ stream_id ] - > codec ;
2004-04-04 00:00:14 +03:00
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 ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
{
FrameCode * ft = & nut - > frame_code [ start2 ] ;
ft - > flags = FLAG_KEY_FRAME * key_frame ;
2004-05-20 19:00:22 +03:00
ft - > flags | = FLAG_DATA_SIZE ;
2004-05-02 04:03:55 +03:00
ft - > stream_id_plus1 = stream_id + 1 ;
ft - > size_mul = 1 ;
2004-05-20 19:00:22 +03:00
ft - > timestamp_delta = 0 ;
2004-05-02 04:03:55 +03:00
start2 + + ;
2004-04-04 00:00:14 +03: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-20 19:00:22 +03:00
int pts ;
for ( pts = 0 ; pts < 2 ; pts + + ) {
2004-05-02 04:03:55 +03:00
for ( pred = 0 ; pred < 2 ; pred + + ) {
2004-04-04 00:00:14 +03:00
FrameCode * ft = & nut - > frame_code [ start2 ] ;
2004-05-20 19:00:22 +03:00
ft - > flags = FLAG_KEY_FRAME * key_frame ;
2004-04-04 00:00:14 +03:00
ft - > stream_id_plus1 = stream_id + 1 ;
2004-05-02 04:03:55 +03:00
ft - > size_mul = frame_bytes + 2 ;
ft - > size_lsb = frame_bytes + pred ;
2004-05-20 19:00:22 +03:00
ft - > timestamp_delta = pts ;
2004-04-04 00:00:14 +03:00
start2 + + ;
}
}
} 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 ;
2004-05-20 19:00:22 +03:00
ft - > timestamp_delta = 1 ;
2004-04-04 00:00:14 +03:00
start2 + + ;
}
# endif
2004-05-20 19:00:22 +03:00
if ( codec - > has_b_frames ) {
pred_count = 5 ;
pred_table [ 0 ] = - 2 ;
pred_table [ 1 ] = - 1 ;
pred_table [ 2 ] = 1 ;
pred_table [ 3 ] = 3 ;
pred_table [ 4 ] = 4 ;
} else if ( codec - > codec_id = = CODEC_ID_VORBIS ) {
pred_count = 3 ;
pred_table [ 0 ] = 2 ;
pred_table [ 1 ] = 9 ;
pred_table [ 2 ] = 16 ;
} else {
pred_count = 1 ;
pred_table [ 0 ] = 1 ;
}
2004-04-04 00:00:14 +03: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 ] ;
2004-05-20 19:00:22 +03:00
ft - > flags = FLAG_KEY_FRAME * key_frame ;
2004-04-04 00:00:14 +03:00
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 ;
2004-05-20 19:00:22 +03:00
ft - > timestamp_delta = pred_table [ pred ] ;
2004-04-04 00:00:14 +03:00
}
}
}
memmove ( & nut - > frame_code [ ' N ' + 1 ] , & nut - > frame_code [ ' N ' ] , sizeof ( FrameCode ) * ( 255 - ' N ' ) ) ;
2004-05-20 19:00:22 +03:00
nut - > frame_code [ ' N ' ] . flags = FLAG_INVALID ;
2004-04-04 00:00:14 +03:00
}
2003-09-05 21:45:32 +03:00
static uint64_t get_v ( ByteIOContext * bc )
{
uint64_t val = 0 ;
2004-04-06 20:40:17 +03:00
for ( ; ; )
2003-09-05 21:45:32 +03:00
{
2005-12-22 03:10:11 +02:00
int tmp = get_byte ( bc ) ;
2003-09-05 21:45:32 +03:00
2005-12-22 03:10:11 +02:00
if ( tmp & 0x80 )
val = ( val < < 7 ) + tmp - 0x80 ;
else {
2004-05-02 04:03:55 +03:00
//av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp);
2005-12-22 03:10:11 +02:00
return ( val < < 7 ) + tmp ;
2004-05-02 04:03:55 +03:00
}
2003-09-05 21:45:32 +03:00
}
return - 1 ;
}
2005-01-08 16:21:33 +02:00
static int get_str ( ByteIOContext * bc , char * string , unsigned int maxlen ) {
unsigned int len = get_v ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-04-05 01:34:26 +03:00
if ( len & & maxlen )
get_buffer ( bc , string , FFMIN ( len , maxlen ) ) ;
while ( len > maxlen ) {
get_byte ( bc ) ;
len - - ;
}
2003-09-10 16:00:24 +03:00
2004-04-05 01:34:26 +03:00
if ( maxlen )
string [ FFMIN ( len , maxlen - 1 ) ] = 0 ;
2005-12-17 20:14:38 +02:00
2004-04-05 01:34:26 +03:00
if ( maxlen = = len )
return - 1 ;
else
return 0 ;
2003-09-05 21:45:32 +03:00
}
2004-05-20 19:00:22 +03:00
static int64_t get_s ( ByteIOContext * bc ) {
int64_t v = get_v ( bc ) + 1 ;
if ( v & 1 ) return - ( v > > 1 ) ;
else return ( v > > 1 ) ;
}
2004-04-08 03:22:22 +03:00
static uint64_t get_vb ( ByteIOContext * bc ) {
uint64_t val = 0 ;
2005-01-08 16:21:33 +02:00
unsigned int i = get_v ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-04-08 03:22:22 +03:00
if ( i > 8 )
return UINT64_MAX ;
2005-12-17 20:14:38 +02:00
2004-04-08 03:22:22 +03:00
while ( i - - )
val = ( val < < 8 ) + get_byte ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val);
2004-04-08 03:22:22 +03:00
return val ;
}
2004-05-20 19:00:22 +03:00
# ifdef TRACE
static inline uint64_t get_v_trace ( ByteIOContext * bc , char * file , char * func , int line ) {
uint64_t v = get_v ( bc ) ;
printf ( " get_v %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
return v ;
}
static inline int64_t get_s_trace ( ByteIOContext * bc , char * file , char * func , int line ) {
int64_t v = get_s ( bc ) ;
printf ( " get_s %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
return v ;
}
static inline uint64_t get_vb_trace ( ByteIOContext * bc , char * file , char * func , int line ) {
uint64_t v = get_vb ( bc ) ;
printf ( " get_vb %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
return v ;
}
# define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# endif
2004-05-02 04:03:55 +03:00
static int get_packetheader ( NUTContext * nut , ByteIOContext * bc , int calculate_checksum )
2003-09-05 21:45:32 +03:00
{
2004-05-02 04:03:55 +03:00
int64_t start , size ;
start = url_ftell ( bc ) - 8 ;
2004-04-04 00:00:14 +03:00
size = get_v ( bc ) ;
2005-09-11 11:32:25 +03:00
init_checksum ( bc , calculate_checksum ? update_adler32 : NULL , 0 ) ;
2004-05-02 04:03:55 +03:00
nut - > packet_start [ 2 ] = start ;
2004-04-04 00:00:14 +03:00
nut - > written_packet_size = size ;
return size ;
2003-09-05 21:45:32 +03:00
}
2004-04-05 15:02:10 +03:00
static int check_checksum ( ByteIOContext * bc ) {
unsigned long checksum = get_checksum ( bc ) ;
return checksum ! = get_be32 ( bc ) ;
}
2003-09-06 19:29:05 +03:00
/**
2005-12-17 20:14:38 +02:00
*
2003-09-06 19:29:05 +03:00
*/
static int get_length ( uint64_t val ) {
int i ;
2003-09-05 21:45:32 +03:00
2004-04-08 03:22:22 +03:00
for ( i = 7 ; val > > i ; i + = 7 ) ;
2003-09-05 21:45:32 +03:00
2004-04-08 03:22:22 +03:00
return i ;
2003-09-05 21:45:32 +03:00
}
2004-04-06 01:00:59 +03:00
static uint64_t find_any_startcode ( ByteIOContext * bc , int64_t pos ) {
uint64_t state = 0 ;
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
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 20:40:17 +03:00
while ( ! url_feof ( bc ) ) {
2004-04-06 01:00:59 +03: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 03:22:22 +03:00
2004-04-06 01:00:59 +03:00
return 0 ;
}
2004-04-08 03:22:22 +03: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 01:00:59 +03:00
for ( ; ; ) {
uint64_t startcode = find_any_startcode ( bc , pos ) ;
if ( startcode = = code )
2004-04-08 03:22:22 +03:00
return url_ftell ( bc ) - 8 ;
2004-04-06 01:00:59 +03:00
else if ( startcode = = 0 )
return - 1 ;
pos = - 1 ;
}
}
2005-09-23 03:25:41 +03:00
# ifdef CONFIG_MUXERS
2004-05-20 19:00:22 +03:00
2004-04-08 03:22:22 +03:00
static void put_v ( ByteIOContext * bc , uint64_t val )
2003-09-05 21:45:32 +03:00
{
int i ;
2004-05-02 04:03:55 +03:00
//av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val);
2003-09-05 21:45:32 +03:00
val & = 0x7FFFFFFFFFFFFFFFULL ; // FIXME can only encode upto 63 bits currently
2003-09-06 19:29:05 +03:00
i = get_length ( val ) ;
2003-09-05 21:45:32 +03:00
2003-09-06 17:03:35 +03:00
for ( i - = 7 ; i > 0 ; i - = 7 ) {
2005-12-22 03:10:11 +02:00
put_byte ( bc , 0x80 | ( val > > i ) ) ;
2003-09-06 17:03:35 +03:00
}
2003-09-05 21:45:32 +03:00
put_byte ( bc , val & 0x7f ) ;
}
2004-04-08 03:22:22 +03:00
/**
* stores a string as vb .
*/
static void put_str ( ByteIOContext * bc , const char * string ) {
2004-04-05 01:34:26 +03:00
int len = strlen ( string ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
put_v ( bc , len ) ;
2004-04-05 01:34:26 +03:00
put_buffer ( bc , string , len ) ;
2004-04-08 03:22:22 +03:00
}
2005-03-13 03:58:29 +02:00
static void put_s ( ByteIOContext * bc , int64_t val ) {
2004-05-20 19:00:22 +03:00
if ( val < = 0 ) put_v ( bc , - 2 * val ) ;
else put_v ( bc , 2 * val - 1 ) ;
}
2004-04-08 03:22:22 +03:00
static void put_vb ( ByteIOContext * bc , uint64_t val ) {
int i ;
2005-12-17 20:14:38 +02:00
2004-04-08 03:22:22 +03: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 23:00:13 +03:00
}
2004-05-20 19:00:22 +03:00
# ifdef TRACE
static inline void put_v_trace ( ByteIOContext * bc , uint64_t v , char * file , char * func , int line ) {
printf ( " get_v %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
put_v ( bc , v ) ;
}
static inline void put_s_trace ( ByteIOContext * bc , int64_t v , char * file , char * func , int line ) {
printf ( " get_s %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
put_s ( bc , v ) ;
}
static inline void put_vb_trace ( ByteIOContext * bc , uint64_t v , char * file , char * func , int line ) {
printf ( " get_vb %5lld / %llX in %s %s:%d \n " , v , v , file , func , line ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
put_vb ( bc , v ) ;
}
# define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# define put_vb(bc, v) put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
# endif
2004-04-05 15:02:10 +03:00
static int put_packetheader ( NUTContext * nut , ByteIOContext * bc , int max_size , int calculate_checksum )
2003-09-05 21:45:32 +03:00
{
put_flush_packet ( bc ) ;
2005-09-11 11:28:03 +03:00
nut - > packet_start [ 2 ] = url_ftell ( bc ) - 8 ;
2004-04-04 00:00:14 +03:00
nut - > written_packet_size = max_size ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
/* packet header */
2004-04-04 00:00:14 +03:00
put_v ( bc , nut - > written_packet_size ) ; /* forward ptr */
2003-09-05 21:45:32 +03:00
2005-09-11 11:32:25 +03:00
if ( calculate_checksum )
init_checksum ( bc , update_adler32 , 0 ) ;
2003-09-05 21:45:32 +03:00
return 0 ;
}
2005-09-11 11:28:03 +03:00
/**
*
* must not be called more then once per packet
*/
2004-04-05 15:02:10 +03:00
static int update_packetheader ( NUTContext * nut , ByteIOContext * bc , int additional_size , int calculate_checksum ) {
2004-05-02 04:03:55 +03:00
int64_t start = nut - > packet_start [ 2 ] ;
2004-04-04 00:00:14 +03:00
int64_t cur = url_ftell ( bc ) ;
2005-09-11 11:28:03 +03:00
int size = cur - start - get_length ( nut - > written_packet_size ) / 7 - 8 ;
2005-12-17 20:14:38 +02:00
2004-04-05 15:02:10 +03:00
if ( calculate_checksum )
size + = 4 ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
if ( size ! = nut - > written_packet_size ) {
int i ;
assert ( size < = nut - > written_packet_size ) ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
url_fseek ( bc , start + 8 , SEEK_SET ) ;
2004-04-04 00:00:14 +03: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
2005-12-17 20:14:38 +02:00
2004-04-05 15:02:10 +03:00
if ( calculate_checksum )
put_be32 ( bc , get_checksum ( bc ) ) ;
2004-04-04 00:00:14 +03:00
}
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
return 0 ;
}
static int nut_write_header ( AVFormatContext * s )
{
NUTContext * nut = s - > priv_data ;
ByteIOContext * bc = & s - > pb ;
AVCodecContext * codec ;
2004-05-20 19:00:22 +03:00
int i , j , tmp_time , tmp_flags , tmp_stream , tmp_mul , tmp_size , tmp_fields ;
2003-09-05 21:45:32 +03:00
2004-04-04 00:00:14 +03:00
nut - > avf = s ;
2005-12-17 20:14:38 +02:00
nut - > stream =
2005-12-22 03:10:11 +02:00
av_mallocz ( sizeof ( StreamContext ) * s - > nb_streams ) ;
2005-12-17 20:14:38 +02:00
2004-06-15 00:30:36 +03:00
put_buffer ( bc , ID_STRING , strlen ( ID_STRING ) ) ;
put_byte ( bc , 0 ) ;
nut - > packet_start [ 2 ] = url_ftell ( bc ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
/* main header */
2003-09-06 17:03:35 +03:00
put_be64 ( bc , MAIN_STARTCODE ) ;
2004-04-05 15:02:10 +03:00
put_packetheader ( nut , bc , 120 + 5 * 256 , 1 ) ;
2004-05-02 04:03:55 +03:00
put_v ( bc , 2 ) ; /* version */
2003-09-05 21:45:32 +03:00
put_v ( bc , s - > nb_streams ) ;
2004-05-02 04:03:55 +03:00
put_v ( bc , MAX_DISTANCE ) ;
2004-06-15 00:30:36 +03:00
put_v ( bc , MAX_SHORT_DISTANCE ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
put_v ( bc , nut - > rate_num = 1 ) ;
put_v ( bc , nut - > rate_den = 2 ) ;
put_v ( bc , nut - > short_startcode = 0x4EFE79 ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
build_frame_code ( s ) ;
2004-05-20 19:00:22 +03:00
assert ( nut - > frame_code [ ' N ' ] . flags = = FLAG_INVALID ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
tmp_time = tmp_flags = tmp_stream = tmp_mul = tmp_size = /*tmp_res=*/ INT_MAX ;
2004-04-04 00:00:14 +03:00
for ( i = 0 ; i < 256 ; ) {
2004-05-20 19:00:22 +03:00
tmp_fields = 0 ;
tmp_size = 0 ;
if ( tmp_time ! = nut - > frame_code [ i ] . timestamp_delta ) tmp_fields = 1 ;
if ( tmp_mul ! = nut - > frame_code [ i ] . size_mul ) tmp_fields = 2 ;
if ( tmp_stream ! = nut - > frame_code [ i ] . stream_id_plus1 ) tmp_fields = 3 ;
if ( tmp_size ! = nut - > frame_code [ i ] . size_lsb ) tmp_fields = 4 ;
// if(tmp_res != nut->frame_code[i].res ) tmp_fields=5;
tmp_time = nut - > frame_code [ i ] . timestamp_delta ;
tmp_flags = nut - > frame_code [ i ] . flags ;
tmp_stream = nut - > frame_code [ i ] . stream_id_plus1 ;
tmp_mul = nut - > frame_code [ i ] . size_mul ;
tmp_size = nut - > frame_code [ i ] . size_lsb ;
// tmp_res = nut->frame_code[i].res;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
for ( j = 0 ; i < 256 ; j + + , i + + ) {
2004-05-20 19:00:22 +03:00
if ( nut - > frame_code [ i ] . timestamp_delta ! = tmp_time ) break ;
2004-04-04 00:00:14 +03:00
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 ;
2004-05-20 19:00:22 +03:00
if ( nut - > frame_code [ i ] . size_lsb ! = tmp_size + j ) break ;
// if(nut->frame_code[i].res != tmp_res ) break;
2004-04-04 00:00:14 +03:00
}
2004-05-20 19:00:22 +03:00
if ( j ! = tmp_mul - tmp_size ) tmp_fields = 6 ;
put_v ( bc , tmp_flags ) ;
put_v ( bc , tmp_fields ) ;
if ( tmp_fields > 0 ) put_s ( bc , tmp_time ) ;
if ( tmp_fields > 1 ) put_v ( bc , tmp_mul ) ;
if ( tmp_fields > 2 ) put_v ( bc , tmp_stream ) ;
if ( tmp_fields > 3 ) put_v ( bc , tmp_size ) ;
if ( tmp_fields > 4 ) put_v ( bc , 0 /*tmp_res*/ ) ;
if ( tmp_fields > 5 ) put_v ( bc , j ) ;
2004-04-04 00:00:14 +03:00
}
2004-04-05 15:02:10 +03:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
/* stream headers */
for ( i = 0 ; i < s - > nb_streams ; i + + )
{
2005-12-22 03:10:11 +02:00
int nom , denom , ssize ;
2003-10-03 01:33:55 +03:00
2005-12-22 03:10:11 +02:00
codec = s - > streams [ i ] - > codec ;
2005-12-17 20:14:38 +02:00
2005-12-22 03:10:11 +02:00
put_be64 ( bc , STREAM_STARTCODE ) ;
put_packetheader ( nut , bc , 120 + codec - > extradata_size , 1 ) ;
put_v ( bc , i /*s->streams[i]->index*/ ) ;
2005-06-03 11:54:32 +03:00
switch ( codec - > codec_type ) {
case CODEC_TYPE_VIDEO : put_v ( bc , 0 ) ; break ;
case CODEC_TYPE_AUDIO : put_v ( bc , 1 ) ; break ;
// case CODEC_TYPE_TEXT : put_v(bc, 2); break;
case CODEC_TYPE_DATA : put_v ( bc , 3 ) ; break ;
default : return - 1 ;
}
2005-12-22 03:10:11 +02:00
if ( codec - > codec_tag )
put_vb ( bc , codec - > codec_tag ) ;
else if ( codec - > codec_type = = CODEC_TYPE_VIDEO )
{
put_vb ( bc , codec_get_bmp_tag ( codec - > codec_id ) ) ;
}
else if ( codec - > codec_type = = CODEC_TYPE_AUDIO )
{
put_vb ( bc , codec_get_wav_tag ( codec - > codec_id ) ) ;
}
2004-04-05 01:34:26 +03:00
else
2004-04-08 03:22:22 +03:00
put_vb ( bc , 0 ) ;
2005-12-17 20:14:38 +02:00
2005-06-03 11:54:32 +03:00
ff_parse_specific_params ( codec , & nom , & ssize , & denom ) ;
2003-10-15 18:21:46 +03:00
2004-04-04 00:00:14 +03:00
nut - > stream [ i ] . rate_num = nom ;
nut - > stream [ i ] . rate_den = denom ;
2004-05-23 19:26:12 +03:00
av_set_pts_info ( s - > streams [ i ] , 60 , denom , nom ) ;
2004-04-04 00:00:14 +03:00
2005-12-22 03:10:11 +02:00
put_v ( bc , codec - > bit_rate ) ;
put_vb ( bc , 0 ) ; /* no language code */
put_v ( bc , nom ) ;
put_v ( bc , denom ) ;
2004-04-04 00:00:14 +03:00
if ( nom / denom < 1000 )
2005-12-22 03:10:11 +02:00
nut - > stream [ i ] . msb_timestamp_shift = 7 ;
2004-04-04 00:00:14 +03:00
else
2005-12-22 03:10:11 +02:00
nut - > stream [ i ] . msb_timestamp_shift = 14 ;
put_v ( bc , nut - > stream [ i ] . msb_timestamp_shift ) ;
2004-05-02 04:03:55 +03:00
put_v ( bc , codec - > has_b_frames ) ;
2005-12-22 03:10:11 +02:00
put_byte ( bc , 0 ) ; /* flags: 0x1 - fixed_fps, 0x2 - index_present */
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
if ( codec - > extradata_size ) {
put_v ( bc , 1 ) ;
put_v ( bc , codec - > extradata_size ) ;
2005-12-17 20:14:38 +02:00
put_buffer ( bc , codec - > extradata , codec - > extradata_size ) ;
2004-04-04 00:00:14 +03:00
}
2005-12-22 03:10:11 +02:00
put_v ( bc , 0 ) ; /* end of codec specific headers */
switch ( codec - > codec_type )
{
case CODEC_TYPE_AUDIO :
put_v ( bc , codec - > sample_rate ) ;
put_v ( bc , 1 ) ;
put_v ( bc , codec - > channels ) ;
break ;
case CODEC_TYPE_VIDEO :
put_v ( bc , codec - > width ) ;
put_v ( bc , codec - > height ) ;
put_v ( bc , codec - > sample_aspect_ratio . num ) ;
put_v ( bc , codec - > sample_aspect_ratio . den ) ;
put_v ( bc , 0 ) ; /* csp type -- unknown */
break ;
2003-09-08 23:00:13 +03:00
default :
break ;
2005-12-22 03:10:11 +02:00
}
2004-04-05 15:02:10 +03:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-05 21:45:32 +03:00
}
/* info header */
2003-09-07 03:37:46 +03:00
put_be64 ( bc , INFO_STARTCODE ) ;
2004-04-05 01:34:26 +03:00
put_packetheader ( nut , bc , 30 + strlen ( s - > author ) + strlen ( s - > title ) +
2005-12-17 20:14:38 +02:00
strlen ( s - > comment ) + strlen ( s - > copyright ) + strlen ( LIBAVFORMAT_IDENT ) , 1 ) ;
2003-09-05 21:45:32 +03:00
if ( s - > author [ 0 ] )
{
2004-04-05 01:34:26 +03:00
put_v ( bc , 9 ) ; /* type */
put_str ( bc , s - > author ) ;
2003-09-05 21:45:32 +03:00
}
if ( s - > title [ 0 ] )
{
2004-04-05 01:34:26 +03:00
put_v ( bc , 10 ) ; /* type */
put_str ( bc , s - > title ) ;
2003-09-05 21:45:32 +03:00
}
if ( s - > comment [ 0 ] )
{
2004-04-05 01:34:26 +03:00
put_v ( bc , 11 ) ; /* type */
put_str ( bc , s - > comment ) ;
2003-09-05 21:45:32 +03:00
}
if ( s - > copyright [ 0 ] )
{
2004-04-05 01:34:26 +03:00
put_v ( bc , 12 ) ; /* type */
put_str ( bc , s - > copyright ) ;
2003-09-05 21:45:32 +03:00
}
/* encoder */
2005-07-18 01:24:36 +03:00
if ( ! ( s - > streams [ 0 ] - > codec - > flags & CODEC_FLAG_BITEXACT ) ) {
2004-04-12 23:06:23 +03:00
put_v ( bc , 13 ) ; /* type */
put_str ( bc , LIBAVFORMAT_IDENT ) ;
}
2005-12-17 20:14:38 +02:00
2003-09-07 02:17:17 +03:00
put_v ( bc , 0 ) ; /* eof info */
2004-04-05 15:02:10 +03:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
put_flush_packet ( bc ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
return 0 ;
}
2004-05-02 04:03:55 +03: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 ;
}
2004-05-29 05:06:32 +03:00
static int nut_write_packet ( AVFormatContext * s , AVPacket * pkt )
2003-09-05 21:45:32 +03:00
{
NUTContext * nut = s - > priv_data ;
2004-05-29 05:06:32 +03:00
StreamContext * stream = & nut - > stream [ pkt - > stream_index ] ;
2003-09-05 21:45:32 +03:00
ByteIOContext * bc = & s - > pb ;
2004-04-04 00:00:14 +03:00
int key_frame = 0 , full_pts = 0 ;
2003-09-05 21:45:32 +03:00
AVCodecContext * enc ;
2004-05-02 04:03:55 +03:00
int64_t coded_pts ;
2004-05-20 19:00:22 +03:00
int frame_type , best_length , frame_code , flags , i , size_mul , size_lsb , time_delta ;
2004-04-04 00:00:14 +03:00
const int64_t frame_start = url_ftell ( bc ) ;
2004-05-29 05:06:32 +03:00
int64_t pts = pkt - > pts ;
int size = pkt - > size ;
int stream_index = pkt - > stream_index ;
2003-09-05 21:45:32 +03:00
2005-07-18 01:24:36 +03:00
enc = s - > streams [ stream_index ] - > codec ;
2004-05-29 05:06:32 +03:00
key_frame = ! ! ( pkt - > flags & PKT_FLAG_KEY ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
frame_type = 0 ;
2004-05-02 04:03:55 +03: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 21:45:32 +03:00
2004-05-20 19:00:22 +03:00
if ( frame_type > 1 ) {
int64_t global_ts = av_rescale ( pts , stream - > rate_den * ( int64_t ) nut - > rate_num , stream - > rate_num * ( int64_t ) nut - > rate_den ) ;
reset ( s , global_ts ) ;
2005-12-22 03:10:11 +02:00
put_be64 ( bc , KEYFRAME_STARTCODE ) ;
2004-05-20 19:00:22 +03:00
put_v ( bc , global_ts ) ;
2004-04-04 00:00:14 +03:00
}
2004-05-20 19:00:22 +03:00
assert ( stream - > last_pts ! = AV_NOPTS_VALUE ) ;
coded_pts = pts & ( ( 1 < < stream - > msb_timestamp_shift ) - 1 ) ;
if ( lsb2full ( stream , coded_pts ) ! = pts )
full_pts = 1 ;
2004-04-04 00:00:14 +03:00
2004-05-02 04:03:55 +03:00
if ( full_pts )
coded_pts = pts + ( 1 < < stream - > msb_timestamp_shift ) ;
2004-04-04 00:00:14 +03: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 19:46:12 +03:00
int fc_key_frame ;
2004-04-04 00:00:14 +03:00
int length = 0 ;
size_mul = nut - > frame_code [ i ] . size_mul ;
size_lsb = nut - > frame_code [ i ] . size_lsb ;
2004-05-20 19:00:22 +03:00
time_delta = nut - > frame_code [ i ] . timestamp_delta ;
2004-04-04 00:00:14 +03:00
flags = nut - > frame_code [ i ] . flags ;
2004-05-02 04:03:55 +03:00
assert ( size_mul > size_lsb ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
if ( stream_id_plus1 = = 0 ) length + = get_length ( stream_index ) ;
else if ( stream_id_plus1 - 1 ! = stream_index )
continue ;
2004-04-09 19:46:12 +03:00
fc_key_frame = ! ! ( flags & FLAG_KEY_FRAME ) ;
2004-04-04 00:00:14 +03:00
assert ( key_frame = = 0 | | key_frame = = 1 ) ;
if ( fc_key_frame ! = key_frame )
continue ;
2004-05-02 04:03:55 +03:00
if ( flags & FLAG_DATA_SIZE ) {
2004-04-04 00:00:14 +03:00
if ( size % size_mul ! = size_lsb )
continue ;
2004-05-02 04:03:55 +03:00
length + = get_length ( size / size_mul ) ;
} else if ( size ! = size_lsb )
continue ;
2004-04-04 00:00:14 +03:00
2004-05-20 19:00:22 +03:00
if ( full_pts & & time_delta )
2004-04-04 00:00:14 +03:00
continue ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
if ( ! time_delta ) {
2004-05-02 04:03:55 +03:00
length + = get_length ( coded_pts ) ;
2004-04-04 00:00:14 +03:00
} else {
2004-05-20 19:00:22 +03:00
if ( time_delta ! = pts - stream - > last_pts )
2004-04-04 00:00:14 +03:00
continue ;
}
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 17:03:35 +03:00
2004-04-04 00:00:14 +03: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 ;
2004-05-20 19:00:22 +03:00
time_delta = nut - > frame_code [ frame_code ] . timestamp_delta ;
# ifdef TRACE
2004-04-04 00:00:14 +03:00
best_length / = 7 ;
best_length + + ; //frame_code
2004-05-02 04:03:55 +03:00
if ( frame_type = = 2 ) {
best_length + = 8 ; // startcode
2004-04-04 00:00:14 +03:00
}
2004-05-20 19:00:22 +03: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 fs:%lld \n " , key_frame , frame_type , full_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 , frame_start ) ;
2004-05-02 04:03:55 +03:00
// 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-04 00:00:14 +03:00
# endif
2004-05-02 04:03:55 +03:00
assert ( frame_type ! = 1 ) ; //short startcode not implemented yet
2004-04-04 00:00:14 +03:00
put_byte ( bc , frame_code ) ;
if ( nut - > frame_code [ frame_code ] . stream_id_plus1 = = 0 )
put_v ( bc , stream_index ) ;
2004-05-20 19:00:22 +03:00
if ( ! time_delta ) {
2004-05-02 04:03:55 +03:00
put_v ( bc , coded_pts ) ;
2004-04-04 00:00:14 +03:00
}
if ( flags & FLAG_DATA_SIZE )
put_v ( bc , size / size_mul ) ;
2004-05-20 19:00:22 +03:00
else
assert ( size = = size_lsb ) ;
2004-05-02 04:03:55 +03:00
if ( size > MAX_DISTANCE ) {
assert ( frame_type > 1 ) ;
2004-04-04 00:00:14 +03:00
}
2005-12-17 20:14:38 +02:00
2004-05-29 05:06:32 +03:00
put_buffer ( bc , pkt - > data , size ) ;
2003-09-05 21:45:32 +03:00
2004-04-04 00:00:14 +03:00
update ( nut , stream_index , frame_start , frame_type , frame_code , key_frame , size , pts ) ;
2005-12-17 20:14:38 +02:00
2003-09-05 21:45:32 +03:00
return 0 ;
}
static int nut_write_trailer ( AVFormatContext * s )
{
2003-12-08 19:54:40 +02:00
NUTContext * nut = s - > priv_data ;
2003-09-05 21:45:32 +03:00
ByteIOContext * bc = & s - > pb ;
2004-04-04 00:00:14 +03:00
2003-09-05 21:45:32 +03:00
#if 0
int i ;
/* WRITE INDEX */
for ( i = 0 ; s - > nb_streams ; i + + )
{
2005-12-22 03:10:11 +02:00
put_be64 ( bc , INDEX_STARTCODE ) ;
put_packetheader ( nut , bc , 64 , 1 ) ;
put_v ( bc , s - > streams [ i ] - > id ) ;
put_v ( bc , . . . ) ;
2004-04-05 15:02:10 +03:00
update_packetheader ( nut , bc , 0 , 1 ) ;
2003-09-05 21:45:32 +03:00
}
# endif
put_flush_packet ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
av_freep ( & nut - > stream ) ;
2003-09-05 21:45:32 +03:00
return 0 ;
}
2005-09-23 03:25:41 +03:00
# endif //CONFIG_MUXERS
2003-09-05 21:45:32 +03:00
static int nut_probe ( AVProbeData * p )
{
2003-09-06 17:03:35 +03:00
int i ;
2004-05-02 04:03:55 +03:00
uint64_t code = 0xff ;
2003-09-06 17:03:35 +03:00
for ( i = 0 ; i < p - > buf_size ; i + + ) {
2004-05-02 04:03:55 +03:00
code = ( code < < 8 ) | p - > buf [ i ] ;
2003-09-06 17:03:35 +03:00
if ( code = = MAIN_STARTCODE )
return AVPROBE_SCORE_MAX ;
}
return 0 ;
2003-09-05 21:45:32 +03:00
}
2004-04-06 01:00:59 +03:00
static int decode_main_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2003-09-05 21:45:32 +03:00
ByteIOContext * bc = & s - > pb ;
2003-09-06 17:03:35 +03:00
uint64_t tmp ;
2004-05-20 19:00:22 +03:00
int i , j , tmp_stream , tmp_mul , tmp_time , tmp_size , count , tmp_res ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 01:00:59 +03:00
2003-09-05 21:45:32 +03:00
tmp = get_v ( bc ) ;
2004-05-02 04:03:55 +03:00
if ( tmp ! = 2 ) {
2005-12-22 03:10:11 +02:00
av_log ( s , AV_LOG_ERROR , " bad version (% " PRId64 " ) \n " , tmp ) ;
2004-04-06 01:00:59 +03:00
return - 1 ;
}
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
nut - > stream_count = get_v ( bc ) ;
2005-01-08 16:21:33 +02:00
if ( nut - > stream_count > MAX_STREAMS ) {
av_log ( s , AV_LOG_ERROR , " too many streams \n " ) ;
return - 1 ;
}
2004-05-02 04:03:55 +03:00
nut - > max_distance = get_v ( bc ) ;
2004-06-15 00:30:36 +03:00
nut - > max_short_distance = get_v ( bc ) ;
2004-05-20 19:00:22 +03:00
nut - > rate_num = get_v ( bc ) ;
nut - > rate_den = get_v ( bc ) ;
nut - > short_startcode = get_v ( bc ) ;
if ( nut - > short_startcode > > 16 ! = ' N ' ) {
2005-12-22 03:10:11 +02:00
av_log ( s , AV_LOG_ERROR , " invalid short startcode %X \n " , nut - > short_startcode ) ;
2004-05-20 19:00:22 +03:00
return - 1 ;
}
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
for ( i = 0 ; i < 256 ; ) {
int tmp_flags = get_v ( bc ) ;
2004-05-20 19:00:22 +03:00
int tmp_fields = get_v ( bc ) ;
if ( tmp_fields > 0 ) tmp_time = get_s ( bc ) ;
if ( tmp_fields > 1 ) tmp_mul = get_v ( bc ) ;
if ( tmp_fields > 2 ) tmp_stream = get_v ( bc ) ;
if ( tmp_fields > 3 ) tmp_size = get_v ( bc ) ;
else tmp_size = 0 ;
if ( tmp_fields > 4 ) tmp_res = get_v ( bc ) ;
else tmp_res = 0 ;
if ( tmp_fields > 5 ) count = get_v ( bc ) ;
else count = tmp_mul - tmp_size ;
2005-12-17 20:14:38 +02:00
while ( tmp_fields - - > 6 )
2004-05-20 19:00:22 +03:00
get_v ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
if ( count = = 0 | | i + count > 256 ) {
av_log ( s , AV_LOG_ERROR , " illegal count %d at %d \n " , count , i ) ;
return - 1 ;
}
2004-05-20 19:00:22 +03:00
if ( tmp_stream > nut - > stream_count + 1 ) {
av_log ( s , AV_LOG_ERROR , " illegal stream number \n " ) ;
return - 1 ;
}
2004-04-04 00:00:14 +03:00
for ( j = 0 ; j < count ; j + + , i + + ) {
nut - > frame_code [ i ] . flags = tmp_flags ;
2004-05-20 19:00:22 +03:00
nut - > frame_code [ i ] . timestamp_delta = tmp_time ;
2004-04-04 00:00:14 +03:00
nut - > frame_code [ i ] . stream_id_plus1 = tmp_stream ;
nut - > frame_code [ i ] . size_mul = tmp_mul ;
2004-05-20 19:00:22 +03:00
nut - > frame_code [ i ] . size_lsb = tmp_size + j ;
nut - > frame_code [ i ] . reserved_count = tmp_res ;
2004-04-04 00:00:14 +03:00
}
}
2004-05-20 19:00:22 +03:00
if ( nut - > frame_code [ ' N ' ] . flags ! = FLAG_INVALID ) {
2004-04-04 00:00:14 +03:00
av_log ( s , AV_LOG_ERROR , " illegal frame_code table \n " ) ;
return - 1 ;
}
2004-04-06 01:00:59 +03:00
2004-04-05 15:02:10 +03:00
if ( check_checksum ( bc ) ) {
2005-04-24 20:21:11 +03:00
av_log ( s , AV_LOG_ERROR , " Main header checksum mismatch \n " ) ;
2004-04-05 15:02:10 +03:00
return - 1 ;
}
2003-12-08 19:54:40 +02:00
2004-04-06 01:00:59 +03:00
return 0 ;
}
static int decode_stream_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
2004-05-20 19:00:22 +03:00
int class , nom , denom , stream_id ;
2004-04-06 01:00:59 +03:00
uint64_t tmp ;
AVStream * st ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 01:00:59 +03:00
stream_id = get_v ( bc ) ;
if ( stream_id > = nut - > stream_count | | s - > streams [ stream_id ] )
return - 1 ;
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
st = av_new_stream ( s , stream_id ) ;
if ( ! st )
return AVERROR_NOMEM ;
2004-05-21 23:43:21 +03:00
2004-04-06 01:00:59 +03:00
class = get_v ( bc ) ;
2004-04-08 03:22:22 +03:00
tmp = get_vb ( bc ) ;
2005-07-18 01:24:36 +03:00
st - > codec - > codec_tag = tmp ;
2004-04-06 01:00:59 +03:00
switch ( class )
2003-09-05 21:45:32 +03:00
{
2004-04-06 01:00:59 +03:00
case 0 :
2005-07-18 01:24:36 +03:00
st - > codec - > codec_type = CODEC_TYPE_VIDEO ;
st - > codec - > codec_id = codec_get_bmp_id ( tmp ) ;
if ( st - > codec - > codec_id = = CODEC_ID_NONE )
2004-04-06 01:00:59 +03:00
av_log ( s , AV_LOG_ERROR , " Unknown codec?! \n " ) ;
break ;
2005-06-03 11:54:32 +03:00
case 1 :
case 32 : //compatibility
2005-07-18 01:24:36 +03:00
st - > codec - > codec_type = CODEC_TYPE_AUDIO ;
st - > codec - > codec_id = codec_get_wav_id ( tmp ) ;
if ( st - > codec - > codec_id = = CODEC_ID_NONE )
2004-04-06 01:00:59 +03:00
av_log ( s , AV_LOG_ERROR , " Unknown codec?! \n " ) ;
break ;
2005-06-03 11:54:32 +03:00
case 2 :
2005-07-18 01:24:36 +03:00
// st->codec->codec_type = CODEC_TYPE_TEXT;
2005-06-03 11:54:32 +03:00
// break;
case 3 :
2005-07-18 01:24:36 +03:00
st - > codec - > codec_type = CODEC_TYPE_DATA ;
2005-06-03 11:54:32 +03:00
break ;
2004-04-06 01:00:59 +03:00
default :
av_log ( s , AV_LOG_ERROR , " Unknown stream class (%d) \n " , class ) ;
2004-04-05 15:02:10 +03:00
return - 1 ;
2004-04-05 01:34:26 +03:00
}
2004-04-06 01:00:59 +03:00
s - > bit_rate + = get_v ( bc ) ;
2004-04-08 03:22:22 +03:00
get_vb ( bc ) ; /* language code */
2004-04-06 01:00:59 +03:00
nom = get_v ( bc ) ;
denom = get_v ( bc ) ;
nut - > stream [ stream_id ] . msb_timestamp_shift = get_v ( bc ) ;
2005-07-18 01:24:36 +03:00
st - > codec - > has_b_frames =
2004-05-02 04:03:55 +03:00
nut - > stream [ stream_id ] . decode_delay = get_v ( bc ) ;
2004-04-06 01:00:59 +03:00
get_byte ( bc ) ; /* flags */
/* codec specific data headers */
while ( get_v ( bc ) ! = 0 ) {
2005-07-18 01:24:36 +03:00
st - > codec - > extradata_size = get_v ( bc ) ;
if ( ( unsigned ) st - > codec - > extradata_size > ( 1 < < 30 ) )
2005-01-08 16:21:33 +02:00
return - 1 ;
2005-07-18 01:24:36 +03:00
st - > codec - > extradata = av_mallocz ( st - > codec - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-12-17 20:14:38 +02:00
get_buffer ( bc , st - > codec - > extradata , st - > codec - > extradata_size ) ;
2005-12-22 03:10:11 +02:00
// url_fskip(bc, get_v(bc));
2004-04-06 01:00:59 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) /* VIDEO */
2004-04-06 01:00:59 +03:00
{
2005-07-18 01:24:36 +03:00
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 ) ;
2004-04-06 01:00:59 +03:00
get_v ( bc ) ; /* csp type */
}
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_AUDIO ) /* AUDIO */
2004-04-06 01:00:59 +03:00
{
2005-07-18 01:24:36 +03:00
st - > codec - > sample_rate = get_v ( bc ) ;
2004-05-02 04:03:55 +03:00
get_v ( bc ) ; // samplerate_den
2005-07-18 01:24:36 +03:00
st - > codec - > channels = get_v ( bc ) ;
2004-04-06 01:00:59 +03:00
}
if ( check_checksum ( bc ) ) {
2005-04-24 20:21:11 +03:00
av_log ( s , AV_LOG_ERROR , " Stream header %d checksum mismatch \n " , stream_id ) ;
2004-04-06 01:00:59 +03:00
return - 1 ;
}
2004-05-23 19:26:12 +03:00
av_set_pts_info ( s - > streams [ stream_id ] , 60 , denom , nom ) ;
2004-04-06 01:00:59 +03:00
nut - > stream [ stream_id ] . rate_num = nom ;
nut - > stream [ stream_id ] . rate_den = denom ;
return 0 ;
}
2004-04-05 01:34:26 +03:00
2004-04-06 01:00:59 +03:00
static int decode_info_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
get_packetheader ( nut , bc , 1 ) ;
2004-04-06 01:00:59 +03: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 ] ) ) {
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_ERROR , " info id is too large %d %zd \n " , id , sizeof ( info_table ) / sizeof ( info_table [ 0 ] ) ) ;
2004-04-06 01:00:59 +03:00
return - 1 ;
}
2004-04-05 01:34:26 +03:00
2004-04-06 01:00:59 +03:00
type = info_table [ id ] [ 1 ] ;
name = info_table [ id ] [ 0 ] ;
2004-04-05 01:34:26 +03:00
//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);
2004-04-06 01:00:59 +03: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 01:34:26 +03:00
}
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
if ( ! strcmp ( type , " v " ) ) {
2005-02-24 21:08:50 +02:00
get_v ( bc ) ;
2004-04-06 01:00:59 +03:00
} 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 15:02:10 +03:00
}
2004-04-06 01:00:59 +03:00
}
if ( check_checksum ( bc ) ) {
2005-04-24 20:21:11 +03:00
av_log ( s , AV_LOG_ERROR , " Info header checksum mismatch \n " ) ;
2004-04-06 01:00:59 +03:00
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 ;
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
/* main header */
pos = 0 ;
for ( ; ; ) {
2004-04-08 03:22:22 +03:00
pos = find_startcode ( bc , MAIN_STARTCODE , pos ) + 1 ;
if ( pos < 0 ) {
2004-04-06 01:00:59 +03:00
av_log ( s , AV_LOG_ERROR , " no main startcode found \n " ) ;
return - 1 ;
}
if ( decode_main_header ( nut ) > = 0 )
break ;
}
2005-12-17 20:14:38 +02:00
2004-04-06 01:00:59 +03:00
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 03:22:22 +03:00
pos = find_startcode ( bc , STREAM_STARTCODE , pos ) + 1 ;
2005-06-03 11:54:32 +03:00
if ( pos < 0 + 1 ) {
2004-04-06 01:00:59 +03: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 20:40:17 +03:00
nut - > next_startcode = startcode ;
2004-04-06 01:00:59 +03:00
break ;
} else if ( startcode ! = INFO_STARTCODE ) {
continue ;
}
decode_info_header ( nut ) ;
}
2003-09-05 21:45:32 +03:00
return 0 ;
}
2004-05-20 19:00:22 +03: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 , int64_t frame_start ) {
2004-04-06 20:40:17 +03:00
AVFormatContext * s = nut - > avf ;
2004-04-04 00:00:14 +03:00
StreamContext * stream ;
2003-09-05 21:45:32 +03:00
ByteIOContext * bc = & s - > pb ;
2004-05-20 19:00:22 +03:00
int size , flags , size_mul , size_lsb , stream_id , time_delta ;
2003-12-08 19:54:40 +02:00
int64_t pts = 0 ;
2003-09-05 21:45:32 +03:00
2004-05-02 04:03:55 +03: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
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03: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-20 19:00:22 +03:00
time_delta = nut - > frame_code [ frame_code ] . timestamp_delta ;
2005-12-17 20:14:38 +02:00
2004-04-04 00:00:14 +03:00
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 20:40:17 +03: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 04:03:55 +03:00
* key_frame_ret = ! ! ( flags & FLAG_KEY_FRAME ) ;
2004-05-20 19:00:22 +03:00
if ( ! time_delta ) {
2004-05-02 04:03:55 +03:00
int64_t mask = ( 1 < < stream - > msb_timestamp_shift ) - 1 ;
pts = get_v ( bc ) ;
if ( pts > mask ) {
pts - = mask + 1 ;
2004-04-04 00:00:14 +03:00
} else {
2004-05-02 04:03:55 +03: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-04 00:00:14 +03:00
}
} else {
2004-05-02 04:03:55 +03:00
if ( stream - > last_pts = = AV_NOPTS_VALUE ) {
av_log ( s , AV_LOG_ERROR , " no reference pts available \n " ) ;
return - 1 ;
}
2004-05-20 19:00:22 +03:00
pts = stream - > last_pts + time_delta ;
2004-04-04 00:00:14 +03:00
}
2004-05-02 04:03:55 +03:00
if ( * key_frame_ret ) {
// 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 (
2005-12-17 20:14:38 +02:00
s - > streams [ stream_id ] ,
frame_start ,
pts ,
2004-05-02 04:03:55 +03:00
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-04 00:00:14 +03:00
}
2004-05-02 04:03:55 +03:00
assert ( size_mul > size_lsb ) ;
size = size_lsb ;
if ( flags & FLAG_DATA_SIZE )
size + = size_mul * get_v ( bc ) ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
# ifdef TRACE
av_log ( s , AV_LOG_DEBUG , " fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d mul:%d lsb:%d flags:%d delta:%d \n " , frame_start , frame_code , frame_type , * key_frame_ret , pts , size , size_mul , size_lsb , flags , time_delta ) ;
# endif
2004-04-06 20:40:17 +03:00
2004-05-02 04:03:55 +03:00
if ( frame_type = = 0 & & url_ftell ( bc ) - nut - > packet_start [ 2 ] + size > nut - > max_distance ) {
2004-04-06 20:40:17 +03:00
av_log ( s , AV_LOG_ERROR , " frame size too large \n " ) ;
return - 1 ;
}
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
* stream_id_ret = stream_id ;
2004-05-23 19:26:12 +03:00
* pts_ret = pts ;
2004-05-02 04:03:55 +03:00
update ( nut , stream_id , frame_start , frame_type , frame_code , * key_frame_ret , size , pts ) ;
return size ;
}
2004-05-20 19:00:22 +03:00
static int decode_frame ( NUTContext * nut , AVPacket * pkt , int frame_code , int frame_type , int64_t frame_start ) {
2004-05-02 04:03:55 +03:00
AVFormatContext * s = nut - > avf ;
ByteIOContext * bc = & s - > pb ;
2005-03-17 03:25:01 +02:00
int size , stream_id , key_frame , discard ;
int64_t pts , last_IP_pts ;
2005-12-17 20:14:38 +02:00
2004-05-20 19:00:22 +03:00
size = decode_frame_header ( nut , & key_frame , & pts , & stream_id , frame_code , frame_type , frame_start ) ;
2004-05-02 04:03:55 +03:00
if ( size < 0 )
return - 1 ;
2005-03-17 03:25:01 +02:00
discard = s - > streams [ stream_id ] - > discard ;
last_IP_pts = s - > streams [ stream_id ] - > last_IP_pts ;
if ( ( discard > = AVDISCARD_NONKEY & & ! key_frame )
| | ( discard > = AVDISCARD_BIDIR & & last_IP_pts ! = AV_NOPTS_VALUE & & last_IP_pts > pts )
| | discard > = AVDISCARD_ALL ) {
2005-01-22 15:36:02 +02:00
url_fskip ( bc , size ) ;
return 1 ;
}
2005-05-26 23:17:12 +03:00
av_get_packet ( bc , pkt , size ) ;
2004-04-04 00:00:14 +03:00
pkt - > stream_index = stream_id ;
2003-09-05 21:45:32 +03:00
if ( key_frame )
2005-12-22 03:10:11 +02:00
pkt - > flags | = PKT_FLAG_KEY ;
2004-05-02 04:03:55 +03:00
pkt - > pts = pts ;
2004-04-04 00:00:14 +03:00
return 0 ;
}
2004-04-06 20:40:17 +03:00
static int nut_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
NUTContext * nut = s - > priv_data ;
ByteIOContext * bc = & s - > pb ;
2005-01-22 15:36:02 +02:00
int i , frame_code = 0 , ret ;
2004-04-06 20:40:17 +03:00
for ( ; ; ) {
2004-05-20 19:00:22 +03:00
int64_t pos = url_ftell ( bc ) ;
2004-04-08 03:22:22 +03:00
int frame_type = 0 ;
2004-04-06 20:40:17 +03:00
uint64_t tmp = nut - > next_startcode ;
nut - > next_startcode = 0 ;
if ( url_feof ( bc ) )
return - 1 ;
2004-05-20 19:00:22 +03:00
if ( tmp ) {
pos - = 8 ;
} else {
2004-04-06 20:40:17 +03:00
frame_code = get_byte ( bc ) ;
if ( frame_code = = ' N ' ) {
tmp = frame_code ;
2004-04-08 03:22:22 +03:00
for ( i = 1 ; i < 8 ; i + + )
tmp = ( tmp < < 8 ) + get_byte ( bc ) ;
2004-04-06 20:40:17 +03:00
}
}
switch ( tmp ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case INDEX_STARTCODE :
2004-05-02 04:03:55 +03:00
get_packetheader ( nut , bc , 0 ) ;
2004-05-20 19:00:22 +03:00
assert ( nut - > packet_start [ 2 ] = = pos ) ;
2005-09-11 11:28:03 +03:00
url_fseek ( bc , nut - > written_packet_size , SEEK_CUR ) ;
2004-04-06 20:40:17 +03:00
break ;
case INFO_STARTCODE :
if ( decode_info_header ( nut ) < 0 )
goto resync ;
break ;
2004-04-08 03:22:22 +03:00
case KEYFRAME_STARTCODE :
frame_type = 2 ;
2004-05-20 19:00:22 +03:00
reset ( s , get_v ( bc ) ) ;
2004-04-08 03:22:22 +03:00
frame_code = get_byte ( bc ) ;
2004-04-06 20:40:17 +03:00
case 0 :
2005-01-22 15:36:02 +02:00
ret = decode_frame ( nut , pkt , frame_code , frame_type , pos ) ;
if ( ret = = 0 )
2004-04-06 20:40:17 +03:00
return 0 ;
2005-01-22 15:36:02 +02:00
else if ( ret = = 1 ) //ok but discard packet
break ;
2004-04-06 20:40:17 +03:00
default :
resync :
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_DEBUG , " syncing from % " PRId64 " \n " , nut - > packet_start [ 2 ] + 1 ) ;
2004-05-02 04:03:55 +03:00
tmp = find_any_startcode ( bc , nut - > packet_start [ 2 ] + 1 ) ;
2004-04-06 20:40:17 +03:00
if ( tmp = = 0 )
return - 1 ;
av_log ( s , AV_LOG_DEBUG , " sync \n " ) ;
2004-05-02 04:03:55 +03:00
nut - > next_startcode = tmp ;
2004-04-08 03:22:22 +03:00
}
}
}
2004-04-12 19:50:03 +03:00
static int64_t nut_read_timestamp ( AVFormatContext * s , int stream_index , int64_t * pos_arg , int64_t pos_limit ) {
2004-04-08 03:22:22 +03:00
NUTContext * nut = s - > priv_data ;
2004-04-12 19:50:03 +03:00
StreamContext * stream ;
2004-04-08 03:22:22 +03:00
ByteIOContext * bc = & s - > pb ;
int64_t pos , pts ;
uint64_t code ;
2004-05-02 04:03:55 +03:00
int frame_code , step , stream_id , i , size , key_frame ;
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_DEBUG , " read_timestamp(X,%d,% " PRId64 " ,% " PRId64 " ) \n " , stream_index , * pos_arg , pos_limit ) ;
2004-04-08 03:22:22 +03:00
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 04:03:55 +03:00
if ( code & & url_ftell ( bc ) - 8 < = * pos_arg )
2004-04-08 03:22:22 +03: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 ) ;
2005-12-17 20:14:38 +02:00
2004-04-08 03:22:22 +03:00
for ( ; ; ) {
2004-05-02 04:03:55 +03:00
int frame_type = 0 ;
2004-04-08 03:22:22 +03:00
int64_t pos = url_ftell ( bc ) ;
uint64_t tmp = 0 ;
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
if ( pos > pos_limit | | url_feof ( bc ) )
2004-04-08 03:22:22 +03: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 04:03:55 +03:00
get_packetheader ( nut , bc , 0 ) ;
assert ( nut - > packet_start [ 2 ] = = pos ) ;
2005-09-11 11:28:03 +03:00
url_fseek ( bc , nut - > written_packet_size , SEEK_CUR ) ;
2004-04-08 03:22:22 +03:00
break ;
case KEYFRAME_STARTCODE :
2004-05-02 04:03:55 +03:00
frame_type = 2 ;
2004-05-20 19:00:22 +03:00
reset ( s , get_v ( bc ) ) ;
2004-04-08 03:22:22 +03:00
frame_code = get_byte ( bc ) ;
case 0 :
2004-05-20 19:00:22 +03:00
size = decode_frame_header ( nut , & key_frame , & pts , & stream_id , frame_code , frame_type , pos ) ;
2004-05-02 04:03:55 +03:00
if ( size < 0 )
2004-04-08 03:22:22 +03:00
goto resync ;
2005-12-17 20:14:38 +02:00
2004-04-12 19:50:03 +03:00
stream = & nut - > stream [ stream_id ] ;
2004-05-02 04:03:55 +03:00
if ( stream_id ! = stream_index | | ! key_frame | | pos < * pos_arg ) {
url_fseek ( bc , size , SEEK_CUR ) ;
2004-04-08 03:22:22 +03:00
break ;
}
2005-12-17 20:14:38 +02:00
2004-05-02 04:03:55 +03:00
* pos_arg = pos ;
2004-04-08 03:22:22 +03:00
return pts ;
default :
resync :
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_DEBUG , " syncing from % " PRId64 " \n " , nut - > packet_start [ 2 ] + 1 ) ;
2004-05-02 04:03:55 +03:00
if ( ! find_any_startcode ( bc , nut - > packet_start [ 2 ] + 1 ) )
2004-04-08 03:22:22 +03:00
return AV_NOPTS_VALUE ;
url_fseek ( bc , - 8 , SEEK_CUR ) ;
2004-04-06 20:40:17 +03:00
}
}
2004-04-08 03:22:22 +03:00
return AV_NOPTS_VALUE ;
}
2004-10-11 01:05:43 +03:00
static int nut_read_seek ( AVFormatContext * s , int stream_index , int64_t target_ts , int flags ) {
2004-05-02 04:03:55 +03:00
// NUTContext *nut = s->priv_data;
2004-04-12 19:50:03 +03:00
int64_t pos ;
2004-04-08 03:22:22 +03:00
2004-10-11 01:05:43 +03:00
if ( av_seek_frame_binary ( s , stream_index , target_ts , flags ) < 0 )
2004-04-12 19:50:03 +03:00
return - 1 ;
2004-04-08 03:22:22 +03:00
2004-04-12 19:50:03 +03:00
pos = url_ftell ( & s - > pb ) ;
2004-05-02 04:03:55 +03:00
nut_read_timestamp ( s , stream_index , & pos , pos - 1 ) ;
2004-04-08 03:22:22 +03:00
return 0 ;
2004-04-06 20:40:17 +03:00
}
2004-04-04 00:00:14 +03:00
static int nut_read_close ( AVFormatContext * s )
{
NUTContext * nut = s - > priv_data ;
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2005-07-18 01:24:36 +03:00
av_freep ( & s - > streams [ i ] - > codec - > extradata ) ;
2004-04-04 00:00:14 +03:00
}
av_freep ( & nut - > stream ) ;
2003-09-05 21:45:32 +03:00
return 0 ;
}
static AVInputFormat nut_iformat = {
" nut " ,
" nut format " ,
sizeof ( NUTContext ) ,
nut_probe ,
nut_read_header ,
nut_read_packet ,
2004-04-04 00:00:14 +03:00
nut_read_close ,
2004-04-08 03:22:22 +03:00
nut_read_seek ,
2004-04-12 19:50:03 +03:00
nut_read_timestamp ,
2003-09-05 21:45:32 +03:00
. extensions = " nut " ,
} ;
2005-09-23 03:25:41 +03:00
# ifdef CONFIG_MUXERS
2003-09-05 21:45:32 +03:00
static AVOutputFormat nut_oformat = {
" nut " ,
" nut format " ,
" video/x-nut " ,
" nut " ,
sizeof ( NUTContext ) ,
2005-02-24 17:18:02 +02:00
# ifdef CONFIG_LIBVORBIS
2003-09-05 21:45:32 +03:00
CODEC_ID_VORBIS ,
# elif defined(CONFIG_MP3LAME)
2003-09-09 01:04:29 +03:00
CODEC_ID_MP3 ,
2003-09-05 21:45:32 +03:00
# else
2003-09-07 03:37:46 +03:00
CODEC_ID_MP2 , /* AC3 needs liba52 decoder */
2003-09-05 21:45:32 +03:00
# endif
CODEC_ID_MPEG4 ,
nut_write_header ,
nut_write_packet ,
nut_write_trailer ,
2005-06-27 03:24:34 +03:00
. flags = AVFMT_GLOBALHEADER ,
2003-09-05 21:45:32 +03:00
} ;
2005-09-23 03:25:41 +03:00
# endif //CONFIG_MUXERS
2003-09-05 21:45:32 +03:00
int nut_init ( void )
{
av_register_input_format ( & nut_iformat ) ;
2005-09-23 03:25:41 +03:00
# ifdef CONFIG_MUXERS
2003-09-05 21:45:32 +03:00
av_register_output_format ( & nut_oformat ) ;
2005-09-23 03:25:41 +03:00
# endif //CONFIG_MUXERS
2003-09-05 21:45:32 +03:00
return 0 ;
}