2006-11-11 01:35:50 +00:00
/*
* "NUT" Container Format demuxer
* Copyright (c) 2004-2006 Michael Niedermayer
* Copyright (c) 2003 Alex Beregszaszi
*
* This file is part of FFmpeg.
*
* FFmpeg 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.1 of the License, or (at your option) any later version.
*
* FFmpeg 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 Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2008-05-09 11:56:36 +00:00
#include "libavutil/avstring.h"
2009-01-11 22:19:48 +00:00
#include "libavutil/bswap.h"
2011-05-22 12:46:29 +02:00
#include "libavutil/dict.h"
2011-06-04 12:58:23 +01:00
#include "libavutil/mathematics.h"
2008-05-09 11:56:36 +00:00
#include "libavutil/tree.h"
2011-03-14 20:38:57 +01:00
#include "avio_internal.h"
2006-11-11 01:35:50 +00:00
#include "nut.h"
#undef NDEBUG
#include <assert.h>
2010-08-10 16:36:36 +00:00
#define NUT_MAX_STREAMS 256 /* arbitrary sanity check value */
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 01:35:50 +00:00
if ( len && maxlen )
2011-02-21 16:43:01 +01:00
avio_read ( bc , string , FFMIN ( len , maxlen ));
2006-11-11 01:35:50 +00:00
while ( len > maxlen ){
2011-02-21 16:43:01 +01:00
avio_r8 ( bc );
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
2007-08-09 21:04:10 +00: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 01:35:50 +00: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 01:35:50 +00:00
int64_t v = get_s ( bc );
2007-08-09 21:04:10 +00: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 01:35:50 +00: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 01:35:50 +00:00
uint64_t v = get_vb ( bc );
2007-08-09 21:04:10 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
{
2007-04-24 05:50:30 +00:00
int64_t size ;
2011-03-03 20:11:45 +01:00
// start= avio_tell(bc) - 8;
2006-11-11 01:35:50 +00:00
2010-07-10 22:12:30 +00:00
startcode = av_be2ne64 ( startcode );
2010-07-03 10:25:32 +00:00
startcode = ff_crc04C11DB7_update ( 0 , ( uint8_t * ) & startcode , 8 );
2007-08-09 21:35:13 +00: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 03:28:31 +00: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 12:51:08 +00:00
return - 1 ;
2006-11-11 01:35:50 +00:00
2011-03-17 12:56:25 +01:00
ffio_init_checksum ( bc , calculate_checksum ? ff_crc04C11DB7_update : NULL , 0 );
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
while ( ! url_feof ( bc )){
2011-02-21 16:43:01 +01:00
state = ( state << 8 ) | avio_r8 ( bc );
2006-11-11 01:35:50 +00: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 10:45:50 +00:00
* Find the given startcode.
2006-11-11 01:35:50 +00:00
* @param code the startcode
* @param pos the start position of the search, or -1 if the current position
2010-03-30 15:50:57 +00:00
* @return the position of the startcode or -1 if not found
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
if ( pos < 0 ){
2011-02-28 14:57:54 +01:00
avio_seek ( bc , pos , SEEK_CUR );
2006-11-11 01:35:50 +00:00
return - 1 ;
} else {
while ( pos -- )
2011-02-21 16:43:01 +01:00
avio_r8 ( bc );
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
uint64_t tmp , end ;
unsigned int stream_count ;
2008-02-15 02:36:09 +00:00
int i , j , tmp_stream , tmp_mul , tmp_pts , tmp_size , count , tmp_res , tmp_head_idx ;
2006-11-11 01:35:50 +00:00
2007-08-09 21:35:13 +00:00
end = get_packetheader ( nut , bc , 1 , MAIN_STARTCODE );
2011-03-03 20:11:45 +01:00
end += avio_tell ( bc );
2006-11-11 01:35:50 +00:00
GET_V ( tmp , tmp >= 2 && tmp <= 3 )
2010-08-10 16:36:36 +00:00
GET_V ( stream_count , tmp > 0 && tmp <= NUT_MAX_STREAMS )
2006-11-11 01:35:50 +00:00
2011-03-14 20:38:57 +01:00
nut -> max_distance = ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00: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 11:13:33 +00:00
if ( av_gcd ( nut -> time_base [ i ]. num , nut -> time_base [ i ]. den ) != 1 ){
2006-11-11 01:35:50 +00:00
av_log ( s , AV_LOG_ERROR , "time base invalid \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
}
tmp_pts = 0 ;
tmp_mul = 1 ;
tmp_stream = 0 ;
2008-02-15 02:36:09 +00:00
tmp_head_idx = 0 ;
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
else count = tmp_mul - tmp_size ;
2011-06-01 17:29:22 +01:00
if ( tmp_fields > 6 ) 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 01:35:50 +00:00
2008-02-15 02:36:09 +00:00
while ( tmp_fields -- > 8 )
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00:00
if ( count == 0 || i + count > 256 ){
av_log ( s , AV_LOG_ERROR , "illegal count %d at %d \n " , count , i );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
if ( tmp_stream >= stream_count ){
av_log ( s , AV_LOG_ERROR , "illegal stream number \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00: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 02:36:09 +00:00
nut -> frame_code [ i ]. header_idx = tmp_head_idx ;
2006-11-11 01:35:50 +00: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 02:36:09 +00: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 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2008-02-15 02:36:09 +00: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 02:36:09 +00: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 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "main header checksum mismatch \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
nut -> stream = av_mallocz ( sizeof ( StreamContext ) * stream_count );
for ( i = 0 ; i < stream_count ; i ++ ){
2011-06-18 11:43:24 +02:00
avformat_new_stream ( s , NULL );
2006-11-11 01:35:50 +00:00
}
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 01:35:50 +00:00
StreamContext * stc ;
2006-11-16 09:59:46 +00:00
int class , stream_id ;
2006-11-11 01:35:50 +00:00
uint64_t tmp , end ;
AVStream * st ;
2007-08-09 21:35:13 +00:00
end = get_packetheader ( nut , bc , 1 , STREAM_STARTCODE );
2011-03-03 20:11:45 +01:00
end += avio_tell ( bc );
2006-11-11 01:35:50 +00:00
2007-08-09 11:04:43 +00:00
GET_V ( stream_id , tmp < s -> nb_streams && ! nut -> stream [ tmp ]. time_base );
2006-11-11 01:35:50 +00:00
stc = & nut -> stream [ stream_id ];
st = s -> streams [ stream_id ];
if ( ! st )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2006-11-11 01:35:50 +00:00
2011-03-14 20:38:57 +01:00
class = ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00:00
tmp = get_fourcc ( bc );
st -> codec -> codec_tag = tmp ;
switch ( class )
{
case 0 :
2010-03-30 23:30:55 +00:00
st -> codec -> codec_type = AVMEDIA_TYPE_VIDEO ;
2010-05-23 18:34:18 +00: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 01:35:50 +00:00
break ;
case 1 :
2010-03-30 23:30:55 +00:00
st -> codec -> codec_type = AVMEDIA_TYPE_AUDIO ;
2009-06-22 23:09:34 +00:00
st -> codec -> codec_id = ff_codec_get_id ( ff_codec_wav_tags , tmp );
2006-11-11 01:35:50 +00:00
break ;
case 2 :
2010-03-30 23:30:55 +00:00
st -> codec -> codec_type = AVMEDIA_TYPE_SUBTITLE ;
2009-06-22 23:09:34 +00:00
st -> codec -> codec_id = ff_codec_get_id ( ff_nut_subtitle_tags , tmp );
2008-03-02 23:11:36 +00:00
break ;
2006-11-11 01:35:50 +00:00
case 3 :
2010-03-30 23:30:55 +00:00
st -> codec -> codec_type = AVMEDIA_TYPE_DATA ;
2006-11-11 01:35:50 +00:00
break ;
default :
2007-08-17 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "unknown stream class (%d) \n " , class );
2006-11-11 01:35:50 +00:00
return - 1 ;
}
2008-03-02 23:13:07 +00:00
if ( class < 3 && st -> codec -> codec_id == CODEC_ID_NONE )
2010-05-09 22:56:02 +00:00
av_log ( s , AV_LOG_ERROR , "Unknown codec tag '0x%04x' for stream number %d \n " ,
( unsigned int ) tmp , stream_id );
2008-03-02 23:13:07 +00:00
2006-11-11 01:35:50 +00: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 10:45:50 +00:00
GET_V ( stc -> decode_delay , tmp < 1000 ); //sanity limit, raise this if Moore's law is true
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 01:35:50 +00:00
}
2010-03-30 23:30:55 +00:00
if ( st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO ){
2006-11-11 01:35:50 +00: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-23 23:43:20 +00: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 01:35:50 +00:00
return - 1 ;
}
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ); /* csp type */
2010-03-30 23:30:55 +00:00
} else if ( st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO ){
2006-11-11 01:35:50 +00: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 01:35:50 +00: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 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "stream header %d checksum mismatch \n " , stream_id );
2006-11-11 01:35:50 +00:00
return - 1 ;
}
2007-08-09 11:04:43 +00:00
stc -> time_base = & nut -> time_base [ stc -> time_base_id ];
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( s -> streams [ stream_id ], 63 , stc -> time_base -> num , stc -> time_base -> den );
2006-11-11 01:35:50 +00:00
return 0 ;
}
2008-03-07 19:25:09 +00: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 01:35:50 +00: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 07:26:41 +00:00
uint64_t tmp , chapter_start , chapter_len ;
unsigned int stream_id_plus1 , count ;
2006-11-11 01:35:50 +00:00
int chapter_id , i ;
int64_t value , end ;
2008-02-04 00:31:31 +00:00
char name [ 256 ], str_value [ 1024 ], type_str [ 256 ];
2008-02-04 00:33:52 +00:00
const char * type ;
2008-05-23 13:52:54 +00:00
AVChapter * chapter = NULL ;
2009-02-27 23:10:34 +00:00
AVStream * st = NULL ;
2011-05-22 12:46:29 +02:00
AVDictionary ** metadata = NULL ;
2006-11-11 01:35:50 +00:00
2007-08-09 21:35:13 +00:00
end = get_packetheader ( nut , bc , 1 , INFO_STARTCODE );
2011-03-03 20:11:45 +01:00
end += avio_tell ( bc );
2006-11-11 01:35:50 +00: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 13:52:54 +00:00
if ( chapter_id && ! stream_id_plus1 ){
int64_t start = chapter_start / nut -> time_base_count ;
2011-10-17 08:58:50 +02:00
chapter = avpriv_new_chapter ( s , chapter_id ,
2008-05-23 18:15:13 +00:00
nut -> time_base [ chapter_start % nut -> time_base_count ],
start , start + chapter_len , NULL );
2010-10-24 07:28:04 +00:00
metadata = & chapter -> metadata ;
} else if ( stream_id_plus1 ) {
2009-02-27 23:10:34 +00:00
st = s -> streams [ stream_id_plus1 - 1 ];
2010-10-24 07:28:04 +00:00
metadata = & st -> metadata ;
} else
metadata = & s -> metadata ;
2008-05-23 13:52:54 +00:00
2006-11-11 01:35:50 +00: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 00:33:52 +00:00
get_str ( bc , type_str , sizeof ( type_str ));
type = type_str ;
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
} else if ( value < - 4 ){
type = "r" ;
get_s ( bc );
} else {
type = "v" ;
}
2008-05-04 10:29:12 +00:00
if ( stream_id_plus1 > s -> nb_streams ) {
2008-03-07 19:25:09 +00:00
av_log ( s , AV_LOG_ERROR , "invalid stream id for info packet \n " );
continue ;
}
2009-02-27 23:10:34 +00:00
if ( ! strcmp ( type , "UTF-8" )){
2010-10-24 07:28:04 +00:00
if ( chapter_id == 0 && ! strcmp ( name , "Disposition" )) {
2008-03-07 19:25:09 +00:00
set_disposition_bits ( s , str_value , stream_id_plus1 - 1 );
2010-10-24 07:28:04 +00:00
continue ;
}
2011-11-02 20:17:25 +01:00
if ( metadata && av_strcasecmp ( name , "Uses" )
&& av_strcasecmp ( name , "Depends" ) && av_strcasecmp ( name , "Replaces" ))
2011-05-22 12:46:29 +02:00
av_dict_set ( metadata , name , str_value , 0 );
2008-05-23 13:52:54 +00:00
}
2006-11-11 01:35:50 +00:00
}
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) || ffio_get_checksum ( bc )){
2007-08-17 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "info header checksum mismatch \n " );
2006-11-11 01:35:50 +00:00
return - 1 ;
}
return 0 ;
}
2006-11-14 13:19:51 +00:00
static int decode_syncpoint ( NUTContext * nut , int64_t * ts , int64_t * back_ptr ){
2006-11-11 01:35:50 +00:00
AVFormatContext * s = nut -> avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s -> pb ;
2006-11-14 13:19:51 +00:00
int64_t end , tmp ;
2006-11-11 01:35:50 +00:00
2011-03-03 20:11:45 +01:00
nut -> last_syncpoint_pos = avio_tell ( bc ) - 8 ;
2006-11-11 01:35:50 +00:00
2007-08-09 21:35:13 +00:00
end = get_packetheader ( nut , bc , 1 , SYNCPOINT_STARTCODE );
2011-03-03 20:11:45 +01:00
end += avio_tell ( bc );
2006-11-11 01:35:50 +00: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 13:19:51 +00:00
if ( * back_ptr < 0 )
return - 1 ;
2006-11-11 01:35:50 +00:00
2008-02-04 10:27:32 +00:00
ff_nut_reset_ts ( nut , nut -> time_base [ tmp % nut -> time_base_count ], tmp / nut -> time_base_count );
2006-11-11 01:35:50 +00:00
2011-03-17 13:04:38 +01:00
if ( skip_reserved ( bc , end ) || ffio_get_checksum ( bc )){
2006-11-11 19:37:21 +00:00
av_log ( s , AV_LOG_ERROR , "sync point checksum mismatch \n " );
2006-11-11 01:35:50 +00:00
return - 1 ;
}
2006-11-14 13:19:51 +00:00
* ts = tmp / s -> nb_streams * av_q2d ( nut -> time_base [ tmp % s -> nb_streams ]) * AV_TIME_BASE ;
2007-08-09 23:24:02 +00:00
ff_nut_add_sp ( nut , nut -> last_syncpoint_pos , * back_ptr , * ts );
2006-11-14 13:19:51 +00:00
2006-11-11 01:35:50 +00:00
return 0 ;
}
2006-11-12 12:07:42 +00: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 12:07:42 +00: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 12:07:42 +00:00
int64_t * syncpoints ;
int8_t * has_keyframe ;
2008-05-27 20:48:27 +00:00
int ret = - 1 ;
2006-11-12 12:07:42 +00: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 12:07:42 +00:00
av_log ( s , AV_LOG_ERROR , "no index at the end \n " );
return - 1 ;
}
2007-08-09 21:35:13 +00:00
end = get_packetheader ( nut , bc , 1 , INDEX_STARTCODE );
2011-03-03 20:11:45 +01:00
end += avio_tell ( bc );
2006-11-12 12:07:42 +00:00
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc ); //max_pts
2006-11-12 12:07:42 +00: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 20:48:27 +00:00
if ( syncpoints [ i ] <= 0 )
goto fail ;
2006-11-12 12:07:42 +00: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 12:07:42 +00: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 20:48:27 +00:00
goto fail ;
2006-11-12 12:07:42 +00: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 20:48:27 +00:00
goto fail ;
2006-11-12 12:07:42 +00: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 20:48:27 +00:00
goto fail ;
2006-11-12 12:07:42 +00:00
}
assert ( n <= syncpoint_count + 1 );
2008-02-04 10:29:03 +00:00
for (; j < n && j < syncpoint_count ; j ++ ){
2006-11-12 12:07:42 +00:00
if ( has_keyframe [ j ]){
2011-03-14 20:38:57 +01:00
uint64_t B , A = ffio_read_varlen ( bc );
2006-11-12 12:07:42 +00:00
if ( ! A ){
2011-03-14 20:38:57 +01:00
A = ffio_read_varlen ( bc );
B = ffio_read_varlen ( bc );
2006-11-12 12:07:42 +00: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 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "index checksum mismatch \n " );
2008-05-27 20:48:27 +00:00
goto fail ;
2006-11-12 12:07:42 +00:00
}
2008-05-27 20:48:27 +00:00
ret = 0 ;
fail :
av_free ( syncpoints );
av_free ( has_keyframe );
return ret ;
2006-11-12 12:07:42 +00:00
}
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
int64_t pos ;
2008-02-13 09:26:10 +00:00
int initialized_stream_count ;
2006-11-11 01:35:50 +00:00
nut -> avf = s ;
/* main header */
pos = 0 ;
2006-11-11 19:47:58 +00:00
do {
2006-11-11 01:35:50 +00:00
pos = find_startcode ( bc , MAIN_STARTCODE , pos ) + 1 ;
if ( pos < 0 + 1 ){
2007-08-17 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "No main startcode found. \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
2006-11-11 19:47:58 +00:00
} while ( decode_main_header ( nut ) < 0 );
2006-11-11 01:35:50 +00:00
/* stream headers */
pos = 0 ;
2008-02-13 09:26:10 +00:00
for ( initialized_stream_count = 0 ; initialized_stream_count < s -> nb_streams ;){
2006-11-11 01:35:50 +00:00
pos = find_startcode ( bc , STREAM_STARTCODE , pos ) + 1 ;
if ( pos < 0 + 1 ){
2007-08-17 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "Not all stream headers found. \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
if ( decode_stream_header ( nut ) >= 0 )
2008-02-13 09:26:10 +00:00
initialized_stream_count ++ ;
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
if ( startcode == 0 ){
av_log ( s , AV_LOG_ERROR , "EOF before video frames \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
} else if ( startcode == SYNCPOINT_STARTCODE ){
nut -> next_startcode = startcode ;
break ;
} else if ( startcode != INFO_STARTCODE ){
continue ;
}
decode_info_header ( nut );
}
2006-11-11 19:37:21 +00: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 12:07:42 +00:00
find_and_decode_index ( nut );
2011-02-28 14:57:54 +01:00
avio_seek ( bc , orig_pos , SEEK_SET );
2006-11-12 12:07:42 +00:00
}
assert ( nut -> next_startcode == SYNCPOINT_STARTCODE );
2010-10-15 19:04:25 +00:00
ff_metadata_conv_ctx ( s , NULL , ff_nut_metadata_conv );
2006-11-11 01:35:50 +00:00
return 0 ;
}
2008-02-15 02:36:09 +00:00
static int decode_frame_header ( NUTContext * nut , int64_t * pts , int * stream_id , uint8_t * header_idx , int frame_code ){
2006-11-11 01:35:50 +00:00
AVFormatContext * s = nut -> avf ;
2011-02-20 11:04:12 +01:00
AVIOContext * bc = s -> pb ;
2006-11-11 01:35:50 +00: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 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00: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 02:36:09 +00:00
* header_idx = nut -> frame_code [ frame_code ]. header_idx ;
2006-11-11 01:35:50 +00:00
if ( flags & FLAG_INVALID )
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
if ( flags & FLAG_CODED )
2011-03-14 20:38:57 +01:00
flags ^= ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
//FIXME check last_pts validity?
if ( coded_pts < ( 1 << stc -> msb_pts_shift )){
2007-08-09 18:37:28 +00:00
* pts = ff_lsb2full ( stc , coded_pts );
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
}
2008-02-13 20:17:28 +00:00
if ( flags & FLAG_MATCH_TIME )
get_s ( bc );
2008-02-15 02:36:09 +00:00
if ( flags & FLAG_HEADER_IDX )
2011-03-14 20:38:57 +01:00
* header_idx = ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00:00
if ( flags & FLAG_RESERVED )
2011-03-14 20:38:57 +01:00
reserved_count = ffio_read_varlen ( bc );
2006-11-11 01:35:50 +00:00
for ( i = 0 ; i < reserved_count ; i ++ )
2011-03-14 20:38:57 +01:00
ffio_read_varlen ( bc );
2008-02-15 02:36:09 +00:00
if ( * header_idx >= ( unsigned ) nut -> header_count ){
av_log ( s , AV_LOG_ERROR , "header_idx invalid \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2008-02-15 02:36:09 +00:00
}
if ( size > 4096 )
* header_idx = 0 ;
size -= nut -> header_len [ * header_idx ];
2006-11-11 01:35:50 +00:00
if ( flags & FLAG_CHECKSUM ){
2011-02-21 16:43:01 +01:00
avio_rb32 ( bc ); //FIXME check this
2006-11-16 11:03:40 +00:00
} else if ( size > 2 * nut -> max_distance || FFABS ( stc -> last_pts - * pts ) > stc -> max_pts_distance ){
2006-11-14 22:24:10 +00:00
av_log ( s , AV_LOG_ERROR , "frame size > 2max_distance and no checksum \n " );
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
}
stc -> last_pts = * pts ;
2006-11-16 11:03:40 +00:00
stc -> last_flags = flags ;
2006-11-11 01:35:50 +00: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 11:03:40 +00:00
int size , stream_id , discard ;
2006-11-11 01:35:50 +00:00
int64_t pts , last_IP_pts ;
2006-11-16 11:03:40 +00:00
StreamContext * stc ;
2008-02-15 02:36:09 +00:00
uint8_t header_idx ;
2006-11-11 01:35:50 +00:00
2008-02-15 02:36:09 +00:00
size = decode_frame_header ( nut , & pts , & stream_id , & header_idx , frame_code );
2006-11-11 01:35:50 +00:00
if ( size < 0 )
2011-01-12 16:40:28 +00:00
return size ;
2006-11-11 01:35:50 +00:00
2006-11-16 11:03:40 +00:00
stc = & nut -> stream [ stream_id ];
if ( stc -> last_flags & FLAG_KEY )
stc -> skip_until_key_frame = 0 ;
2006-11-16 10:20:29 +00:00
2006-11-11 01:35:50 +00:00
discard = s -> streams [ stream_id ] -> discard ;
last_IP_pts = s -> streams [ stream_id ] -> last_IP_pts ;
2006-11-16 11:03:40 +00:00
if ( ( discard >= AVDISCARD_NONKEY && ! ( stc -> last_flags & FLAG_KEY ))
2006-11-11 01:35:50 +00:00
|| ( discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts )
2006-11-16 10:20:29 +00:00
|| discard >= AVDISCARD_ALL
2006-11-16 11:03:40 +00:00
|| stc -> skip_until_key_frame ){
2011-03-15 09:14:38 +01:00
avio_skip ( bc , size );
2006-11-11 01:35:50 +00:00
return 1 ;
}
2008-02-15 02:36:09 +00: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 02:36:09 +00:00
2006-11-11 01:35:50 +00:00
pkt -> stream_index = stream_id ;
2006-11-16 11:03:40 +00:00
if ( stc -> last_flags & FLAG_KEY )
2010-03-31 12:29:58 +00:00
pkt -> flags |= AV_PKT_FLAG_KEY ;
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
int i , frame_code = 0 , ret , skip ;
2006-11-14 13:19:51 +00:00
int64_t ts , back_ptr ;
2006-11-11 01:35:50 +00:00
for (;;){
2011-03-03 20:11:45 +01:00
int64_t pos = avio_tell ( bc );
2006-11-11 01:35:50 +00: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 );
2007-03-18 23:59:56 +00:00
if ( url_feof ( bc ))
return - 1 ;
2006-11-11 01:35:50 +00: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 01:35:50 +00:00
}
}
switch ( tmp ){
case MAIN_STARTCODE :
case STREAM_STARTCODE :
case INDEX_STARTCODE :
2007-08-09 21:35:13 +00:00
skip = get_packetheader ( nut , bc , 0 , tmp );
2011-03-15 09:14:38 +01:00
avio_skip ( bc , skip );
2006-11-11 01:35:50 +00:00
break ;
case INFO_STARTCODE :
if ( decode_info_header ( nut ) < 0 )
goto resync ;
break ;
case SYNCPOINT_STARTCODE :
2006-11-14 13:19:51 +00:00
if ( decode_syncpoint ( nut , & ts , & back_ptr ) < 0 )
2006-11-11 01:35:50 +00:00
goto resync ;
2011-02-21 16:43:01 +01:00
frame_code = avio_r8 ( bc );
2006-11-11 01:35:50 +00: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 22:23:26 +00:00
tmp = find_any_startcode ( bc , nut -> last_syncpoint_pos + 1 );
2006-11-11 01:35:50 +00:00
if ( tmp == 0 )
2011-01-12 16:40:28 +00:00
return AVERROR_INVALIDDATA ;
2006-11-11 01:35:50 +00:00
av_log ( s , AV_LOG_DEBUG , "sync \n " );
nut -> next_startcode = tmp ;
}
}
}
2006-11-11 19:37:21 +00: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 13:19:51 +00:00
int64_t pos , pts , back_ptr ;
2006-11-11 19:37:21 +00: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 10:45:50 +00:00
av_log ( s , AV_LOG_ERROR , "read_timestamp failed. \n " );
2006-11-11 19:37:21 +00:00
return AV_NOPTS_VALUE ;
}
2006-11-14 13:19:51 +00:00
} while ( decode_syncpoint ( nut , & pts , & back_ptr ) < 0 );
2006-11-11 19:37:21 +00:00
* pos_arg = pos - 1 ;
assert ( nut -> last_syncpoint_pos == * pos_arg );
2007-06-16 14:52:05 +00:00
av_log ( s , AV_LOG_DEBUG , "return %" PRId64 " %" PRId64 " \n " , pts , back_ptr );
2006-11-14 13:19:51 +00:00
if ( stream_index == - 1 ) return pts ;
else if ( stream_index == - 2 ) return back_ptr ;
assert ( 0 );
2006-11-11 19:37:21 +00:00
}
2006-11-14 13:19:51 +00: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 19:06:24 +00: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 13:19:51 +00:00
int64_t pos , pos2 , ts ;
2006-11-16 10:20:29 +00:00
int i ;
2006-11-14 13:19:51 +00:00
2006-11-14 13:32:14 +00: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 09:59:58 +00:00
av_tree_find ( nut -> syncpoints , & dummy , ( void * ) ff_nut_sp_pts_cmp ,
( void ** ) next_node );
2007-06-16 14:52:05 +00:00
av_log ( s , AV_LOG_DEBUG , "%" PRIu64 "-%" PRIu64 " %" PRId64 "-%" PRId64 " \n " , next_node [ 0 ] -> pos , next_node [ 1 ] -> pos ,
2006-11-14 13:33:05 +00:00
next_node [ 0 ] -> ts , next_node [ 1 ] -> ts );
2011-10-16 15:03:30 +02:00
pos = ff_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 );
2006-11-14 13:19:51 +00:00
2006-11-14 13:33:05 +00:00
if ( ! ( flags & AVSEEK_FLAG_BACKWARD )){
dummy . pos = pos + 16 ;
next_node [ 1 ] = & nopts_sp ;
2010-03-28 09:59:58 +00:00
av_tree_find ( nut -> syncpoints , & dummy , ( void * ) ff_nut_sp_pos_cmp ,
( void ** ) next_node );
2011-10-16 15:03:30 +02:00
pos2 = ff_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 );
2006-11-14 13:33:05 +00:00
if ( pos2 >= 0 )
pos = pos2 ;
2008-03-12 23:58:46 +00:00
//FIXME dir but I think it does not matter
2006-11-14 13:33:05 +00:00
}
dummy . pos = pos ;
2010-03-28 09:59:58 +00:00
sp = av_tree_find ( nut -> syncpoints , & dummy , ( void * ) ff_nut_sp_pos_cmp ,
NULL );
2006-11-14 13:19:51 +00:00
2006-11-14 13:33:05 +00:00
assert ( sp );
pos2 = sp -> back_ptr - 15 ;
2006-11-14 13:32:14 +00:00
}
av_log ( NULL , AV_LOG_DEBUG , "SEEKTO: %" PRId64 " \n " , pos2 );
2007-11-21 07:41:00 +00: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 13:19:51 +00:00
av_log ( NULL , AV_LOG_DEBUG , "SP: %" PRId64 " \n " , pos );
2006-11-14 13:32:14 +00:00
if ( pos2 > pos || pos2 + 15 < pos ){
2006-11-14 13:19:51 +00:00
av_log ( NULL , AV_LOG_ERROR , "no syncpoint at backptr pos \n " );
}
2006-11-16 10:20:29 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ )
nut -> stream [ i ]. skip_until_key_frame = 1 ;
2006-11-14 13:19:51 +00:00
return 0 ;
}
2006-11-11 01:35:50 +00:00
static int nut_read_close ( AVFormatContext * s )
{
NUTContext * nut = s -> priv_data ;
2010-02-28 20:49:21 +00:00
int i ;
2006-11-11 01:35:50 +00:00
av_freep ( & nut -> time_base );
av_freep ( & nut -> stream );
2010-03-03 17:31:24 +00:00
ff_nut_free_sp ( nut );
2010-02-28 20:49:21 +00:00
for ( i = 1 ; i < nut -> header_count ; i ++ )
av_freep ( & nut -> header [ i ]);
2006-11-11 01:35:50 +00:00
return 0 ;
}
2009-01-13 23:44:16 +00:00
#if CONFIG_NUT_DEMUXER
2011-01-25 22:03:28 +00:00
AVInputFormat ff_nut_demuxer = {
2011-07-16 22:18:12 +02:00
. name = "nut" ,
. long_name = NULL_IF_CONFIG_SMALL ( "NUT format" ),
. priv_data_size = sizeof ( NUTContext ),
. read_probe = nut_probe ,
. read_header = nut_read_header ,
. read_packet = nut_read_packet ,
. read_close = nut_read_close ,
. read_seek = read_seek ,
2006-11-11 01:35:50 +00:00
. extensions = "nut" ,
2010-05-23 18:34:15 +00: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 01:35:50 +00:00
};
#endif