2006-11-11 02:35:50 +01:00
/*
* " NUT " Container Format demuxer
* Copyright ( c ) 2004 - 2006 Michael Niedermayer
* Copyright ( c ) 2003 Alex Beregszaszi
*
2011-03-18 18:35:10 +01:00
* This file is part of Libav .
2006-11-11 02:35:50 +01:00
*
2011-03-18 18:35:10 +01:00
* Libav is free software ; you can redistribute it and / or
2006-11-11 02:35:50 +01:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
2011-03-18 18:35:10 +01:00
* Libav is distributed in the hope that it will be useful ,
2006-11-11 02:35:50 +01:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2011-03-18 18:35:10 +01:00
* License along with Libav ; if not , write to the Free Software
2006-11-11 02:35:50 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2009-02-28 00:10:34 +01:00
# include <strings.h>
2008-05-09 13:56:36 +02:00
# include "libavutil/avstring.h"
2009-01-11 23:19:48 +01:00
# include "libavutil/bswap.h"
2008-05-09 13:56:36 +02:00
# include "libavutil/tree.h"
2011-03-14 20:38:57 +01:00
# include "avio_internal.h"
2006-11-11 02:35:50 +01:00
# include "nut.h"
# undef NDEBUG
# include <assert.h>
2010-08-18 22:34:31 +02:00
# if FF_API_MAX_STREAMS
2010-08-10 18:36:36 +02:00
# define NUT_MAX_STREAMS MAX_STREAMS
# else
# define NUT_MAX_STREAMS 256 /* arbitrary sanity check value */
# endif
2011-02-20 11:04:12 +01:00
static int get_str ( AVIOContext * bc , char * string , unsigned int maxlen ) {
2011-03-14 20:38:57 +01:00
unsigned int len = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( len & & maxlen )
2011-02-21 16:43:01 +01:00
avio_read ( bc , string , FFMIN ( len , maxlen ) ) ;
2006-11-11 02:35:50 +01:00
while ( len > maxlen ) {
2011-02-21 16:43:01 +01:00
avio_r8 ( bc ) ;
2006-11-11 02:35:50 +01:00
len - - ;
}
if ( maxlen )
string [ FFMIN ( len , maxlen - 1 ) ] = 0 ;
if ( maxlen = = len )
return - 1 ;
else
return 0 ;
}
2011-02-20 11:04:12 +01:00
static int64_t get_s ( AVIOContext * bc ) {
2011-03-14 20:38:57 +01:00
int64_t v = ffio_read_varlen ( bc ) + 1 ;
2006-11-11 02:35:50 +01:00
if ( v & 1 ) return - ( v > > 1 ) ;
else return ( v > > 1 ) ;
}
2011-02-20 11:04:12 +01:00
static uint64_t get_fourcc ( AVIOContext * bc ) {
2011-03-14 20:38:57 +01:00
unsigned int len = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
2011-02-21 16:43:01 +01:00
if ( len = = 2 ) return avio_rl16 ( bc ) ;
else if ( len = = 4 ) return avio_rl32 ( bc ) ;
2006-11-11 02:35:50 +01:00
else return - 1 ;
}
# ifdef TRACE
2011-02-20 11:04:12 +01:00
static inline uint64_t get_v_trace ( AVIOContext * bc , char * file , char * func , int line ) {
2011-03-14 20:38:57 +01:00
uint64_t v = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
2007-08-09 23:04:10 +02:00
av_log ( NULL , AV_LOG_DEBUG , " get_v %5 " PRId64 " / % " PRIX64 " in %s %s:%d \n " , v , v , file , func , line ) ;
2006-11-11 02:35:50 +01:00
return v ;
}
2011-02-20 11:04:12 +01:00
static inline int64_t get_s_trace ( AVIOContext * bc , char * file , char * func , int line ) {
2006-11-11 02:35:50 +01:00
int64_t v = get_s ( bc ) ;
2007-08-09 23:04:10 +02:00
av_log ( NULL , AV_LOG_DEBUG , " get_s %5 " PRId64 " / % " PRIX64 " in %s %s:%d \n " , v , v , file , func , line ) ;
2006-11-11 02:35:50 +01:00
return v ;
}
2011-02-20 11:04:12 +01:00
static inline uint64_t get_vb_trace ( AVIOContext * bc , char * file , char * func , int line ) {
2006-11-11 02:35:50 +01:00
uint64_t v = get_vb ( bc ) ;
2007-08-09 23:04:10 +02:00
av_log ( NULL , AV_LOG_DEBUG , " get_vb %5 " PRId64 " / % " PRIX64 " in %s %s:%d \n " , v , v , file , func , line ) ;
2006-11-11 02:35:50 +01:00
return v ;
}
2011-03-14 20:38:57 +01:00
# define ffio_read_varlen(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
2006-11-11 02:35:50 +01:00
# 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
2011-02-20 11:04:12 +01:00
static int get_packetheader ( NUTContext * nut , AVIOContext * bc , int calculate_checksum , uint64_t startcode )
2006-11-11 02:35:50 +01:00
{
2007-04-24 07:50:30 +02:00
int64_t size ;
2011-03-03 20:11:45 +01:00
// start= avio_tell(bc) - 8;
2006-11-11 02:35:50 +01:00
2010-07-11 00:12:30 +02:00
startcode = av_be2ne64 ( startcode ) ;
2010-07-03 12:25:32 +02:00
startcode = ff_crc04C11DB7_update ( 0 , ( uint8_t * ) & startcode , 8 ) ;
2007-08-09 23:35:13 +02:00
2011-03-17 12:56:25 +01:00
ffio_init_checksum ( bc , ff_crc04C11DB7_update , startcode ) ;
2011-03-14 20:38:57 +01:00
size = ffio_read_varlen ( bc ) ;
2007-02-28 04:28:31 +01:00
if ( size > 4096 )
2011-02-21 16:43:01 +01:00
avio_rb32 ( bc ) ;
2011-03-17 13:04:38 +01:00
if ( ffio_get_checksum ( bc ) & & size > 4096 )
2007-08-09 14:51:08 +02:00
return - 1 ;
2006-11-11 02:35:50 +01:00
2011-03-17 12:56:25 +01:00
ffio_init_checksum ( bc , calculate_checksum ? ff_crc04C11DB7_update : NULL , 0 ) ;
2006-11-11 02:35:50 +01:00
return size ;
}
2011-02-20 11:04:12 +01:00
static uint64_t find_any_startcode ( AVIOContext * bc , int64_t pos ) {
2006-11-11 02:35:50 +01:00
uint64_t state = 0 ;
if ( pos > = 0 )
2011-02-28 14:57:54 +01:00
avio_seek ( bc , pos , SEEK_SET ) ; //note, this may fail if the stream is not seekable, but that should not matter, as in this case we simply start where we currently are
2006-11-11 02:35:50 +01:00
2011-03-07 21:50:25 +01:00
while ( ! bc - > eof_reached ) {
2011-02-21 16:43:01 +01:00
state = ( state < < 8 ) | avio_r8 ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( ( state > > 56 ) ! = ' N ' )
continue ;
switch ( state ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case SYNCPOINT_STARTCODE :
case INFO_STARTCODE :
case INDEX_STARTCODE :
return state ;
}
}
return 0 ;
}
/**
2007-08-17 12:45:50 +02:00
* Find the given startcode .
2006-11-11 02:35:50 +01:00
* @ param code the startcode
* @ param pos the start position of the search , or - 1 if the current position
2010-03-30 17:50:57 +02:00
* @ return the position of the startcode or - 1 if not found
2006-11-11 02:35:50 +01:00
*/
2011-02-20 11:04:12 +01:00
static int64_t find_startcode ( AVIOContext * bc , uint64_t code , int64_t pos ) {
2006-11-11 02:35:50 +01:00
for ( ; ; ) {
uint64_t startcode = find_any_startcode ( bc , pos ) ;
if ( startcode = = code )
2011-03-03 20:11:45 +01:00
return avio_tell ( bc ) - 8 ;
2006-11-11 02:35:50 +01:00
else if ( startcode = = 0 )
return - 1 ;
pos = - 1 ;
}
}
static int nut_probe ( AVProbeData * p ) {
int i ;
uint64_t code = 0 ;
for ( i = 0 ; i < p - > buf_size ; i + + ) {
code = ( code < < 8 ) | p - > buf [ i ] ;
if ( code = = MAIN_STARTCODE )
return AVPROBE_SCORE_MAX ;
}
return 0 ;
}
# define GET_V(dst, check) \
2011-03-14 20:38:57 +01:00
tmp = ffio_read_varlen ( bc ) ; \
2006-11-11 02:35:50 +01:00
if ( ! ( check ) ) { \
av_log ( s , AV_LOG_ERROR , " Error " # dst " is (% " PRId64 " ) \n " , tmp ) ; \
return - 1 ; \
} \
dst = tmp ;
2011-02-20 11:04:12 +01:00
static int skip_reserved ( AVIOContext * bc , int64_t pos ) {
2011-03-03 20:11:45 +01:00
pos - = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( pos < 0 ) {
2011-02-28 14:57:54 +01:00
avio_seek ( bc , pos , SEEK_CUR ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
} else {
while ( pos - - )
2011-02-21 16:43:01 +01:00
avio_r8 ( bc ) ;
2006-11-11 02:35:50 +01:00
return 0 ;
}
}
static int decode_main_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-11 02:35:50 +01:00
uint64_t tmp , end ;
unsigned int stream_count ;
2008-02-15 03:36:09 +01:00
int i , j , tmp_stream , tmp_mul , tmp_pts , tmp_size , count , tmp_res , tmp_head_idx ;
2008-02-13 21:13:29 +01:00
int64_t tmp_match ;
2006-11-11 02:35:50 +01:00
2007-08-09 23:35:13 +02:00
end = get_packetheader ( nut , bc , 1 , MAIN_STARTCODE ) ;
2011-03-03 20:11:45 +01:00
end + = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
GET_V ( tmp , tmp > = 2 & & tmp < = 3 )
2010-08-10 18:36:36 +02:00
GET_V ( stream_count , tmp > 0 & & tmp < = NUT_MAX_STREAMS )
2006-11-11 02:35:50 +01:00
2011-03-14 20:38:57 +01:00
nut - > max_distance = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( nut - > max_distance > 65536 ) {
av_log ( s , AV_LOG_DEBUG , " max_distance %d \n " , nut - > max_distance ) ;
nut - > max_distance = 65536 ;
}
GET_V ( nut - > time_base_count , tmp > 0 & & tmp < INT_MAX / sizeof ( AVRational ) )
nut - > time_base = av_malloc ( nut - > time_base_count * sizeof ( AVRational ) ) ;
for ( i = 0 ; i < nut - > time_base_count ; i + + ) {
GET_V ( nut - > time_base [ i ] . num , tmp > 0 & & tmp < ( 1ULL < < 31 ) )
GET_V ( nut - > time_base [ i ] . den , tmp > 0 & & tmp < ( 1ULL < < 31 ) )
2009-01-17 12:13:33 +01:00
if ( av_gcd ( nut - > time_base [ i ] . num , nut - > time_base [ i ] . den ) ! = 1 ) {
2006-11-11 02:35:50 +01:00
av_log ( s , AV_LOG_ERROR , " time base invalid \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
}
tmp_pts = 0 ;
tmp_mul = 1 ;
tmp_stream = 0 ;
2008-02-13 21:13:29 +01:00
tmp_match = 1 - ( 1LL < < 62 ) ;
2008-02-15 03:36:09 +01:00
tmp_head_idx = 0 ;
2006-11-11 02:35:50 +01:00
for ( i = 0 ; i < 256 ; ) {
2011-03-14 20:38:57 +01:00
int tmp_flags = ffio_read_varlen ( bc ) ;
int tmp_fields = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( tmp_fields > 0 ) tmp_pts = get_s ( bc ) ;
2011-03-14 20:38:57 +01:00
if ( tmp_fields > 1 ) tmp_mul = ffio_read_varlen ( bc ) ;
if ( tmp_fields > 2 ) tmp_stream = ffio_read_varlen ( bc ) ;
if ( tmp_fields > 3 ) tmp_size = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
else tmp_size = 0 ;
2011-03-14 20:38:57 +01:00
if ( tmp_fields > 4 ) tmp_res = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
else tmp_res = 0 ;
2011-03-14 20:38:57 +01:00
if ( tmp_fields > 5 ) count = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
else count = tmp_mul - tmp_size ;
2008-02-13 21:13:29 +01:00
if ( tmp_fields > 6 ) tmp_match = get_s ( bc ) ;
2011-03-14 20:38:57 +01:00
if ( tmp_fields > 7 ) tmp_head_idx = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
2008-02-15 03:36:09 +01:00
while ( tmp_fields - - > 8 )
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( count = = 0 | | i + count > 256 ) {
av_log ( s , AV_LOG_ERROR , " illegal count %d at %d \n " , count , i ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
if ( tmp_stream > = stream_count ) {
av_log ( s , AV_LOG_ERROR , " illegal stream number \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
for ( j = 0 ; j < count ; j + + , i + + ) {
if ( i = = ' N ' ) {
nut - > frame_code [ i ] . flags = FLAG_INVALID ;
j - - ;
continue ;
}
nut - > frame_code [ i ] . flags = tmp_flags ;
nut - > frame_code [ i ] . pts_delta = tmp_pts ;
nut - > frame_code [ i ] . stream_id = tmp_stream ;
nut - > frame_code [ i ] . size_mul = tmp_mul ;
nut - > frame_code [ i ] . size_lsb = tmp_size + j ;
nut - > frame_code [ i ] . reserved_count = tmp_res ;
2008-02-15 03:36:09 +01:00
nut - > frame_code [ i ] . header_idx = tmp_head_idx ;
2006-11-11 02:35:50 +01:00
}
}
assert ( nut - > frame_code [ ' N ' ] . flags = = FLAG_INVALID ) ;
2011-03-03 20:11:45 +01:00
if ( end > avio_tell ( bc ) + 4 ) {
2008-02-15 03:36:09 +01:00
int rem = 1024 ;
GET_V ( nut - > header_count , tmp < 128U )
nut - > header_count + + ;
for ( i = 1 ; i < nut - > header_count ; i + + ) {
GET_V ( nut - > header_len [ i ] , tmp > 0 & & tmp < 256 ) ;
rem - = nut - > header_len [ i ] ;
if ( rem < 0 ) {
av_log ( s , AV_LOG_ERROR , " invalid elision header \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2008-02-15 03:36:09 +01:00
}
nut - > header [ i ] = av_malloc ( nut - > header_len [ i ] ) ;
2011-02-21 16:43:01 +01:00
avio_read ( bc , nut - > header [ i ] , nut - > header_len [ i ] ) ;
2008-02-15 03:36:09 +01:00
}
assert ( nut - > header_len [ 0 ] = = 0 ) ;
}
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) | | ffio_get_checksum ( bc ) ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " main header checksum mismatch \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
nut - > stream = av_mallocz ( sizeof ( StreamContext ) * stream_count ) ;
for ( i = 0 ; i < stream_count ; i + + ) {
av_new_stream ( s , i ) ;
}
return 0 ;
}
static int decode_stream_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-11 02:35:50 +01:00
StreamContext * stc ;
2006-11-16 10:59:46 +01:00
int class , stream_id ;
2006-11-11 02:35:50 +01:00
uint64_t tmp , end ;
AVStream * st ;
2007-08-09 23:35:13 +02:00
end = get_packetheader ( nut , bc , 1 , STREAM_STARTCODE ) ;
2011-03-03 20:11:45 +01:00
end + = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
2007-08-09 13:04:43 +02:00
GET_V ( stream_id , tmp < s - > nb_streams & & ! nut - > stream [ tmp ] . time_base ) ;
2006-11-11 02:35:50 +01:00
stc = & nut - > stream [ stream_id ] ;
st = s - > streams [ stream_id ] ;
if ( ! st )
2007-07-19 17:21:30 +02:00
return AVERROR ( ENOMEM ) ;
2006-11-11 02:35:50 +01:00
2011-03-14 20:38:57 +01:00
class = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
tmp = get_fourcc ( bc ) ;
st - > codec - > codec_tag = tmp ;
switch ( class )
{
case 0 :
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_VIDEO ;
2010-05-23 20:34:18 +02:00
st - > codec - > codec_id = av_codec_get_id (
( const AVCodecTag * const [ ] ) { ff_codec_bmp_tags , ff_nut_video_tags , 0 } ,
tmp ) ;
2006-11-11 02:35:50 +01:00
break ;
case 1 :
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_AUDIO ;
2009-06-23 01:09:34 +02:00
st - > codec - > codec_id = ff_codec_get_id ( ff_codec_wav_tags , tmp ) ;
2006-11-11 02:35:50 +01:00
break ;
case 2 :
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_SUBTITLE ;
2009-06-23 01:09:34 +02:00
st - > codec - > codec_id = ff_codec_get_id ( ff_nut_subtitle_tags , tmp ) ;
2008-03-03 00:11:36 +01:00
break ;
2006-11-11 02:35:50 +01:00
case 3 :
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_DATA ;
2006-11-11 02:35:50 +01:00
break ;
default :
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " unknown stream class (%d) \n " , class ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
}
2008-03-03 00:13:07 +01:00
if ( class < 3 & & st - > codec - > codec_id = = CODEC_ID_NONE )
2010-05-10 00:56:02 +02:00
av_log ( s , AV_LOG_ERROR , " Unknown codec tag '0x%04x' for stream number %d \n " ,
( unsigned int ) tmp , stream_id ) ;
2008-03-03 00:13:07 +01:00
2006-11-11 02:35:50 +01:00
GET_V ( stc - > time_base_id , tmp < nut - > time_base_count ) ;
GET_V ( stc - > msb_pts_shift , tmp < 16 ) ;
2011-03-14 20:38:57 +01:00
stc - > max_pts_distance = ffio_read_varlen ( bc ) ;
2007-08-17 12:45:50 +02:00
GET_V ( stc - > decode_delay , tmp < 1000 ) ; //sanity limit, raise this if Moore's law is true
2006-11-11 02:35:50 +01:00
st - > codec - > has_b_frames = stc - > decode_delay ;
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ; //stream flags
2006-11-11 02:35:50 +01:00
GET_V ( st - > codec - > extradata_size , tmp < ( 1 < < 30 ) ) ;
if ( st - > codec - > extradata_size ) {
st - > codec - > extradata = av_mallocz ( st - > codec - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2011-02-21 16:43:01 +01:00
avio_read ( bc , st - > codec - > extradata , st - > codec - > extradata_size ) ;
2006-11-11 02:35:50 +01:00
}
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2006-11-11 02:35:50 +01:00
GET_V ( st - > codec - > width , tmp > 0 )
GET_V ( st - > codec - > height , tmp > 0 )
2011-03-14 20:38:57 +01:00
st - > sample_aspect_ratio . num = ffio_read_varlen ( bc ) ;
st - > sample_aspect_ratio . den = ffio_read_varlen ( bc ) ;
2008-08-24 01:43:20 +02:00
if ( ( ! st - > sample_aspect_ratio . num ) ! = ( ! st - > sample_aspect_ratio . den ) ) {
av_log ( s , AV_LOG_ERROR , " invalid aspect ratio %d/%d \n " , st - > sample_aspect_ratio . num , st - > sample_aspect_ratio . den ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
}
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ; /* csp type */
2010-03-31 01:30:55 +02:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2006-11-11 02:35:50 +01:00
GET_V ( st - > codec - > sample_rate , tmp > 0 )
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ; // samplerate_den
2006-11-11 02:35:50 +01:00
GET_V ( st - > codec - > channels , tmp > 0 )
}
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) | | ffio_get_checksum ( bc ) ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " stream header %d checksum mismatch \n " , stream_id ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
}
2007-08-09 13:04:43 +02:00
stc - > time_base = & nut - > time_base [ stc - > time_base_id ] ;
av_set_pts_info ( s - > streams [ stream_id ] , 63 , stc - > time_base - > num , stc - > time_base - > den ) ;
2006-11-11 02:35:50 +01:00
return 0 ;
}
2008-03-07 20:25:09 +01:00
static void set_disposition_bits ( AVFormatContext * avf , char * value , int stream_id ) {
int flag = 0 , i ;
for ( i = 0 ; ff_nut_dispositions [ i ] . flag ; + + i ) {
if ( ! strcmp ( ff_nut_dispositions [ i ] . str , value ) )
flag = ff_nut_dispositions [ i ] . flag ;
}
if ( ! flag )
av_log ( avf , AV_LOG_INFO , " unknown disposition type '%s' \n " , value ) ;
for ( i = 0 ; i < avf - > nb_streams ; + + i )
if ( stream_id = = i | | stream_id = = - 1 )
avf - > streams [ i ] - > disposition | = flag ;
}
2006-11-11 02:35:50 +01:00
static int decode_info_header ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2010-03-01 08:26:41 +01:00
uint64_t tmp , chapter_start , chapter_len ;
unsigned int stream_id_plus1 , count ;
2006-11-11 02:35:50 +01:00
int chapter_id , i ;
int64_t value , end ;
2008-02-04 01:31:31 +01:00
char name [ 256 ] , str_value [ 1024 ] , type_str [ 256 ] ;
2008-02-04 01:33:52 +01:00
const char * type ;
2008-05-23 15:52:54 +02:00
AVChapter * chapter = NULL ;
2009-02-28 00:10:34 +01:00
AVStream * st = NULL ;
2010-10-24 09:28:04 +02:00
AVMetadata * * metadata = NULL ;
2006-11-11 02:35:50 +01:00
2007-08-09 23:35:13 +02:00
end = get_packetheader ( nut , bc , 1 , INFO_STARTCODE ) ;
2011-03-03 20:11:45 +01:00
end + = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
GET_V ( stream_id_plus1 , tmp < = s - > nb_streams )
chapter_id = get_s ( bc ) ;
2011-03-14 20:38:57 +01:00
chapter_start = ffio_read_varlen ( bc ) ;
chapter_len = ffio_read_varlen ( bc ) ;
count = ffio_read_varlen ( bc ) ;
2008-05-23 15:52:54 +02:00
if ( chapter_id & & ! stream_id_plus1 ) {
int64_t start = chapter_start / nut - > time_base_count ;
2008-05-23 20:15:13 +02:00
chapter = ff_new_chapter ( s , chapter_id ,
nut - > time_base [ chapter_start % nut - > time_base_count ] ,
start , start + chapter_len , NULL ) ;
2010-10-24 09:28:04 +02:00
metadata = & chapter - > metadata ;
} else if ( stream_id_plus1 ) {
2009-02-28 00:10:34 +01:00
st = s - > streams [ stream_id_plus1 - 1 ] ;
2010-10-24 09:28:04 +02:00
metadata = & st - > metadata ;
} else
metadata = & s - > metadata ;
2008-05-23 15:52:54 +02:00
2006-11-11 02:35:50 +01:00
for ( i = 0 ; i < count ; i + + ) {
get_str ( bc , name , sizeof ( name ) ) ;
value = get_s ( bc ) ;
if ( value = = - 1 ) {
type = " UTF-8 " ;
get_str ( bc , str_value , sizeof ( str_value ) ) ;
} else if ( value = = - 2 ) {
2008-02-04 01:33:52 +01:00
get_str ( bc , type_str , sizeof ( type_str ) ) ;
type = type_str ;
2006-11-11 02:35:50 +01:00
get_str ( bc , str_value , sizeof ( str_value ) ) ;
} else if ( value = = - 3 ) {
type = " s " ;
value = get_s ( bc ) ;
} else if ( value = = - 4 ) {
type = " t " ;
2011-03-14 20:38:57 +01:00
value = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
} else if ( value < - 4 ) {
type = " r " ;
get_s ( bc ) ;
} else {
type = " v " ;
}
2008-05-04 12:29:12 +02:00
if ( stream_id_plus1 > s - > nb_streams ) {
2008-03-07 20:25:09 +01:00
av_log ( s , AV_LOG_ERROR , " invalid stream id for info packet \n " ) ;
continue ;
}
2009-02-28 00:10:34 +01:00
if ( ! strcmp ( type , " UTF-8 " ) ) {
2010-10-24 09:28:04 +02:00
if ( chapter_id = = 0 & & ! strcmp ( name , " Disposition " ) ) {
2008-03-07 20:25:09 +01:00
set_disposition_bits ( s , str_value , stream_id_plus1 - 1 ) ;
2010-10-24 09:28:04 +02:00
continue ;
}
2009-02-28 00:10:34 +01:00
if ( metadata & & strcasecmp ( name , " Uses " )
& & strcasecmp ( name , " Depends " ) & & strcasecmp ( name , " Replaces " ) )
2010-04-25 16:27:42 +02:00
av_metadata_set2 ( metadata , name , str_value , 0 ) ;
2008-05-23 15:52:54 +02:00
}
2006-11-11 02:35:50 +01:00
}
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) | | ffio_get_checksum ( bc ) ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " info header checksum mismatch \n " ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
}
return 0 ;
}
2006-11-14 14:19:51 +01:00
static int decode_syncpoint ( NUTContext * nut , int64_t * ts , int64_t * back_ptr ) {
2006-11-11 02:35:50 +01:00
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-14 14:19:51 +01:00
int64_t end , tmp ;
2006-11-11 02:35:50 +01:00
2011-03-03 20:11:45 +01:00
nut - > last_syncpoint_pos = avio_tell ( bc ) - 8 ;
2006-11-11 02:35:50 +01:00
2007-08-09 23:35:13 +02:00
end = get_packetheader ( nut , bc , 1 , SYNCPOINT_STARTCODE ) ;
2011-03-03 20:11:45 +01:00
end + = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
2011-03-14 20:38:57 +01:00
tmp = ffio_read_varlen ( bc ) ;
* back_ptr = nut - > last_syncpoint_pos - 16 * ffio_read_varlen ( bc ) ;
2006-11-14 14:19:51 +01:00
if ( * back_ptr < 0 )
return - 1 ;
2006-11-11 02:35:50 +01:00
2008-02-04 11:27:32 +01:00
ff_nut_reset_ts ( nut , nut - > time_base [ tmp % nut - > time_base_count ] , tmp / nut - > time_base_count ) ;
2006-11-11 02:35:50 +01:00
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) | | ffio_get_checksum ( bc ) ) {
2006-11-11 20:37:21 +01:00
av_log ( s , AV_LOG_ERROR , " sync point checksum mismatch \n " ) ;
2006-11-11 02:35:50 +01:00
return - 1 ;
}
2006-11-14 14:19:51 +01:00
* ts = tmp / s - > nb_streams * av_q2d ( nut - > time_base [ tmp % s - > nb_streams ] ) * AV_TIME_BASE ;
2007-08-10 01:24:02 +02:00
ff_nut_add_sp ( nut , nut - > last_syncpoint_pos , * back_ptr , * ts ) ;
2006-11-14 14:19:51 +01:00
2006-11-11 02:35:50 +01:00
return 0 ;
}
2006-11-12 13:07:42 +01:00
static int find_and_decode_index ( NUTContext * nut ) {
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-12 13:07:42 +01:00
uint64_t tmp , end ;
int i , j , syncpoint_count ;
2011-03-04 19:57:36 +01:00
int64_t filesize = avio_size ( bc ) ;
2006-11-12 13:07:42 +01:00
int64_t * syncpoints ;
int8_t * has_keyframe ;
2008-05-27 22:48:27 +02:00
int ret = - 1 ;
2006-11-12 13:07:42 +01:00
2011-02-28 14:57:54 +01:00
avio_seek ( bc , filesize - 12 , SEEK_SET ) ;
avio_seek ( bc , filesize - avio_rb64 ( bc ) , SEEK_SET ) ;
2011-02-21 16:43:01 +01:00
if ( avio_rb64 ( bc ) ! = INDEX_STARTCODE ) {
2006-11-12 13:07:42 +01:00
av_log ( s , AV_LOG_ERROR , " no index at the end \n " ) ;
return - 1 ;
}
2007-08-09 23:35:13 +02:00
end = get_packetheader ( nut , bc , 1 , INDEX_STARTCODE ) ;
2011-03-03 20:11:45 +01:00
end + = avio_tell ( bc ) ;
2006-11-12 13:07:42 +01:00
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ; //max_pts
2006-11-12 13:07:42 +01:00
GET_V ( syncpoint_count , tmp < INT_MAX / 8 & & tmp > 0 )
syncpoints = av_malloc ( sizeof ( int64_t ) * syncpoint_count ) ;
has_keyframe = av_malloc ( sizeof ( int8_t ) * ( syncpoint_count + 1 ) ) ;
for ( i = 0 ; i < syncpoint_count ; i + + ) {
2011-03-14 20:38:57 +01:00
syncpoints [ i ] = ffio_read_varlen ( bc ) ;
2008-05-27 22:48:27 +02:00
if ( syncpoints [ i ] < = 0 )
goto fail ;
2006-11-12 13:07:42 +01:00
if ( i )
syncpoints [ i ] + = syncpoints [ i - 1 ] ;
}
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
int64_t last_pts = - 1 ;
for ( j = 0 ; j < syncpoint_count ; ) {
2011-03-14 20:38:57 +01:00
uint64_t x = ffio_read_varlen ( bc ) ;
2006-11-12 13:07:42 +01:00
int type = x & 1 ;
int n = j ;
x > > = 1 ;
if ( type ) {
int flag = x & 1 ;
x > > = 1 ;
if ( n + x > = syncpoint_count + 1 ) {
av_log ( s , AV_LOG_ERROR , " index overflow A \n " ) ;
2008-05-27 22:48:27 +02:00
goto fail ;
2006-11-12 13:07:42 +01:00
}
while ( x - - )
has_keyframe [ n + + ] = flag ;
has_keyframe [ n + + ] = ! flag ;
} else {
while ( x ! = 1 ) {
if ( n > = syncpoint_count + 1 ) {
av_log ( s , AV_LOG_ERROR , " index overflow B \n " ) ;
2008-05-27 22:48:27 +02:00
goto fail ;
2006-11-12 13:07:42 +01:00
}
has_keyframe [ n + + ] = x & 1 ;
x > > = 1 ;
}
}
if ( has_keyframe [ 0 ] ) {
av_log ( s , AV_LOG_ERROR , " keyframe before first syncpoint in index \n " ) ;
2008-05-27 22:48:27 +02:00
goto fail ;
2006-11-12 13:07:42 +01:00
}
assert ( n < = syncpoint_count + 1 ) ;
2008-02-04 11:29:03 +01:00
for ( ; j < n & & j < syncpoint_count ; j + + ) {
2006-11-12 13:07:42 +01:00
if ( has_keyframe [ j ] ) {
2011-03-14 20:38:57 +01:00
uint64_t B , A = ffio_read_varlen ( bc ) ;
2006-11-12 13:07:42 +01:00
if ( ! A ) {
2011-03-14 20:38:57 +01:00
A = ffio_read_varlen ( bc ) ;
B = ffio_read_varlen ( bc ) ;
2006-11-12 13:07:42 +01:00
//eor_pts[j][i] = last_pts + A + B
} else
B = 0 ;
av_add_index_entry (
s - > streams [ i ] ,
16 * syncpoints [ j - 1 ] ,
last_pts + A ,
0 ,
0 ,
AVINDEX_KEYFRAME ) ;
last_pts + = A + B ;
}
}
}
}
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) | | ffio_get_checksum ( bc ) ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " index checksum mismatch \n " ) ;
2008-05-27 22:48:27 +02:00
goto fail ;
2006-11-12 13:07:42 +01:00
}
2008-05-27 22:48:27 +02:00
ret = 0 ;
fail :
av_free ( syncpoints ) ;
av_free ( has_keyframe ) ;
return ret ;
2006-11-12 13:07:42 +01:00
}
2006-11-11 02:35:50 +01:00
static int nut_read_header ( AVFormatContext * s , AVFormatParameters * ap )
{
NUTContext * nut = s - > priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-11 02:35:50 +01:00
int64_t pos ;
2008-02-13 10:26:10 +01:00
int initialized_stream_count ;
2006-11-11 02:35:50 +01:00
nut - > avf = s ;
/* main header */
pos = 0 ;
2006-11-11 20:47:58 +01:00
do {
2006-11-11 02:35:50 +01:00
pos = find_startcode ( bc , MAIN_STARTCODE , pos ) + 1 ;
if ( pos < 0 + 1 ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " No main startcode found. \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
2006-11-11 20:47:58 +01:00
} while ( decode_main_header ( nut ) < 0 ) ;
2006-11-11 02:35:50 +01:00
/* stream headers */
pos = 0 ;
2008-02-13 10:26:10 +01:00
for ( initialized_stream_count = 0 ; initialized_stream_count < s - > nb_streams ; ) {
2006-11-11 02:35:50 +01:00
pos = find_startcode ( bc , STREAM_STARTCODE , pos ) + 1 ;
if ( pos < 0 + 1 ) {
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " Not all stream headers found. \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
if ( decode_stream_header ( nut ) > = 0 )
2008-02-13 10:26:10 +01:00
initialized_stream_count + + ;
2006-11-11 02:35:50 +01:00
}
/* info headers */
pos = 0 ;
for ( ; ; ) {
uint64_t startcode = find_any_startcode ( bc , pos ) ;
2011-03-03 20:11:45 +01:00
pos = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( startcode = = 0 ) {
av_log ( s , AV_LOG_ERROR , " EOF before video frames \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
} else if ( startcode = = SYNCPOINT_STARTCODE ) {
nut - > next_startcode = startcode ;
break ;
} else if ( startcode ! = INFO_STARTCODE ) {
continue ;
}
decode_info_header ( nut ) ;
}
2006-11-11 20:37:21 +01:00
s - > data_offset = pos - 8 ;
2011-03-05 21:06:46 +01:00
if ( bc - > seekable ) {
2011-03-03 20:11:45 +01:00
int64_t orig_pos = avio_tell ( bc ) ;
2006-11-12 13:07:42 +01:00
find_and_decode_index ( nut ) ;
2011-02-28 14:57:54 +01:00
avio_seek ( bc , orig_pos , SEEK_SET ) ;
2006-11-12 13:07:42 +01:00
}
assert ( nut - > next_startcode = = SYNCPOINT_STARTCODE ) ;
2010-10-15 21:04:25 +02:00
ff_metadata_conv_ctx ( s , NULL , ff_nut_metadata_conv ) ;
2006-11-11 02:35:50 +01:00
return 0 ;
}
2008-02-15 03:36:09 +01:00
static int decode_frame_header ( NUTContext * nut , int64_t * pts , int * stream_id , uint8_t * header_idx , int frame_code ) {
2006-11-11 02:35:50 +01:00
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-11 02:35:50 +01:00
StreamContext * stc ;
int size , flags , size_mul , pts_delta , i , reserved_count ;
uint64_t tmp ;
2011-03-03 20:11:45 +01:00
if ( avio_tell ( bc ) > nut - > last_syncpoint_pos + nut - > max_distance ) {
av_log ( s , AV_LOG_ERROR , " Last frame must have been damaged % " PRId64 " > % " PRId64 " + %d \n " , avio_tell ( bc ) , nut - > last_syncpoint_pos , nut - > max_distance ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
flags = nut - > frame_code [ frame_code ] . flags ;
size_mul = nut - > frame_code [ frame_code ] . size_mul ;
size = nut - > frame_code [ frame_code ] . size_lsb ;
* stream_id = nut - > frame_code [ frame_code ] . stream_id ;
pts_delta = nut - > frame_code [ frame_code ] . pts_delta ;
reserved_count = nut - > frame_code [ frame_code ] . reserved_count ;
2008-02-15 03:36:09 +01:00
* header_idx = nut - > frame_code [ frame_code ] . header_idx ;
2006-11-11 02:35:50 +01:00
if ( flags & FLAG_INVALID )
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
if ( flags & FLAG_CODED )
2011-03-14 20:38:57 +01:00
flags ^ = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( flags & FLAG_STREAM_ID ) {
GET_V ( * stream_id , tmp < s - > nb_streams )
}
stc = & nut - > stream [ * stream_id ] ;
if ( flags & FLAG_CODED_PTS ) {
2011-03-14 20:38:57 +01:00
int coded_pts = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
//FIXME check last_pts validity?
if ( coded_pts < ( 1 < < stc - > msb_pts_shift ) ) {
2007-08-09 20:37:28 +02:00
* pts = ff_lsb2full ( stc , coded_pts ) ;
2006-11-11 02:35:50 +01:00
} else
* pts = coded_pts - ( 1 < < stc - > msb_pts_shift ) ;
} else
* pts = stc - > last_pts + pts_delta ;
if ( flags & FLAG_SIZE_MSB ) {
2011-03-14 20:38:57 +01:00
size + = size_mul * ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
}
2008-02-13 21:17:28 +01:00
if ( flags & FLAG_MATCH_TIME )
get_s ( bc ) ;
2008-02-15 03:36:09 +01:00
if ( flags & FLAG_HEADER_IDX )
2011-03-14 20:38:57 +01:00
* header_idx = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
if ( flags & FLAG_RESERVED )
2011-03-14 20:38:57 +01:00
reserved_count = ffio_read_varlen ( bc ) ;
2006-11-11 02:35:50 +01:00
for ( i = 0 ; i < reserved_count ; i + + )
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ) ;
2008-02-15 03:36:09 +01:00
if ( * header_idx > = ( unsigned ) nut - > header_count ) {
av_log ( s , AV_LOG_ERROR , " header_idx invalid \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2008-02-15 03:36:09 +01:00
}
if ( size > 4096 )
* header_idx = 0 ;
size - = nut - > header_len [ * header_idx ] ;
2006-11-11 02:35:50 +01:00
if ( flags & FLAG_CHECKSUM ) {
2011-02-21 16:43:01 +01:00
avio_rb32 ( bc ) ; //FIXME check this
2006-11-16 12:03:40 +01:00
} else if ( size > 2 * nut - > max_distance | | FFABS ( stc - > last_pts - * pts ) > stc - > max_pts_distance ) {
2006-11-14 23:24:10 +01:00
av_log ( s , AV_LOG_ERROR , " frame size > 2max_distance and no checksum \n " ) ;
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
}
stc - > last_pts = * pts ;
2006-11-16 12:03:40 +01:00
stc - > last_flags = flags ;
2006-11-11 02:35:50 +01:00
return size ;
}
static int decode_frame ( NUTContext * nut , AVPacket * pkt , int frame_code ) {
AVFormatContext * s = nut - > avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-16 12:03:40 +01:00
int size , stream_id , discard ;
2006-11-11 02:35:50 +01:00
int64_t pts , last_IP_pts ;
2006-11-16 12:03:40 +01:00
StreamContext * stc ;
2008-02-15 03:36:09 +01:00
uint8_t header_idx ;
2006-11-11 02:35:50 +01:00
2008-02-15 03:36:09 +01:00
size = decode_frame_header ( nut , & pts , & stream_id , & header_idx , frame_code ) ;
2006-11-11 02:35:50 +01:00
if ( size < 0 )
2011-01-12 17:40:28 +01:00
return size ;
2006-11-11 02:35:50 +01:00
2006-11-16 12:03:40 +01:00
stc = & nut - > stream [ stream_id ] ;
if ( stc - > last_flags & FLAG_KEY )
stc - > skip_until_key_frame = 0 ;
2006-11-16 11:20:29 +01:00
2006-11-11 02:35:50 +01:00
discard = s - > streams [ stream_id ] - > discard ;
last_IP_pts = s - > streams [ stream_id ] - > last_IP_pts ;
2006-11-16 12:03:40 +01:00
if ( ( discard > = AVDISCARD_NONKEY & & ! ( stc - > last_flags & FLAG_KEY ) )
2006-11-11 02:35:50 +01:00
| | ( discard > = AVDISCARD_BIDIR & & last_IP_pts ! = AV_NOPTS_VALUE & & last_IP_pts > pts )
2006-11-16 11:20:29 +01:00
| | discard > = AVDISCARD_ALL
2006-11-16 12:03:40 +01:00
| | stc - > skip_until_key_frame ) {
2011-03-15 09:14:38 +01:00
avio_skip ( bc , size ) ;
2006-11-11 02:35:50 +01:00
return 1 ;
}
2008-02-15 03:36:09 +01:00
av_new_packet ( pkt , size + nut - > header_len [ header_idx ] ) ;
memcpy ( pkt - > data , nut - > header [ header_idx ] , nut - > header_len [ header_idx ] ) ;
2011-03-03 20:11:45 +01:00
pkt - > pos = avio_tell ( bc ) ; //FIXME
2011-02-21 16:43:01 +01:00
avio_read ( bc , pkt - > data + nut - > header_len [ header_idx ] , size ) ;
2008-02-15 03:36:09 +01:00
2006-11-11 02:35:50 +01:00
pkt - > stream_index = stream_id ;
2006-11-16 12:03:40 +01:00
if ( stc - > last_flags & FLAG_KEY )
2010-03-31 14:29:58 +02:00
pkt - > flags | = AV_PKT_FLAG_KEY ;
2006-11-11 02:35:50 +01:00
pkt - > pts = pts ;
return 0 ;
}
static int nut_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
NUTContext * nut = s - > priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-11 02:35:50 +01:00
int i , frame_code = 0 , ret , skip ;
2006-11-14 14:19:51 +01:00
int64_t ts , back_ptr ;
2006-11-11 02:35:50 +01:00
for ( ; ; ) {
2011-03-03 20:11:45 +01:00
int64_t pos = avio_tell ( bc ) ;
2006-11-11 02:35:50 +01:00
uint64_t tmp = nut - > next_startcode ;
nut - > next_startcode = 0 ;
if ( tmp ) {
pos - = 8 ;
} else {
2011-02-21 16:43:01 +01:00
frame_code = avio_r8 ( bc ) ;
2011-03-07 21:50:25 +01:00
if ( bc - > eof_reached )
2007-03-19 00:59:56 +01:00
return - 1 ;
2006-11-11 02:35:50 +01:00
if ( frame_code = = ' N ' ) {
tmp = frame_code ;
for ( i = 1 ; i < 8 ; i + + )
2011-02-21 16:43:01 +01:00
tmp = ( tmp < < 8 ) + avio_r8 ( bc ) ;
2006-11-11 02:35:50 +01:00
}
}
switch ( tmp ) {
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case INDEX_STARTCODE :
2007-08-09 23:35:13 +02:00
skip = get_packetheader ( nut , bc , 0 , tmp ) ;
2011-03-15 09:14:38 +01:00
avio_skip ( bc , skip ) ;
2006-11-11 02:35:50 +01:00
break ;
case INFO_STARTCODE :
if ( decode_info_header ( nut ) < 0 )
goto resync ;
break ;
case SYNCPOINT_STARTCODE :
2006-11-14 14:19:51 +01:00
if ( decode_syncpoint ( nut , & ts , & back_ptr ) < 0 )
2006-11-11 02:35:50 +01:00
goto resync ;
2011-02-21 16:43:01 +01:00
frame_code = avio_r8 ( bc ) ;
2006-11-11 02:35:50 +01:00
case 0 :
ret = decode_frame ( nut , pkt , frame_code ) ;
if ( ret = = 0 )
return 0 ;
else if ( ret = = 1 ) //ok but discard packet
break ;
default :
resync :
av_log ( s , AV_LOG_DEBUG , " syncing from % " PRId64 " \n " , pos ) ;
2006-11-14 23:23:26 +01:00
tmp = find_any_startcode ( bc , nut - > last_syncpoint_pos + 1 ) ;
2006-11-11 02:35:50 +01:00
if ( tmp = = 0 )
2011-01-12 17:40:28 +01:00
return AVERROR_INVALIDDATA ;
2006-11-11 02:35:50 +01:00
av_log ( s , AV_LOG_DEBUG , " sync \n " ) ;
nut - > next_startcode = tmp ;
}
}
}
2006-11-11 20:37:21 +01:00
static int64_t nut_read_timestamp ( AVFormatContext * s , int stream_index , int64_t * pos_arg , int64_t pos_limit ) {
NUTContext * nut = s - > priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s - > pb ;
2006-11-14 14:19:51 +01:00
int64_t pos , pts , back_ptr ;
2006-11-11 20:37:21 +01:00
av_log ( s , AV_LOG_DEBUG , " read_timestamp(X,%d,% " PRId64 " ,% " PRId64 " ) \n " , stream_index , * pos_arg , pos_limit ) ;
pos = * pos_arg ;
do {
pos = find_startcode ( bc , SYNCPOINT_STARTCODE , pos ) + 1 ;
if ( pos < 1 ) {
assert ( nut - > next_startcode = = 0 ) ;
2007-08-17 12:45:50 +02:00
av_log ( s , AV_LOG_ERROR , " read_timestamp failed. \n " ) ;
2006-11-11 20:37:21 +01:00
return AV_NOPTS_VALUE ;
}
2006-11-14 14:19:51 +01:00
} while ( decode_syncpoint ( nut , & pts , & back_ptr ) < 0 ) ;
2006-11-11 20:37:21 +01:00
* pos_arg = pos - 1 ;
assert ( nut - > last_syncpoint_pos = = * pos_arg ) ;
2007-06-16 16:52:05 +02:00
av_log ( s , AV_LOG_DEBUG , " return % " PRId64 " % " PRId64 " \n " , pts , back_ptr ) ;
2006-11-14 14:19:51 +01:00
if ( stream_index = = - 1 ) return pts ;
else if ( stream_index = = - 2 ) return back_ptr ;
assert ( 0 ) ;
2006-11-11 20:37:21 +01:00
}
2006-11-14 14:19:51 +01:00
static int read_seek ( AVFormatContext * s , int stream_index , int64_t pts , int flags ) {
NUTContext * nut = s - > priv_data ;
AVStream * st = s - > streams [ stream_index ] ;
2008-12-11 20:06:24 +01:00
Syncpoint dummy = { . ts = pts * av_q2d ( st - > time_base ) * AV_TIME_BASE } ;
Syncpoint nopts_sp = { . ts = AV_NOPTS_VALUE , . back_ptr = AV_NOPTS_VALUE } ;
Syncpoint * sp , * next_node [ 2 ] = { & nopts_sp , & nopts_sp } ;
2006-11-14 14:19:51 +01:00
int64_t pos , pos2 , ts ;
2006-11-16 11:20:29 +01:00
int i ;
2006-11-14 14:19:51 +01:00
2006-11-14 14:32:14 +01:00
if ( st - > index_entries ) {
int index = av_index_search_timestamp ( st , pts , flags ) ;
if ( index < 0 )
return - 1 ;
pos2 = st - > index_entries [ index ] . pos ;
ts = st - > index_entries [ index ] . timestamp ;
} else {
2010-03-28 11:59:58 +02:00
av_tree_find ( nut - > syncpoints , & dummy , ( void * ) ff_nut_sp_pts_cmp ,
( void * * ) next_node ) ;
2007-06-16 16:52:05 +02:00
av_log ( s , AV_LOG_DEBUG , " % " PRIu64 " -% " PRIu64 " % " PRId64 " -% " PRId64 " \n " , next_node [ 0 ] - > pos , next_node [ 1 ] - > pos ,
2006-11-14 14:33:05 +01:00
next_node [ 0 ] - > ts , next_node [ 1 ] - > ts ) ;
pos = av_gen_search ( s , - 1 , dummy . ts , next_node [ 0 ] - > pos , next_node [ 1 ] - > pos , next_node [ 1 ] - > pos ,
next_node [ 0 ] - > ts , next_node [ 1 ] - > ts , AVSEEK_FLAG_BACKWARD , & ts , nut_read_timestamp ) ;
if ( ! ( flags & AVSEEK_FLAG_BACKWARD ) ) {
dummy . pos = pos + 16 ;
next_node [ 1 ] = & nopts_sp ;
2010-03-28 11:59:58 +02:00
av_tree_find ( nut - > syncpoints , & dummy , ( void * ) ff_nut_sp_pos_cmp ,
( void * * ) next_node ) ;
2006-11-14 14:33:05 +01:00
pos2 = av_gen_search ( s , - 2 , dummy . pos , next_node [ 0 ] - > pos , next_node [ 1 ] - > pos , next_node [ 1 ] - > pos ,
next_node [ 0 ] - > back_ptr , next_node [ 1 ] - > back_ptr , flags , & ts , nut_read_timestamp ) ;
if ( pos2 > = 0 )
pos = pos2 ;
2008-03-13 00:58:46 +01:00
//FIXME dir but I think it does not matter
2006-11-14 14:33:05 +01:00
}
dummy . pos = pos ;
2010-03-28 11:59:58 +02:00
sp = av_tree_find ( nut - > syncpoints , & dummy , ( void * ) ff_nut_sp_pos_cmp ,
NULL ) ;
2006-11-14 14:33:05 +01:00
assert ( sp ) ;
pos2 = sp - > back_ptr - 15 ;
2006-11-14 14:32:14 +01:00
}
av_log ( NULL , AV_LOG_DEBUG , " SEEKTO: % " PRId64 " \n " , pos2 ) ;
2007-11-21 08:41:00 +01:00
pos = find_startcode ( s - > pb , SYNCPOINT_STARTCODE , pos2 ) ;
2011-02-28 14:57:54 +01:00
avio_seek ( s - > pb , pos , SEEK_SET ) ;
2006-11-14 14:19:51 +01:00
av_log ( NULL , AV_LOG_DEBUG , " SP: % " PRId64 " \n " , pos ) ;
2006-11-14 14:32:14 +01:00
if ( pos2 > pos | | pos2 + 15 < pos ) {
2006-11-14 14:19:51 +01:00
av_log ( NULL , AV_LOG_ERROR , " no syncpoint at backptr pos \n " ) ;
}
2006-11-16 11:20:29 +01:00
for ( i = 0 ; i < s - > nb_streams ; i + + )
nut - > stream [ i ] . skip_until_key_frame = 1 ;
2006-11-14 14:19:51 +01:00
return 0 ;
}
2006-11-11 02:35:50 +01:00
static int nut_read_close ( AVFormatContext * s )
{
NUTContext * nut = s - > priv_data ;
2010-02-28 21:49:21 +01:00
int i ;
2006-11-11 02:35:50 +01:00
av_freep ( & nut - > time_base ) ;
av_freep ( & nut - > stream ) ;
2010-03-03 18:31:24 +01:00
ff_nut_free_sp ( nut ) ;
2010-02-28 21:49:21 +01:00
for ( i = 1 ; i < nut - > header_count ; i + + )
av_freep ( & nut - > header [ i ] ) ;
2006-11-11 02:35:50 +01:00
return 0 ;
}
2009-01-14 00:44:16 +01:00
# if CONFIG_NUT_DEMUXER
2011-01-25 23:03:28 +01:00
AVInputFormat ff_nut_demuxer = {
2006-11-11 02:35:50 +01:00
" nut " ,
2008-06-03 18:20:54 +02:00
NULL_IF_CONFIG_SMALL ( " NUT format " ) ,
2006-11-11 02:35:50 +01:00
sizeof ( NUTContext ) ,
nut_probe ,
nut_read_header ,
nut_read_packet ,
nut_read_close ,
2006-11-14 14:19:51 +01:00
read_seek ,
2006-11-11 02:35:50 +01:00
. extensions = " nut " ,
2010-05-23 20:34:15 +02:00
. codec_tag = ( const AVCodecTag * const [ ] ) { ff_codec_bmp_tags , ff_nut_video_tags , ff_codec_wav_tags , ff_nut_subtitle_tags , 0 } ,
2006-11-11 02:35:50 +01:00
} ;
# endif