2001-07-22 17:18:56 +03:00
/*
2008-01-17 00:14:26 +02:00
* various utility functions for use within FFmpeg
2002-05-26 01:34:32 +03:00
* Copyright ( c ) 2000 , 2001 , 2002 Fabrice Bellard
2001-07-22 17:18:56 +03:00
*
2006-10-07 18:30:46 +03:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-05-26 01:34:32 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 18:30:46 +03:00
* version 2.1 of the License , or ( at your option ) any later version .
2001-07-22 17:18:56 +03:00
*
2006-10-07 18:30:46 +03:00
* FFmpeg is distributed in the hope that it will be useful ,
2001-07-22 17:18:56 +03:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-26 01:34:32 +03:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2001-07-22 17:18:56 +03:00
*
2002-05-26 01:34:32 +03:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 18:30:46 +03:00
* License along with FFmpeg ; 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
2001-07-22 17:18:56 +03:00
*/
2001-08-14 00:37:10 +03:00
# include "avformat.h"
2006-08-27 15:14:13 +03:00
# include "opt.h"
2007-06-24 02:10:32 +03:00
# include "avstring.h"
2007-07-11 15:45:14 +03:00
# include "riff.h"
2007-07-16 23:28:43 +03:00
# include <sys/time.h>
# include <time.h>
2002-07-27 05:54:10 +03:00
2004-01-14 00:02:49 +02:00
# undef NDEBUG
# include <assert.h>
2005-06-28 15:55:08 +03:00
/**
* @ file libavformat / utils . c
2008-01-17 00:14:26 +02:00
* various utility functions for use within FFmpeg
2005-06-28 15:55:08 +03:00
*/
2006-06-25 20:37:12 +03:00
static void av_frac_init ( AVFrac * f , int64_t val , int64_t num , int64_t den ) ;
static void av_frac_add ( AVFrac * f , int64_t incr ) ;
2008-01-17 00:14:26 +02:00
/** head of registered input format linked list */
2004-08-13 18:30:42 +03:00
AVInputFormat * first_iformat = NULL ;
2008-01-17 00:14:26 +02:00
/** head of registered output format linked list */
2004-08-13 18:30:42 +03:00
AVOutputFormat * first_oformat = NULL ;
2001-07-22 17:18:56 +03:00
2007-12-12 21:01:58 +02:00
AVInputFormat * av_iformat_next ( AVInputFormat * f )
{
if ( f ) return f - > next ;
else return first_iformat ;
}
AVOutputFormat * av_oformat_next ( AVOutputFormat * f )
{
if ( f ) return f - > next ;
else return first_oformat ;
}
2002-05-20 19:28:47 +03:00
void av_register_input_format ( AVInputFormat * format )
2001-07-22 17:18:56 +03:00
{
2002-05-20 19:28:47 +03:00
AVInputFormat * * p ;
p = & first_iformat ;
while ( * p ! = NULL ) p = & ( * p ) - > next ;
* p = format ;
format - > next = NULL ;
}
void av_register_output_format ( AVOutputFormat * format )
{
AVOutputFormat * * p ;
p = & first_oformat ;
2001-07-22 17:18:56 +03:00
while ( * p ! = NULL ) p = & ( * p ) - > next ;
* p = format ;
format - > next = NULL ;
}
2002-11-18 19:17:27 +02:00
int match_ext ( const char * filename , const char * extensions )
2001-07-22 17:18:56 +03:00
{
const char * ext , * p ;
char ext1 [ 32 ] , * q ;
2004-04-27 05:55:05 +03:00
if ( ! filename )
return 0 ;
2005-12-17 20:14:38 +02:00
2001-07-22 17:18:56 +03:00
ext = strrchr ( filename , ' . ' ) ;
if ( ext ) {
ext + + ;
p = extensions ;
for ( ; ; ) {
q = ext1 ;
2005-12-17 20:14:38 +02:00
while ( * p ! = ' \0 ' & & * p ! = ' , ' & & q - ext1 < sizeof ( ext1 ) - 1 )
2001-07-22 17:18:56 +03:00
* q + + = * p + + ;
* q = ' \0 ' ;
2005-12-17 20:14:38 +02:00
if ( ! strcasecmp ( ext1 , ext ) )
2001-07-22 17:18:56 +03:00
return 1 ;
2005-12-17 20:14:38 +02:00
if ( * p = = ' \0 ' )
2001-07-22 17:18:56 +03:00
break ;
p + + ;
}
}
return 0 ;
}
2005-12-17 20:14:38 +02:00
AVOutputFormat * guess_format ( const char * short_name , const char * filename ,
2002-05-20 19:28:47 +03:00
const char * mime_type )
2001-07-22 17:18:56 +03:00
{
2002-05-20 19:28:47 +03:00
AVOutputFormat * fmt , * fmt_found ;
2001-07-22 17:18:56 +03:00
int score_max , score ;
2003-01-11 07:02:14 +02:00
/* specific test for image sequences */
2006-07-11 00:14:37 +03:00
# ifdef CONFIG_IMAGE2_MUXER
2005-12-17 20:14:38 +02:00
if ( ! short_name & & filename & &
2006-09-04 12:57:47 +03:00
av_filename_number_test ( filename ) & &
2004-11-11 20:09:28 +02:00
av_guess_image2_codec ( filename ) ! = CODEC_ID_NONE ) {
return guess_format ( " image2 " , NULL , NULL ) ;
}
2006-07-11 00:14:37 +03:00
# endif
2008-01-17 00:14:26 +02:00
/* Find the proper file type. */
2001-07-22 17:18:56 +03:00
fmt_found = NULL ;
score_max = 0 ;
2002-05-20 19:28:47 +03:00
fmt = first_oformat ;
2001-07-22 17:18:56 +03:00
while ( fmt ! = NULL ) {
score = 0 ;
if ( fmt - > name & & short_name & & ! strcmp ( fmt - > name , short_name ) )
score + = 100 ;
if ( fmt - > mime_type & & mime_type & & ! strcmp ( fmt - > mime_type , mime_type ) )
score + = 10 ;
2005-12-17 20:14:38 +02:00
if ( filename & & fmt - > extensions & &
2001-07-22 17:18:56 +03:00
match_ext ( filename , fmt - > extensions ) ) {
score + = 5 ;
}
if ( score > score_max ) {
score_max = score ;
fmt_found = fmt ;
}
fmt = fmt - > next ;
}
return fmt_found ;
2005-12-17 20:14:38 +02:00
}
2001-07-22 17:18:56 +03:00
2005-12-17 20:14:38 +02:00
AVOutputFormat * guess_stream_format ( const char * short_name , const char * filename ,
2002-07-27 05:54:10 +03:00
const char * mime_type )
{
AVOutputFormat * fmt = guess_format ( short_name , filename , mime_type ) ;
if ( fmt ) {
AVOutputFormat * stream_fmt ;
char stream_format_name [ 64 ] ;
snprintf ( stream_format_name , sizeof ( stream_format_name ) , " %s_stream " , fmt - > name ) ;
stream_fmt = guess_format ( stream_format_name , NULL , NULL ) ;
if ( stream_fmt )
fmt = stream_fmt ;
}
return fmt ;
}
2005-12-17 20:14:38 +02:00
enum CodecID av_guess_codec ( AVOutputFormat * fmt , const char * short_name ,
2004-11-11 20:09:28 +02:00
const char * filename , const char * mime_type , enum CodecType type ) {
if ( type = = CODEC_TYPE_VIDEO ) {
enum CodecID codec_id = CODEC_ID_NONE ;
2006-07-11 00:14:37 +03:00
# ifdef CONFIG_IMAGE2_MUXER
2004-11-13 00:51:52 +02:00
if ( ! strcmp ( fmt - > name , " image2 " ) | | ! strcmp ( fmt - > name , " image2pipe " ) ) {
2004-11-11 20:09:28 +02:00
codec_id = av_guess_image2_codec ( filename ) ;
}
2006-07-11 00:14:37 +03:00
# endif
2004-11-11 20:09:28 +02:00
if ( codec_id = = CODEC_ID_NONE )
codec_id = fmt - > video_codec ;
return codec_id ;
} else if ( type = = CODEC_TYPE_AUDIO )
return fmt - > audio_codec ;
else
return CODEC_ID_NONE ;
}
2002-05-20 19:28:47 +03:00
AVInputFormat * av_find_input_format ( const char * short_name )
{
AVInputFormat * fmt ;
for ( fmt = first_iformat ; fmt ! = NULL ; fmt = fmt - > next ) {
if ( ! strcmp ( fmt - > name , short_name ) )
return fmt ;
}
return NULL ;
}
2001-07-22 17:18:56 +03:00
/* memory handling */
2005-06-27 03:04:03 +03:00
void av_destruct_packet ( AVPacket * pkt )
2003-02-04 00:58:29 +02:00
{
av_free ( pkt - > data ) ;
pkt - > data = NULL ; pkt - > size = 0 ;
}
2007-06-04 19:52:02 +03:00
void av_init_packet ( AVPacket * pkt )
{
pkt - > pts = AV_NOPTS_VALUE ;
pkt - > dts = AV_NOPTS_VALUE ;
pkt - > pos = - 1 ;
pkt - > duration = 0 ;
pkt - > flags = 0 ;
pkt - > stream_index = 0 ;
pkt - > destruct = av_destruct_packet_nofree ;
}
2001-07-22 17:18:56 +03:00
int av_new_packet ( AVPacket * pkt , int size )
{
2006-10-31 01:59:52 +02:00
uint8_t * data ;
2005-01-08 16:21:33 +02:00
if ( ( unsigned ) size > ( unsigned ) size + FF_INPUT_BUFFER_PADDING_SIZE )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2005-01-08 16:21:33 +02:00
data = av_malloc ( size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2003-02-04 00:58:29 +02:00
if ( ! data )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2003-02-04 00:58:29 +02:00
memset ( data + size , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2002-11-09 17:53:52 +02:00
2003-02-04 00:58:29 +02:00
av_init_packet ( pkt ) ;
2005-12-17 20:14:38 +02:00
pkt - > data = data ;
2003-02-04 00:58:29 +02:00
pkt - > size = size ;
pkt - > destruct = av_destruct_packet ;
2001-07-22 17:18:56 +03:00
return 0 ;
}
2005-05-26 23:17:12 +03:00
int av_get_packet ( ByteIOContext * s , AVPacket * pkt , int size )
{
int ret = av_new_packet ( pkt , size ) ;
if ( ret < 0 )
return ret ;
pkt - > pos = url_ftell ( s ) ;
ret = get_buffer ( s , pkt - > data , size ) ;
if ( ret < = 0 )
av_free_packet ( pkt ) ;
else
pkt - > size = ret ;
return ret ;
}
2003-11-10 20:37:55 +02:00
int av_dup_packet ( AVPacket * pkt )
{
if ( pkt - > destruct ! = av_destruct_packet ) {
uint8_t * data ;
2008-01-17 00:14:26 +02:00
/* We duplicate the packet and don't forget to add the padding again. */
2005-01-08 16:21:33 +02:00
if ( ( unsigned ) pkt - > size > ( unsigned ) pkt - > size + FF_INPUT_BUFFER_PADDING_SIZE )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2003-12-09 17:34:44 +02:00
data = av_malloc ( pkt - > size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2003-11-10 20:37:55 +02:00
if ( ! data ) {
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2003-11-10 20:37:55 +02:00
}
memcpy ( data , pkt - > data , pkt - > size ) ;
2003-12-09 17:34:44 +02:00
memset ( data + pkt - > size , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2003-11-10 20:37:55 +02:00
pkt - > data = data ;
pkt - > destruct = av_destruct_packet ;
}
return 0 ;
}
2006-09-04 12:57:47 +03:00
int av_filename_number_test ( const char * filename )
2002-05-20 19:28:47 +03:00
{
char buf [ 1024 ] ;
2006-09-04 12:57:47 +03:00
return filename & & ( av_get_frame_filename ( buf , sizeof ( buf ) , filename , 1 ) > = 0 ) ;
2002-05-20 19:28:47 +03:00
}
2007-03-27 22:28:40 +03:00
static AVInputFormat * av_probe_input_format2 ( AVProbeData * pd , int is_opened , int * score_max )
2002-05-20 19:28:47 +03:00
{
AVInputFormat * fmt1 , * fmt ;
2007-03-27 22:28:40 +03:00
int score ;
2002-05-20 19:28:47 +03:00
fmt = NULL ;
for ( fmt1 = first_iformat ; fmt1 ! = NULL ; fmt1 = fmt1 - > next ) {
2007-01-20 00:52:59 +02:00
if ( ! is_opened = = ! ( fmt1 - > flags & AVFMT_NOFILE ) )
2002-05-20 19:28:47 +03:00
continue ;
score = 0 ;
2002-05-24 05:09:40 +03:00
if ( fmt1 - > read_probe ) {
score = fmt1 - > read_probe ( pd ) ;
} else if ( fmt1 - > extensions ) {
2002-05-20 19:28:47 +03:00
if ( match_ext ( pd - > filename , fmt1 - > extensions ) ) {
score = 50 ;
}
2005-12-17 20:14:38 +02:00
}
2007-03-27 22:28:40 +03:00
if ( score > * score_max ) {
* score_max = score ;
2002-05-20 19:28:47 +03:00
fmt = fmt1 ;
}
}
return fmt ;
}
2007-03-27 22:28:40 +03:00
AVInputFormat * av_probe_input_format ( AVProbeData * pd , int is_opened ) {
int score = 0 ;
return av_probe_input_format2 ( pd , is_opened , & score ) ;
}
2002-05-20 19:28:47 +03:00
/************************************************************/
/* input media file */
2001-09-25 02:25:28 +03:00
2003-10-29 16:20:56 +02:00
/**
2005-06-28 15:55:08 +03:00
* Open a media file from an IO stream . ' fmt ' must be specified .
2003-10-29 16:20:56 +02:00
*/
2004-03-03 19:53:55 +02:00
static const char * format_to_name ( void * ptr )
2004-03-03 17:41:21 +02:00
{
2004-03-03 19:53:55 +02:00
AVFormatContext * fc = ( AVFormatContext * ) ptr ;
2004-03-03 17:41:21 +02:00
if ( fc - > iformat ) return fc - > iformat - > name ;
else if ( fc - > oformat ) return fc - > oformat - > name ;
else return " NULL " ;
}
2006-09-14 16:51:54 +03:00
# define OFFSET(x) offsetof(AVFormatContext,x)
2007-06-12 12:29:25 +03:00
# define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C
2006-08-27 15:14:13 +03:00
//these names are too long to be readable
# define E AV_OPT_FLAG_ENCODING_PARAM
# define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption options [ ] = {
2006-09-11 00:51:08 +03:00
{ " probesize " , NULL , OFFSET ( probesize ) , FF_OPT_TYPE_INT , 32000 , 32 , INT_MAX , D } , /* 32000 from mpegts.c: 1.0 second at 24Mbit/s */
2006-09-20 11:23:01 +03:00
{ " muxrate " , " set mux rate " , OFFSET ( mux_rate ) , FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E } ,
2006-09-20 11:24:17 +03:00
{ " packetsize " , " set packet size " , OFFSET ( packet_size ) , FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E } ,
2006-10-27 13:53:08 +03:00
{ " fflags " , NULL , OFFSET ( flags ) , FF_OPT_TYPE_FLAGS , DEFAULT , INT_MIN , INT_MAX , D | E , " fflags " } ,
2006-09-05 22:23:32 +03:00
{ " ignidx " , " ignore index " , 0 , FF_OPT_TYPE_CONST , AVFMT_FLAG_IGNIDX , INT_MIN , INT_MAX , D , " fflags " } ,
{ " genpts " , " generate pts " , 0 , FF_OPT_TYPE_CONST , AVFMT_FLAG_GENPTS , INT_MIN , INT_MAX , D , " fflags " } ,
2006-09-11 00:51:08 +03:00
{ " track " , " set the track number " , OFFSET ( track ) , FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E } ,
2006-09-08 15:28:28 +03:00
{ " year " , " set the year " , OFFSET ( year ) , FF_OPT_TYPE_INT , DEFAULT , INT_MIN , INT_MAX , E } ,
2007-04-06 12:43:32 +03:00
{ " analyzeduration " , " how many microseconds are analyzed to estimate duration " , OFFSET ( max_analyze_duration ) , FF_OPT_TYPE_INT , 3 * AV_TIME_BASE , 0 , INT_MAX , D } ,
2007-12-17 19:41:24 +02:00
{ " cryptokey " , " decryption key " , OFFSET ( key ) , FF_OPT_TYPE_BINARY , 0 , 0 , 0 , D } ,
2008-01-13 15:33:37 +02:00
{ " indexmem " , " max memory used for timestamp index (per stream) " , OFFSET ( max_index_size ) , FF_OPT_TYPE_INT , INT_MAX , 0 , INT_MAX , D } ,
2006-08-27 15:14:13 +03:00
{ NULL } ,
} ;
2006-09-09 11:49:28 +03:00
# undef E
# undef D
# undef DEFAULT
2006-08-27 15:14:13 +03:00
static const AVClass av_format_context_class = { " AVFormatContext " , format_to_name , options } ;
2007-01-08 16:42:01 +02:00
static void avformat_get_context_defaults ( AVFormatContext * s )
{
2006-08-27 15:14:13 +03:00
memset ( s , 0 , sizeof ( AVFormatContext ) ) ;
2006-08-27 15:21:19 +03:00
2006-09-10 23:21:40 +03:00
s - > av_class = & av_format_context_class ;
av_opt_set_defaults ( s ) ;
2006-08-27 15:14:13 +03:00
}
2004-03-03 17:41:21 +02:00
AVFormatContext * av_alloc_format_context ( void )
{
AVFormatContext * ic ;
2006-09-14 15:04:07 +03:00
ic = av_malloc ( sizeof ( AVFormatContext ) ) ;
2004-03-03 17:41:21 +02:00
if ( ! ic ) return ic ;
2006-08-27 15:14:13 +03:00
avformat_get_context_defaults ( ic ) ;
2004-03-03 19:53:55 +02:00
ic - > av_class = & av_format_context_class ;
2004-03-03 17:41:21 +02:00
return ic ;
}
2005-12-17 20:14:38 +02:00
int av_open_input_stream ( AVFormatContext * * ic_ptr ,
ByteIOContext * pb , const char * filename ,
2003-10-29 16:20:56 +02:00
AVInputFormat * fmt , AVFormatParameters * ap )
{
int err ;
AVFormatContext * ic ;
2006-03-11 02:22:21 +02:00
AVFormatParameters default_ap ;
if ( ! ap ) {
ap = & default_ap ;
memset ( ap , 0 , sizeof ( default_ap ) ) ;
}
2003-10-29 16:20:56 +02:00
2006-08-27 15:14:13 +03:00
if ( ! ap - > prealloced_context )
ic = av_alloc_format_context ( ) ;
else
ic = * ic_ptr ;
2003-10-29 16:20:56 +02:00
if ( ! ic ) {
2007-07-19 18:21:30 +03:00
err = AVERROR ( ENOMEM ) ;
2003-10-29 16:20:56 +02:00
goto fail ;
}
ic - > iformat = fmt ;
2007-11-21 09:41:00 +02:00
ic - > pb = pb ;
2003-10-29 16:20:56 +02:00
ic - > duration = AV_NOPTS_VALUE ;
ic - > start_time = AV_NOPTS_VALUE ;
2007-06-24 02:10:32 +03:00
av_strlcpy ( ic - > filename , filename , sizeof ( ic - > filename ) ) ;
2003-10-29 16:20:56 +02:00
/* allocate private data */
if ( fmt - > priv_data_size > 0 ) {
ic - > priv_data = av_mallocz ( fmt - > priv_data_size ) ;
if ( ! ic - > priv_data ) {
2007-07-19 18:21:30 +03:00
err = AVERROR ( ENOMEM ) ;
2003-10-29 16:20:56 +02:00
goto fail ;
}
} else {
ic - > priv_data = NULL ;
}
err = ic - > iformat - > read_header ( ic , ap ) ;
if ( err < 0 )
goto fail ;
2003-11-10 20:37:55 +02:00
2006-11-11 21:37:21 +02:00
if ( pb & & ! ic - > data_offset )
2007-11-21 09:41:00 +02:00
ic - > data_offset = url_ftell ( ic - > pb ) ;
2003-11-10 20:37:55 +02:00
2003-10-29 16:20:56 +02:00
* ic_ptr = ic ;
return 0 ;
fail :
if ( ic ) {
av_freep ( & ic - > priv_data ) ;
}
av_free ( ic ) ;
* ic_ptr = NULL ;
return err ;
}
2008-01-17 00:14:26 +02:00
/** size of probe buffer, for guessing file type from file contents */
2006-02-02 13:27:35 +02:00
# define PROBE_BUF_MIN 2048
2006-06-13 14:10:55 +03:00
# define PROBE_BUF_MAX (1<<20)
2002-05-20 19:28:47 +03:00
2005-12-17 20:14:38 +02:00
int av_open_input_file ( AVFormatContext * * ic_ptr , const char * filename ,
2002-05-20 19:28:47 +03:00
AVInputFormat * fmt ,
int buf_size ,
AVFormatParameters * ap )
2001-07-22 17:18:56 +03:00
{
2007-12-17 21:08:17 +02:00
int err , probe_size ;
2002-05-20 19:28:47 +03:00
AVProbeData probe_data , * pd = & probe_data ;
2007-12-17 21:08:17 +02:00
ByteIOContext * pb = NULL ;
2005-12-17 20:14:38 +02:00
2003-10-29 16:20:56 +02:00
pd - > filename = " " ;
if ( filename )
pd - > filename = filename ;
2006-02-02 13:27:35 +02:00
pd - > buf = NULL ;
2002-05-20 19:28:47 +03:00
pd - > buf_size = 0 ;
if ( ! fmt ) {
2008-01-17 00:14:26 +02:00
/* guess format if no file can be opened */
2002-07-25 19:05:52 +03:00
fmt = av_probe_input_format ( pd , 0 ) ;
2001-07-22 17:18:56 +03:00
}
2008-01-17 00:14:26 +02:00
/* Do not open file if the format does not need it. XXX: specific
2003-07-15 19:57:35 +03:00
hack needed to handle RTSP / TCP */
2007-12-17 21:08:17 +02:00
if ( ! fmt | | ! ( fmt - > flags & AVFMT_NOFILE ) ) {
2003-01-11 07:02:14 +02:00
/* if no file needed do not try to open one */
2007-11-21 09:41:00 +02:00
if ( ( err = url_fopen ( & pb , filename , URL_RDONLY ) ) < 0 ) {
2001-09-25 02:25:28 +03:00
goto fail ;
2002-05-20 19:28:47 +03:00
}
2001-09-25 02:25:28 +03:00
if ( buf_size > 0 ) {
2003-10-29 16:20:56 +02:00
url_setbufsize ( pb , buf_size ) ;
2001-09-25 02:25:28 +03:00
}
2006-02-02 13:27:35 +02:00
for ( probe_size = PROBE_BUF_MIN ; probe_size < = PROBE_BUF_MAX & & ! fmt ; probe_size < < = 1 ) {
2007-03-27 22:28:40 +03:00
int score = probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX / 4 : 0 ;
2002-11-18 19:17:27 +02:00
/* read probe data */
2007-04-08 14:34:15 +03:00
pd - > buf = av_realloc ( pd - > buf , probe_size + AVPROBE_PADDING_SIZE ) ;
2006-02-02 13:27:35 +02:00
pd - > buf_size = get_buffer ( pb , pd - > buf , probe_size ) ;
2007-09-03 08:19:59 +03:00
memset ( pd - > buf + pd - > buf_size , 0 , AVPROBE_PADDING_SIZE ) ;
2007-03-01 18:40:48 +02:00
if ( url_fseek ( pb , 0 , SEEK_SET ) < 0 ) {
2004-07-25 14:59:34 +03:00
url_fclose ( pb ) ;
2007-11-21 09:41:00 +02:00
if ( url_fopen ( & pb , filename , URL_RDONLY ) < 0 ) {
2007-12-17 21:08:17 +02:00
pb = NULL ;
2007-07-19 18:23:32 +03:00
err = AVERROR ( EIO ) ;
2004-07-25 14:59:34 +03:00
goto fail ;
}
}
2006-02-02 13:27:35 +02:00
/* guess file format */
2007-03-27 22:28:40 +03:00
fmt = av_probe_input_format2 ( pd , 1 , & score ) ;
2002-11-18 19:17:27 +02:00
}
2006-02-02 13:27:35 +02:00
av_freep ( & pd - > buf ) ;
2002-05-20 19:28:47 +03:00
}
/* if still no format found, error */
if ( ! fmt ) {
err = AVERROR_NOFMT ;
2003-10-29 16:20:56 +02:00
goto fail ;
2001-07-22 17:18:56 +03:00
}
2005-12-17 20:14:38 +02:00
2008-01-17 00:14:26 +02:00
/* check filename in case an image number is expected */
2003-10-29 16:20:56 +02:00
if ( fmt - > flags & AVFMT_NEEDNUMBER ) {
2006-09-04 12:57:47 +03:00
if ( ! av_filename_number_test ( filename ) ) {
2003-01-11 07:02:14 +02:00
err = AVERROR_NUMEXPECTED ;
2003-10-29 16:20:56 +02:00
goto fail ;
2003-01-11 07:02:14 +02:00
}
}
2003-10-29 16:20:56 +02:00
err = av_open_input_stream ( ic_ptr , pb , filename , fmt , ap ) ;
if ( err )
goto fail ;
2002-05-20 19:28:47 +03:00
return 0 ;
2001-07-22 17:18:56 +03:00
fail :
2006-02-02 13:27:35 +02:00
av_freep ( & pd - > buf ) ;
2007-12-17 21:08:17 +02:00
if ( pb )
2003-10-29 16:20:56 +02:00
url_fclose ( pb ) ;
2002-05-20 19:28:47 +03:00
* ic_ptr = NULL ;
return err ;
2005-12-17 20:14:38 +02:00
2001-07-22 17:18:56 +03:00
}
2003-10-29 16:20:56 +02:00
/*******************************************************/
2001-07-22 17:18:56 +03:00
int av_read_packet ( AVFormatContext * s , AVPacket * pkt )
2003-11-10 20:37:55 +02:00
{
2007-12-19 12:56:17 +02:00
int ret ;
AVStream * st ;
2007-04-22 14:07:35 +03:00
av_init_packet ( pkt ) ;
2007-12-19 12:56:17 +02:00
ret = s - > iformat - > read_packet ( s , pkt ) ;
2007-12-23 15:16:55 +02:00
if ( ret < 0 )
return ret ;
2007-12-19 12:56:17 +02:00
st = s - > streams [ pkt - > stream_index ] ;
switch ( st - > codec - > codec_type ) {
case CODEC_TYPE_VIDEO :
if ( s - > video_codec_id ) st - > codec - > codec_id = s - > video_codec_id ;
break ;
case CODEC_TYPE_AUDIO :
if ( s - > audio_codec_id ) st - > codec - > codec_id = s - > audio_codec_id ;
break ;
case CODEC_TYPE_SUBTITLE :
if ( s - > subtitle_codec_id ) st - > codec - > codec_id = s - > subtitle_codec_id ;
break ;
}
return ret ;
2003-11-10 20:37:55 +02:00
}
/**********************************************************/
2005-06-28 15:55:08 +03:00
/**
2008-01-17 00:14:26 +02:00
* Get the number of samples of an audio frame . Return - 1 on error .
2005-06-28 15:55:08 +03:00
*/
2003-11-10 20:37:55 +02:00
static int get_audio_frame_size ( AVCodecContext * enc , int size )
{
int frame_size ;
if ( enc - > frame_size < = 1 ) {
2006-07-07 20:50:09 +03:00
int bits_per_sample = av_get_bits_per_sample ( enc - > codec_id ) ;
if ( bits_per_sample ) {
2003-11-10 20:37:55 +02:00
if ( enc - > channels = = 0 )
return - 1 ;
2006-07-08 10:14:00 +03:00
frame_size = ( size < < 3 ) / ( bits_per_sample * enc - > channels ) ;
2006-07-07 20:50:09 +03:00
} else {
2003-11-10 20:37:55 +02:00
/* used for example by ADPCM codecs */
if ( enc - > bit_rate = = 0 )
return - 1 ;
frame_size = ( size * 8 * enc - > sample_rate ) / enc - > bit_rate ;
}
} else {
frame_size = enc - > frame_size ;
}
return frame_size ;
}
2005-06-28 15:55:08 +03:00
/**
2008-01-17 00:14:26 +02:00
* Return the frame duration in seconds . Return 0 if not available .
2005-06-28 15:55:08 +03:00
*/
2005-12-17 20:14:38 +02:00
static void compute_frame_duration ( int * pnum , int * pden , AVStream * st ,
2003-11-10 20:37:55 +02:00
AVCodecParserContext * pc , AVPacket * pkt )
{
int frame_size ;
* pnum = 0 ;
* pden = 0 ;
2005-07-18 01:24:36 +03:00
switch ( st - > codec - > codec_type ) {
2003-11-10 20:37:55 +02:00
case CODEC_TYPE_VIDEO :
2005-05-12 19:27:05 +03:00
if ( st - > time_base . num * 1000LL > st - > time_base . den ) {
2005-05-01 00:43:59 +03:00
* pnum = st - > time_base . num ;
* pden = st - > time_base . den ;
2005-07-18 01:24:36 +03:00
} else if ( st - > codec - > time_base . num * 1000LL > st - > codec - > time_base . den ) {
* pnum = st - > codec - > time_base . num ;
* pden = st - > codec - > time_base . den ;
2005-05-06 23:26:50 +03:00
if ( pc & & pc - > repeat_pict ) {
* pden * = 2 ;
* pnum = ( * pnum ) * ( 2 + pc - > repeat_pict ) ;
}
2003-11-10 20:37:55 +02:00
}
break ;
case CODEC_TYPE_AUDIO :
2005-07-18 01:24:36 +03:00
frame_size = get_audio_frame_size ( st - > codec , pkt - > size ) ;
2003-11-10 20:37:55 +02:00
if ( frame_size < 0 )
break ;
* pnum = frame_size ;
2005-07-18 01:24:36 +03:00
* pden = st - > codec - > sample_rate ;
2003-11-10 20:37:55 +02:00
break ;
default :
break ;
}
}
2004-10-22 04:51:17 +03:00
static int is_intra_only ( AVCodecContext * enc ) {
if ( enc - > codec_type = = CODEC_TYPE_AUDIO ) {
return 1 ;
} else if ( enc - > codec_type = = CODEC_TYPE_VIDEO ) {
switch ( enc - > codec_id ) {
case CODEC_ID_MJPEG :
case CODEC_ID_MJPEGB :
case CODEC_ID_LJPEG :
case CODEC_ID_RAWVIDEO :
case CODEC_ID_DVVIDEO :
case CODEC_ID_HUFFYUV :
2004-11-28 20:29:38 +02:00
case CODEC_ID_FFVHUFF :
2004-10-22 04:51:17 +03:00
case CODEC_ID_ASV1 :
case CODEC_ID_ASV2 :
case CODEC_ID_VCR1 :
return 1 ;
default : break ;
}
}
return 0 ;
}
2007-09-03 10:56:26 +03:00
static void update_initial_timestamps ( AVFormatContext * s , int stream_index ,
int64_t dts , int64_t pts )
{
2007-08-05 01:46:13 +03:00
AVStream * st = s - > streams [ stream_index ] ;
AVPacketList * pktl = s - > packet_buffer ;
if ( st - > first_dts ! = AV_NOPTS_VALUE | | dts = = AV_NOPTS_VALUE )
return ;
st - > first_dts = dts - st - > cur_dts ;
st - > cur_dts = dts ;
for ( ; pktl ; pktl = pktl - > next ) {
if ( pktl - > pkt . stream_index ! = stream_index )
continue ;
//FIXME think more about this check
if ( pktl - > pkt . pts ! = AV_NOPTS_VALUE & & pktl - > pkt . pts = = pktl - > pkt . dts )
pktl - > pkt . pts + = st - > first_dts ;
if ( pktl - > pkt . dts ! = AV_NOPTS_VALUE )
pktl - > pkt . dts + = st - > first_dts ;
2007-08-05 01:54:46 +03:00
if ( st - > start_time = = AV_NOPTS_VALUE & & pktl - > pkt . pts ! = AV_NOPTS_VALUE )
st - > start_time = pktl - > pkt . pts ;
2007-08-05 01:46:13 +03:00
}
2007-09-03 10:56:26 +03:00
if ( st - > start_time = = AV_NOPTS_VALUE )
st - > start_time = pts ;
2007-08-05 01:46:13 +03:00
}
2005-12-17 20:14:38 +02:00
static void compute_pkt_fields ( AVFormatContext * s , AVStream * st ,
2003-11-10 20:37:55 +02:00
AVCodecParserContext * pc , AVPacket * pkt )
{
2007-03-17 16:27:01 +02:00
int num , den , presentation_delayed , delay , i ;
2007-04-13 10:50:04 +03:00
int64_t offset ;
2005-12-17 20:14:38 +02:00
2007-07-31 18:06:27 +03:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > dts > pkt - > pts & & st - > pts_wrap_bits < 63
/*&& pkt->dts-(1LL<<st->pts_wrap_bits) < pkt->pts*/ ) {
pkt - > dts - = 1LL < < st - > pts_wrap_bits ;
}
2003-11-10 20:37:55 +02:00
if ( pkt - > duration = = 0 ) {
2004-05-29 21:50:31 +03:00
compute_frame_duration ( & num , & den , st , pc , pkt ) ;
2003-11-10 20:37:55 +02:00
if ( den & & num ) {
2004-05-24 00:36:23 +03:00
pkt - > duration = av_rescale ( 1 , num * ( int64_t ) st - > time_base . den , den * ( int64_t ) st - > time_base . num ) ;
2003-11-10 20:37:55 +02:00
}
}
2008-01-17 00:14:26 +02:00
/* correct timestamps with byte offset if demuxers only have timestamps
on packet boundaries */
2007-04-13 10:50:04 +03:00
if ( pc & & st - > need_parsing = = AVSTREAM_PARSE_TIMESTAMPS & & pkt - > size ) {
/* this will estimate bitrate based on this frame's duration and size */
offset = av_rescale ( pc - > offset , pkt - > duration , pkt - > size ) ;
if ( pkt - > pts ! = AV_NOPTS_VALUE )
pkt - > pts + = offset ;
if ( pkt - > dts ! = AV_NOPTS_VALUE )
pkt - > dts + = offset ;
}
2008-01-17 00:14:26 +02:00
/* do we have a video B-frame ? */
2007-03-17 00:59:45 +02:00
delay = st - > codec - > has_b_frames ;
2003-11-10 20:37:55 +02:00
presentation_delayed = 0 ;
2007-03-17 16:29:00 +02:00
/* XXX: need has_b_frame, but cannot get it if the codec is
not initialized */
if ( delay & &
pc & & pc - > pict_type ! = FF_B_TYPE )
presentation_delayed = 1 ;
2007-06-12 12:29:25 +03:00
/* This may be redundant, but it should not hurt. */
2007-03-17 16:29:00 +02:00
if ( pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > pts > pkt - > dts )
presentation_delayed = 1 ;
2005-12-17 20:14:38 +02:00
2004-05-29 05:06:32 +03:00
if ( st - > cur_dts = = AV_NOPTS_VALUE ) {
2007-08-05 01:46:13 +03:00
st - > cur_dts = 0 ; //FIXME maybe set it to 0 during init
2004-05-29 05:06:32 +03:00
}
2003-11-10 20:37:55 +02:00
2006-11-02 00:39:58 +02:00
// av_log(NULL, AV_LOG_DEBUG, "IN delayed:%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64" st:%d pc:%p\n", presentation_delayed, pkt->pts, pkt->dts, st->cur_dts, pkt->stream_index, pc);
2003-11-10 20:37:55 +02:00
/* interpolate PTS and DTS if they are not present */
2007-03-17 16:29:00 +02:00
if ( delay < = 1 ) {
if ( presentation_delayed ) {
2008-01-17 00:14:26 +02:00
/* DTS = decompression timestamp */
/* PTS = presentation timestamp */
2007-03-17 16:29:00 +02:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
pkt - > dts = st - > last_IP_pts ;
2007-09-03 10:56:26 +03:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > dts , pkt - > pts ) ;
2007-03-17 16:29:00 +02:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
pkt - > dts = st - > cur_dts ;
/* this is tricky: the dts must be incremented by the duration
2008-01-17 00:14:26 +02:00
of the frame we are displaying , i . e . the last I - or P - frame */
2007-03-17 16:29:00 +02:00
if ( st - > last_IP_duration = = 0 )
st - > last_IP_duration = pkt - > duration ;
st - > cur_dts = pkt - > dts + st - > last_IP_duration ;
st - > last_IP_duration = pkt - > duration ;
st - > last_IP_pts = pkt - > pts ;
/* cannot compute PTS if not present (we can compute it only
2008-01-17 00:14:26 +02:00
by knowing the future */
2007-03-20 15:59:59 +02:00
} else if ( pkt - > pts ! = AV_NOPTS_VALUE | | pkt - > dts ! = AV_NOPTS_VALUE | | pkt - > duration ) {
2007-03-17 16:29:00 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > duration ) {
int64_t old_diff = FFABS ( st - > cur_dts - pkt - > duration - pkt - > pts ) ;
int64_t new_diff = FFABS ( st - > cur_dts - pkt - > pts ) ;
if ( old_diff < new_diff & & old_diff < ( pkt - > duration > > 3 ) ) {
pkt - > pts + = pkt - > duration ;
// av_log(NULL, AV_LOG_DEBUG, "id:%d old:%"PRId64" new:%"PRId64" dur:%d cur:%"PRId64" size:%d\n", pkt->stream_index, old_diff, new_diff, pkt->duration, st->cur_dts, pkt->size);
}
2004-12-15 04:36:03 +02:00
}
2005-12-17 20:14:38 +02:00
2007-03-17 16:29:00 +02:00
/* presentation is not delayed : PTS and DTS are the same */
if ( pkt - > pts = = AV_NOPTS_VALUE )
pkt - > pts = pkt - > dts ;
2007-09-03 10:56:26 +03:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > pts , pkt - > pts ) ;
2007-03-17 16:29:00 +02:00
if ( pkt - > pts = = AV_NOPTS_VALUE )
pkt - > pts = st - > cur_dts ;
pkt - > dts = pkt - > pts ;
st - > cur_dts = pkt - > pts + pkt - > duration ;
}
2003-11-10 20:37:55 +02:00
}
2007-03-17 16:27:01 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE ) {
st - > pts_buffer [ 0 ] = pkt - > pts ;
for ( i = 1 ; i < delay + 1 & & st - > pts_buffer [ i ] = = AV_NOPTS_VALUE ; i + + )
st - > pts_buffer [ i ] = ( i - delay - 1 ) * pkt - > duration ;
for ( i = 0 ; i < delay & & st - > pts_buffer [ i ] > st - > pts_buffer [ i + 1 ] ; i + + )
FFSWAP ( int64_t , st - > pts_buffer [ i ] , st - > pts_buffer [ i + 1 ] ) ;
if ( pkt - > dts = = AV_NOPTS_VALUE )
pkt - > dts = st - > pts_buffer [ 0 ] ;
2007-08-05 01:46:13 +03:00
if ( delay > 1 ) {
2007-09-03 10:56:26 +03:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > dts , pkt - > pts ) ; // this should happen on the first packet
2007-08-05 01:46:13 +03:00
}
2007-03-17 16:27:01 +02:00
if ( pkt - > dts > st - > cur_dts )
st - > cur_dts = pkt - > dts ;
}
// av_log(NULL, AV_LOG_ERROR, "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n", presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts);
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
/* update flags */
2007-10-24 07:54:44 +03:00
if ( is_intra_only ( st - > codec ) )
pkt - > flags | = PKT_FLAG_KEY ;
else if ( pc ) {
2003-11-10 20:37:55 +02:00
pkt - > flags = 0 ;
2008-01-17 00:14:26 +02:00
/* keyframe computation */
2003-11-10 20:37:55 +02:00
if ( pc - > pict_type = = FF_I_TYPE )
pkt - > flags | = PKT_FLAG_KEY ;
}
}
2004-09-29 00:09:25 +03:00
void av_destruct_packet_nofree ( AVPacket * pkt )
2003-11-10 20:37:55 +02:00
{
pkt - > data = NULL ; pkt - > size = 0 ;
}
static int av_read_frame_internal ( AVFormatContext * s , AVPacket * pkt )
{
AVStream * st ;
2003-12-15 16:45:37 +02:00
int len , ret , i ;
2003-11-10 20:37:55 +02:00
2007-04-22 14:07:35 +03:00
av_init_packet ( pkt ) ;
2003-11-10 20:37:55 +02:00
for ( ; ; ) {
/* select current input stream component */
st = s - > cur_st ;
if ( st ) {
2005-06-27 03:04:03 +03:00
if ( ! st - > need_parsing | | ! st - > parser ) {
2003-11-10 20:37:55 +02:00
/* no parsing needed: we just output the packet as is */
/* raw data support */
* pkt = s - > cur_pkt ;
compute_pkt_fields ( s , st , NULL , pkt ) ;
s - > cur_st = NULL ;
2006-08-08 22:55:32 +03:00
break ;
2005-03-17 03:25:01 +02:00
} else if ( s - > cur_len > 0 & & st - > discard < AVDISCARD_ALL ) {
2005-12-17 20:14:38 +02:00
len = av_parser_parse ( st - > parser , st - > codec , & pkt - > data , & pkt - > size ,
2003-12-16 13:21:25 +02:00
s - > cur_ptr , s - > cur_len ,
s - > cur_pkt . pts , s - > cur_pkt . dts ) ;
s - > cur_pkt . pts = AV_NOPTS_VALUE ;
s - > cur_pkt . dts = AV_NOPTS_VALUE ;
2003-11-10 20:37:55 +02:00
/* increment read pointer */
s - > cur_ptr + = len ;
s - > cur_len - = len ;
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
/* return packet if any */
if ( pkt - > size ) {
2003-12-15 16:45:37 +02:00
got_packet :
2007-05-02 16:36:45 +03:00
pkt - > pos = s - > cur_pkt . pos ; // Isn't quite accurate but close.
2003-11-10 20:37:55 +02:00
pkt - > duration = 0 ;
pkt - > stream_index = st - > index ;
2003-12-16 13:21:25 +02:00
pkt - > pts = st - > parser - > pts ;
pkt - > dts = st - > parser - > dts ;
2003-11-10 20:37:55 +02:00
pkt - > destruct = av_destruct_packet_nofree ;
compute_pkt_fields ( s , st , st - > parser , pkt ) ;
2007-02-06 01:04:48 +02:00
if ( ( s - > iformat - > flags & AVFMT_GENERIC_INDEX ) & & pkt - > flags & PKT_FLAG_KEY ) {
2008-01-13 15:33:37 +02:00
ff_reduce_index ( s , st - > index ) ;
2007-02-06 01:04:48 +02:00
av_add_index_entry ( st , st - > parser - > frame_offset , pkt - > dts ,
0 , 0 , AVINDEX_KEYFRAME ) ;
}
2006-08-08 22:55:32 +03:00
break ;
2003-11-10 20:37:55 +02:00
}
} else {
2003-11-20 13:22:25 +02:00
/* free packet */
2005-12-17 20:14:38 +02:00
av_free_packet ( & s - > cur_pkt ) ;
2003-11-10 20:37:55 +02:00
s - > cur_st = NULL ;
}
} else {
/* read next packet */
ret = av_read_packet ( s , & s - > cur_pkt ) ;
2003-12-15 16:45:37 +02:00
if ( ret < 0 ) {
2007-02-13 20:26:14 +02:00
if ( ret = = AVERROR ( EAGAIN ) )
2003-12-15 16:45:37 +02:00
return ret ;
/* return the last frames, if any */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
2005-06-27 03:04:03 +03:00
if ( st - > parser & & st - > need_parsing ) {
2005-12-17 20:14:38 +02:00
av_parser_parse ( st - > parser , st - > codec ,
& pkt - > data , & pkt - > size ,
NULL , 0 ,
2003-12-16 13:21:25 +02:00
AV_NOPTS_VALUE , AV_NOPTS_VALUE ) ;
2003-12-15 16:45:37 +02:00
if ( pkt - > size )
goto got_packet ;
}
}
2008-01-17 00:14:26 +02:00
/* no more packets: really terminate parsing */
2003-11-10 20:37:55 +02:00
return ret ;
2003-12-15 16:45:37 +02:00
}
2005-12-17 20:14:38 +02:00
2004-05-21 23:43:21 +03:00
st = s - > streams [ s - > cur_pkt . stream_index ] ;
2006-08-08 22:55:32 +03:00
if ( st - > codec - > debug & FF_DEBUG_PTS )
2006-10-14 23:43:39 +03:00
av_log ( s , AV_LOG_DEBUG , " av_read_packet stream=%d, pts=% " PRId64 " , dts=% " PRId64 " , size=%d \n " ,
2006-08-08 22:55:32 +03:00
s - > cur_pkt . stream_index ,
s - > cur_pkt . pts ,
s - > cur_pkt . dts ,
s - > cur_pkt . size ) ;
2003-11-10 20:37:55 +02:00
s - > cur_st = st ;
s - > cur_ptr = s - > cur_pkt . data ;
s - > cur_len = s - > cur_pkt . size ;
if ( st - > need_parsing & & ! st - > parser ) {
2005-07-18 01:24:36 +03:00
st - > parser = av_parser_init ( st - > codec - > codec_id ) ;
2003-11-10 20:37:55 +02:00
if ( ! st - > parser ) {
2008-01-17 00:14:26 +02:00
/* no parser available: just output the raw packets */
2007-04-15 16:51:57 +03:00
st - > need_parsing = AVSTREAM_PARSE_NONE ;
} else if ( st - > need_parsing = = AVSTREAM_PARSE_HEADERS ) {
2005-08-15 18:58:21 +03:00
st - > parser - > flags | = PARSER_FLAG_COMPLETE_FRAMES ;
2003-11-10 20:37:55 +02:00
}
2007-02-06 01:04:48 +02:00
if ( st - > parser & & ( s - > iformat - > flags & AVFMT_GENERIC_INDEX ) ) {
st - > parser - > last_frame_offset =
st - > parser - > cur_offset = s - > cur_pkt . pos ;
}
2003-11-10 20:37:55 +02:00
}
}
}
2006-08-08 22:55:32 +03:00
if ( st - > codec - > debug & FF_DEBUG_PTS )
2006-10-14 23:43:39 +03:00
av_log ( s , AV_LOG_DEBUG , " av_read_frame_internal stream=%d, pts=% " PRId64 " , dts=% " PRId64 " , size=%d \n " ,
2006-08-08 22:55:32 +03:00
pkt - > stream_index ,
pkt - > pts ,
pkt - > dts ,
pkt - > size ) ;
return 0 ;
2003-11-10 20:37:55 +02:00
}
2007-08-03 11:56:00 +03:00
static AVPacket * add_to_pktbuf ( AVFormatContext * s , AVPacket * pkt ) {
AVPacketList * pktl = s - > packet_buffer ;
AVPacketList * * plast_pktl = & s - > packet_buffer ;
while ( * plast_pktl ) plast_pktl = & ( * plast_pktl ) - > next ; //FIXME maybe maintain pointer to the last?
pktl = av_mallocz ( sizeof ( AVPacketList ) ) ;
if ( ! pktl )
return NULL ;
/* add the packet in the buffered packet list */
* plast_pktl = pktl ;
pktl - > pkt = * pkt ;
return & pktl - > pkt ;
}
2003-11-10 20:37:55 +02:00
int av_read_frame ( AVFormatContext * s , AVPacket * pkt )
2001-07-22 17:18:56 +03:00
{
AVPacketList * pktl ;
2005-08-15 17:22:43 +03:00
int eof = 0 ;
const int genpts = s - > flags & AVFMT_FLAG_GENPTS ;
for ( ; ; ) {
pktl = s - > packet_buffer ;
if ( pktl ) {
AVPacket * next_pkt = & pktl - > pkt ;
if ( genpts & & next_pkt - > dts ! = AV_NOPTS_VALUE ) {
while ( pktl & & next_pkt - > pts = = AV_NOPTS_VALUE ) {
2005-12-17 20:14:38 +02:00
if ( pktl - > pkt . stream_index = = next_pkt - > stream_index
2005-08-15 17:22:43 +03:00
& & next_pkt - > dts < pktl - > pkt . dts
& & pktl - > pkt . pts ! = pktl - > pkt . dts //not b frame
/*&& pktl->pkt.dts != AV_NOPTS_VALUE*/ ) {
next_pkt - > pts = pktl - > pkt . dts ;
}
pktl = pktl - > next ;
}
pktl = s - > packet_buffer ;
}
2005-12-17 20:14:38 +02:00
if ( next_pkt - > pts ! = AV_NOPTS_VALUE
| | next_pkt - > dts = = AV_NOPTS_VALUE
2005-08-15 17:22:43 +03:00
| | ! genpts | | eof ) {
/* read packet from packet buffer, if there is data */
* pkt = * next_pkt ;
s - > packet_buffer = pktl - > next ;
av_free ( pktl ) ;
return 0 ;
}
}
if ( genpts ) {
int ret = av_read_frame_internal ( s , pkt ) ;
if ( ret < 0 ) {
2007-02-13 20:26:14 +02:00
if ( pktl & & ret ! = AVERROR ( EAGAIN ) ) {
2005-08-15 17:22:43 +03:00
eof = 1 ;
continue ;
} else
return ret ;
}
2005-12-17 20:14:38 +02:00
2007-08-03 11:56:00 +03:00
if ( av_dup_packet ( add_to_pktbuf ( s , pkt ) ) < 0 )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2005-08-15 17:22:43 +03:00
} else {
assert ( ! s - > packet_buffer ) ;
return av_read_frame_internal ( s , pkt ) ;
}
2003-11-10 20:37:55 +02:00
}
}
/* XXX: suppress the packet queue */
static void flush_packet_queue ( AVFormatContext * s )
{
AVPacketList * pktl ;
for ( ; ; ) {
pktl = s - > packet_buffer ;
2005-12-17 20:14:38 +02:00
if ( ! pktl )
2003-11-10 20:37:55 +02:00
break ;
s - > packet_buffer = pktl - > next ;
av_free_packet ( & pktl - > pkt ) ;
av_free ( pktl ) ;
2002-05-20 19:28:47 +03:00
}
}
2003-11-10 20:37:55 +02:00
/*******************************************************/
/* seek support */
2004-01-14 00:02:49 +02:00
int av_find_default_stream_index ( AVFormatContext * s )
{
int i ;
AVStream * st ;
if ( s - > nb_streams < = 0 )
return - 1 ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) {
2004-01-14 00:02:49 +02:00
return i ;
}
}
return 0 ;
}
2005-06-28 15:55:08 +03:00
/**
* Flush the frame reader .
*/
2003-11-10 20:37:55 +02:00
static void av_read_frame_flush ( AVFormatContext * s )
{
AVStream * st ;
int i ;
flush_packet_queue ( s ) ;
/* free previous packet */
if ( s - > cur_st ) {
if ( s - > cur_st - > parser )
av_free_packet ( & s - > cur_pkt ) ;
s - > cur_st = NULL ;
}
/* fail safe */
s - > cur_ptr = NULL ;
s - > cur_len = 0 ;
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
/* for each stream, reset read state */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
st - > parser = NULL ;
}
2004-05-24 00:36:23 +03:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2007-03-20 15:01:39 +02:00
st - > cur_dts = AV_NOPTS_VALUE ; /* we set the current DTS to an unspecified origin */
2003-11-10 20:37:55 +02:00
}
}
2006-07-23 21:19:33 +03:00
void av_update_cur_dts ( AVFormatContext * s , AVStream * ref_st , int64_t timestamp ) {
2004-10-12 13:28:27 +03:00
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2004-10-22 16:15:18 +03:00
AVStream * st = s - > streams [ i ] ;
2004-10-12 13:28:27 +03:00
2005-12-17 20:14:38 +02:00
st - > cur_dts = av_rescale ( timestamp ,
2004-10-22 16:15:18 +03:00
st - > time_base . den * ( int64_t ) ref_st - > time_base . num ,
st - > time_base . num * ( int64_t ) ref_st - > time_base . den ) ;
2004-10-12 13:28:27 +03:00
}
}
2008-01-13 15:33:37 +02:00
void ff_reduce_index ( AVFormatContext * s , int stream_index )
{
AVStream * st = s - > streams [ stream_index ] ;
unsigned int max_entries = s - > max_index_size / sizeof ( AVIndexEntry ) ;
if ( ( unsigned ) st - > nb_index_entries > = max_entries ) {
int i ;
for ( i = 0 ; 2 * i < st - > nb_index_entries ; i + + )
st - > index_entries [ i ] = st - > index_entries [ 2 * i ] ;
st - > nb_index_entries = i ;
}
}
2004-01-17 20:06:52 +02:00
int av_add_index_entry ( AVStream * st ,
2006-03-01 13:29:55 +02:00
int64_t pos , int64_t timestamp , int size , int distance , int flags )
2003-11-10 20:37:55 +02:00
{
AVIndexEntry * entries , * ie ;
2004-01-14 00:02:49 +02:00
int index ;
2005-12-17 20:14:38 +02:00
2005-01-08 16:21:33 +02:00
if ( ( unsigned ) st - > nb_index_entries + 1 > = UINT_MAX / sizeof ( AVIndexEntry ) )
return - 1 ;
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
entries = av_fast_realloc ( st - > index_entries ,
& st - > index_entries_allocated_size ,
2005-12-17 20:14:38 +02:00
( st - > nb_index_entries + 1 ) *
2003-11-10 20:37:55 +02:00
sizeof ( AVIndexEntry ) ) ;
2005-01-08 16:21:33 +02:00
if ( ! entries )
return - 1 ;
2004-01-14 00:02:49 +02:00
st - > index_entries = entries ;
2005-03-13 02:13:01 +02:00
index = av_index_search_timestamp ( st , timestamp , AVSEEK_FLAG_ANY ) ;
2004-01-14 00:02:49 +02:00
2004-10-11 01:05:43 +03:00
if ( index < 0 ) {
2004-01-17 20:06:52 +02:00
index = st - > nb_index_entries + + ;
ie = & entries [ index ] ;
2004-10-11 01:05:43 +03:00
assert ( index = = 0 | | ie [ - 1 ] . timestamp < timestamp ) ;
} else {
ie = & entries [ index ] ;
if ( ie - > timestamp ! = timestamp ) {
2004-10-14 02:58:28 +03:00
if ( ie - > timestamp < = timestamp )
return - 1 ;
2004-10-11 01:05:43 +03:00
memmove ( entries + index + 1 , entries + index , sizeof ( AVIndexEntry ) * ( st - > nb_index_entries - index ) ) ;
st - > nb_index_entries + + ;
2007-06-12 12:29:25 +03:00
} else if ( ie - > pos = = pos & & distance < ie - > min_distance ) //do not reduce the distance
2004-10-11 01:05:43 +03:00
distance = ie - > min_distance ;
2004-01-17 20:06:52 +02:00
}
2004-10-11 01:05:43 +03:00
2004-01-14 00:02:49 +02:00
ie - > pos = pos ;
ie - > timestamp = timestamp ;
2004-01-17 20:06:52 +02:00
ie - > min_distance = distance ;
2006-03-01 13:29:55 +02:00
ie - > size = size ;
2004-01-14 00:02:49 +02:00
ie - > flags = flags ;
2005-12-17 20:14:38 +02:00
2004-01-17 20:06:52 +02:00
return index ;
2003-11-10 20:37:55 +02:00
}
2004-11-23 20:23:56 +02:00
int av_index_search_timestamp ( AVStream * st , int64_t wanted_timestamp ,
2005-03-13 02:13:01 +02:00
int flags )
2003-11-10 20:37:55 +02:00
{
2004-01-14 00:02:49 +02:00
AVIndexEntry * entries = st - > index_entries ;
int nb_entries = st - > nb_index_entries ;
2003-11-10 20:37:55 +02:00
int a , b , m ;
int64_t timestamp ;
2004-10-11 01:05:43 +03:00
a = - 1 ;
b = nb_entries ;
2004-01-14 00:02:49 +02:00
2004-10-11 01:05:43 +03:00
while ( b - a > 1 ) {
m = ( a + b ) > > 1 ;
2003-11-10 20:37:55 +02:00
timestamp = entries [ m ] . timestamp ;
2004-10-11 01:05:43 +03:00
if ( timestamp > = wanted_timestamp )
b = m ;
if ( timestamp < = wanted_timestamp )
2004-01-14 00:02:49 +02:00
a = m ;
2003-11-10 20:37:55 +02:00
}
2005-03-13 02:13:01 +02:00
m = ( flags & AVSEEK_FLAG_BACKWARD ) ? a : b ;
2005-12-17 20:14:38 +02:00
2005-03-13 02:13:01 +02:00
if ( ! ( flags & AVSEEK_FLAG_ANY ) ) {
while ( m > = 0 & & m < nb_entries & & ! ( entries [ m ] . flags & AVINDEX_KEYFRAME ) ) {
m + = ( flags & AVSEEK_FLAG_BACKWARD ) ? - 1 : 1 ;
}
}
2004-10-11 01:05:43 +03:00
2005-12-17 20:14:38 +02:00
if ( m = = nb_entries )
2004-10-11 01:05:43 +03:00
return - 1 ;
return m ;
2003-11-10 20:37:55 +02:00
}
2007-10-16 22:50:08 +03:00
# define DEBUG_SEEK
2004-04-12 19:50:03 +03:00
2004-10-11 01:05:43 +03:00
int av_seek_frame_binary ( AVFormatContext * s , int stream_index , int64_t target_ts , int flags ) {
2004-04-12 19:50:03 +03:00
AVInputFormat * avif = s - > iformat ;
int64_t pos_min , pos_max , pos , pos_limit ;
int64_t ts_min , ts_max , ts ;
2006-11-14 03:34:36 +02:00
int index ;
2004-04-12 19:50:03 +03:00
AVStream * st ;
2004-05-23 19:26:12 +03:00
if ( stream_index < 0 )
return - 1 ;
2005-12-17 20:14:38 +02:00
2004-04-12 19:50:03 +03:00
# ifdef DEBUG_SEEK
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_DEBUG , " read_seek: %d % " PRId64 " \n " , stream_index , target_ts ) ;
2004-04-12 19:50:03 +03:00
# endif
ts_max =
ts_min = AV_NOPTS_VALUE ;
2007-06-12 21:50:50 +03:00
pos_limit = - 1 ; //gcc falsely says it may be uninitialized
2004-04-12 19:50:03 +03:00
st = s - > streams [ stream_index ] ;
if ( st - > index_entries ) {
AVIndexEntry * e ;
2008-01-17 00:14:26 +02:00
index = av_index_search_timestamp ( st , target_ts , flags | AVSEEK_FLAG_BACKWARD ) ; //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp()
2004-10-11 01:05:43 +03:00
index = FFMAX ( index , 0 ) ;
2004-04-12 19:50:03 +03:00
e = & st - > index_entries [ index ] ;
if ( e - > timestamp < = target_ts | | e - > pos = = e - > min_distance ) {
pos_min = e - > pos ;
ts_min = e - > timestamp ;
# ifdef DEBUG_SEEK
2005-12-17 20:14:38 +02:00
av_log ( s , AV_LOG_DEBUG , " using cached pos_min=0x% " PRIx64 " dts_min=% " PRId64 " \n " ,
2004-04-12 19:50:03 +03:00
pos_min , ts_min ) ;
# endif
} else {
assert ( index = = 0 ) ;
}
2005-12-17 20:14:38 +02:00
index = av_index_search_timestamp ( st , target_ts , flags & ~ AVSEEK_FLAG_BACKWARD ) ;
2005-03-13 02:13:01 +02:00
assert ( index < st - > nb_index_entries ) ;
if ( index > = 0 ) {
2004-04-12 19:50:03 +03:00
e = & st - > index_entries [ index ] ;
assert ( e - > timestamp > = target_ts ) ;
pos_max = e - > pos ;
ts_max = e - > timestamp ;
pos_limit = pos_max - e - > min_distance ;
# ifdef DEBUG_SEEK
2005-12-17 20:14:38 +02:00
av_log ( s , AV_LOG_DEBUG , " using cached pos_max=0x% " PRIx64 " pos_limit=0x% " PRIx64 " dts_max=% " PRId64 " \n " ,
2004-04-12 19:50:03 +03:00
pos_max , pos_limit , ts_max ) ;
# endif
}
}
2006-11-14 03:34:36 +02:00
pos = av_gen_search ( s , stream_index , target_ts , pos_min , pos_max , pos_limit , ts_min , ts_max , flags , & ts , avif - > read_timestamp ) ;
if ( pos < 0 )
return - 1 ;
/* do the seek */
2007-11-21 09:41:00 +02:00
url_fseek ( s - > pb , pos , SEEK_SET ) ;
2006-11-14 03:34:36 +02:00
av_update_cur_dts ( s , st , ts ) ;
return 0 ;
}
int64_t av_gen_search ( AVFormatContext * s , int stream_index , int64_t target_ts , int64_t pos_min , int64_t pos_max , int64_t pos_limit , int64_t ts_min , int64_t ts_max , int flags , int64_t * ts_ret , int64_t ( * read_timestamp ) ( struct AVFormatContext * , int , int64_t * , int64_t ) ) {
int64_t pos , ts ;
int64_t start_pos , filesize ;
int no_change ;
# ifdef DEBUG_SEEK
av_log ( s , AV_LOG_DEBUG , " gen_seek: %d % " PRId64 " \n " , stream_index , target_ts ) ;
# endif
2004-04-12 19:50:03 +03:00
if ( ts_min = = AV_NOPTS_VALUE ) {
pos_min = s - > data_offset ;
2006-11-14 03:34:36 +02:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2004-04-12 19:50:03 +03:00
if ( ts_min = = AV_NOPTS_VALUE )
return - 1 ;
}
if ( ts_max = = AV_NOPTS_VALUE ) {
int step = 1024 ;
2007-11-21 09:41:00 +02:00
filesize = url_fsize ( s - > pb ) ;
2005-07-08 12:14:05 +03:00
pos_max = filesize - 1 ;
2004-04-12 19:50:03 +03:00
do {
pos_max - = step ;
2006-11-14 03:34:36 +02:00
ts_max = read_timestamp ( s , stream_index , & pos_max , pos_max + step ) ;
2004-04-12 19:50:03 +03:00
step + = step ;
} while ( ts_max = = AV_NOPTS_VALUE & & pos_max > = step ) ;
if ( ts_max = = AV_NOPTS_VALUE )
return - 1 ;
2005-12-17 20:14:38 +02:00
2004-04-12 19:50:03 +03:00
for ( ; ; ) {
int64_t tmp_pos = pos_max + 1 ;
2006-11-14 03:34:36 +02:00
int64_t tmp_ts = read_timestamp ( s , stream_index , & tmp_pos , INT64_MAX ) ;
2004-04-12 19:50:03 +03:00
if ( tmp_ts = = AV_NOPTS_VALUE )
break ;
ts_max = tmp_ts ;
pos_max = tmp_pos ;
2005-07-08 12:14:05 +03:00
if ( tmp_pos > = filesize )
break ;
2004-04-12 19:50:03 +03:00
}
pos_limit = pos_max ;
}
2006-02-02 21:23:33 +02:00
if ( ts_min > ts_max ) {
return - 1 ;
} else if ( ts_min = = ts_max ) {
pos_limit = pos_min ;
}
2004-04-12 19:50:03 +03:00
no_change = 0 ;
while ( pos_min < pos_limit ) {
# ifdef DEBUG_SEEK
2005-12-17 20:14:38 +02:00
av_log ( s , AV_LOG_DEBUG , " pos_min=0x% " PRIx64 " pos_max=0x% " PRIx64 " dts_min=% " PRId64 " dts_max=% " PRId64 " \n " ,
2004-04-12 19:50:03 +03:00
pos_min , pos_max ,
ts_min , ts_max ) ;
# endif
assert ( pos_limit < = pos_max ) ;
if ( no_change = = 0 ) {
int64_t approximate_keyframe_distance = pos_max - pos_limit ;
// interpolate position (better than dichotomy)
2004-10-11 01:05:43 +03:00
pos = av_rescale ( target_ts - ts_min , pos_max - pos_min , ts_max - ts_min )
+ pos_min - approximate_keyframe_distance ;
2004-04-12 19:50:03 +03:00
} else if ( no_change = = 1 ) {
// bisection, if interpolation failed to change min or max pos last time
pos = ( pos_min + pos_limit ) > > 1 ;
} else {
2008-01-17 00:14:26 +02:00
/* linear search if bisection failed, can only happen if there
are very few or no keyframes between min / max */
2004-04-12 19:50:03 +03:00
pos = pos_min ;
}
if ( pos < = pos_min )
pos = pos_min + 1 ;
else if ( pos > pos_limit )
pos = pos_limit ;
start_pos = pos ;
2006-11-14 03:34:36 +02:00
ts = read_timestamp ( s , stream_index , & pos , INT64_MAX ) ; //may pass pos_limit instead of -1
2004-04-12 19:50:03 +03:00
if ( pos = = pos_max )
no_change + + ;
else
no_change = 0 ;
# ifdef DEBUG_SEEK
2005-12-12 03:56:46 +02:00
av_log ( s , AV_LOG_DEBUG , " % " PRId64 " % " PRId64 " % " PRId64 " / % " PRId64 " % " PRId64 " % " PRId64 " target:% " PRId64 " limit:% " PRId64 " start:% " PRId64 " noc:%d \n " , pos_min , pos , pos_max , ts_min , ts , ts_max , target_ts , pos_limit , start_pos , no_change ) ;
2004-04-12 19:50:03 +03:00
# endif
2007-04-22 21:48:07 +03:00
if ( ts = = AV_NOPTS_VALUE ) {
av_log ( s , AV_LOG_ERROR , " read_timestamp() failed in the middle \n " ) ;
return - 1 ;
}
2004-04-12 19:50:03 +03:00
assert ( ts ! = AV_NOPTS_VALUE ) ;
2004-10-11 01:05:43 +03:00
if ( target_ts < = ts ) {
2004-04-12 19:50:03 +03:00
pos_limit = start_pos - 1 ;
pos_max = pos ;
ts_max = ts ;
2004-10-11 01:05:43 +03:00
}
if ( target_ts > = ts ) {
2004-04-12 19:50:03 +03:00
pos_min = pos ;
ts_min = ts ;
}
}
2005-12-17 20:14:38 +02:00
2004-10-11 01:05:43 +03:00
pos = ( flags & AVSEEK_FLAG_BACKWARD ) ? pos_min : pos_max ;
ts = ( flags & AVSEEK_FLAG_BACKWARD ) ? ts_min : ts_max ;
2004-04-12 19:50:03 +03:00
# ifdef DEBUG_SEEK
pos_min = pos ;
2006-11-14 03:34:36 +02:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2004-04-12 19:50:03 +03:00
pos_min + + ;
2006-11-14 03:34:36 +02:00
ts_max = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2005-12-17 20:14:38 +02:00
av_log ( s , AV_LOG_DEBUG , " pos=0x% " PRIx64 " % " PRId64 " <=% " PRId64 " <=% " PRId64 " \n " ,
2004-04-12 19:50:03 +03:00
pos , ts_min , target_ts , ts_max ) ;
# endif
2006-11-14 03:34:36 +02:00
* ts_ret = ts ;
return pos ;
2004-04-12 19:50:03 +03:00
}
2004-10-11 01:05:43 +03:00
static int av_seek_frame_byte ( AVFormatContext * s , int stream_index , int64_t pos , int flags ) {
int64_t pos_min , pos_max ;
#if 0
AVStream * st ;
if ( stream_index < 0 )
return - 1 ;
st = s - > streams [ stream_index ] ;
# endif
pos_min = s - > data_offset ;
2007-11-21 09:41:00 +02:00
pos_max = url_fsize ( s - > pb ) - 1 ;
2004-10-11 01:05:43 +03:00
if ( pos < pos_min ) pos = pos_min ;
else if ( pos > pos_max ) pos = pos_max ;
2007-11-21 09:41:00 +02:00
url_fseek ( s - > pb , pos , SEEK_SET ) ;
2004-10-11 01:05:43 +03:00
#if 0
2004-10-12 13:28:27 +03:00
av_update_cur_dts ( s , st , ts ) ;
2004-10-11 01:05:43 +03:00
# endif
return 0 ;
}
2005-12-17 20:14:38 +02:00
static int av_seek_frame_generic ( AVFormatContext * s ,
2004-10-11 01:05:43 +03:00
int stream_index , int64_t timestamp , int flags )
2003-11-10 20:37:55 +02:00
{
2004-10-12 13:28:27 +03:00
int index ;
2003-11-10 20:37:55 +02:00
AVStream * st ;
AVIndexEntry * ie ;
st = s - > streams [ stream_index ] ;
2007-02-06 01:04:48 +02:00
2005-03-13 02:13:01 +02:00
index = av_index_search_timestamp ( st , timestamp , flags ) ;
2007-02-06 01:04:48 +02:00
2007-04-22 19:23:44 +03:00
if ( index < 0 | | index = = st - > nb_index_entries - 1 ) {
2007-02-06 01:04:48 +02:00
int i ;
AVPacket pkt ;
if ( st - > index_entries & & st - > nb_index_entries ) {
ie = & st - > index_entries [ st - > nb_index_entries - 1 ] ;
2007-11-21 09:41:00 +02:00
url_fseek ( s - > pb , ie - > pos , SEEK_SET ) ;
2007-02-06 01:04:48 +02:00
av_update_cur_dts ( s , st , ie - > timestamp ) ;
} else
2007-11-21 09:41:00 +02:00
url_fseek ( s - > pb , 0 , SEEK_SET ) ;
2007-02-06 01:04:48 +02:00
for ( i = 0 ; ; i + + ) {
int ret = av_read_frame ( s , & pkt ) ;
if ( ret < 0 )
break ;
av_free_packet ( & pkt ) ;
if ( stream_index = = pkt . stream_index ) {
if ( ( pkt . flags & PKT_FLAG_KEY ) & & pkt . dts > timestamp )
break ;
}
}
index = av_index_search_timestamp ( st , timestamp , flags ) ;
}
2003-11-10 20:37:55 +02:00
if ( index < 0 )
return - 1 ;
av_read_frame_flush ( s ) ;
2007-02-06 01:04:48 +02:00
if ( s - > iformat - > read_seek ) {
if ( s - > iformat - > read_seek ( s , stream_index , timestamp , flags ) > = 0 )
return 0 ;
}
ie = & st - > index_entries [ index ] ;
2007-11-21 09:41:00 +02:00
url_fseek ( s - > pb , ie - > pos , SEEK_SET ) ;
2004-10-11 01:05:43 +03:00
2004-10-12 13:28:27 +03:00
av_update_cur_dts ( s , st , ie - > timestamp ) ;
2004-05-23 19:26:12 +03:00
2003-11-10 20:37:55 +02:00
return 0 ;
}
2004-10-11 01:05:43 +03:00
int av_seek_frame ( AVFormatContext * s , int stream_index , int64_t timestamp , int flags )
2003-11-10 20:37:55 +02:00
{
int ret ;
2004-05-23 19:26:12 +03:00
AVStream * st ;
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
av_read_frame_flush ( s ) ;
2005-12-17 20:14:38 +02:00
2004-10-11 01:05:43 +03:00
if ( flags & AVSEEK_FLAG_BYTE )
return av_seek_frame_byte ( s , stream_index , timestamp , flags ) ;
2005-12-17 20:14:38 +02:00
2004-05-23 19:26:12 +03:00
if ( stream_index < 0 ) {
stream_index = av_find_default_stream_index ( s ) ;
if ( stream_index < 0 )
return - 1 ;
2005-12-17 20:14:38 +02:00
2004-10-11 01:05:43 +03:00
st = s - > streams [ stream_index ] ;
2004-10-11 22:42:18 +03:00
/* timestamp for default must be expressed in AV_TIME_BASE units */
2004-10-11 01:05:43 +03:00
timestamp = av_rescale ( timestamp , st - > time_base . den , AV_TIME_BASE * ( int64_t ) st - > time_base . num ) ;
2004-05-23 19:26:12 +03:00
}
st = s - > streams [ stream_index ] ;
2003-11-10 20:37:55 +02:00
/* first, we try the format specific seek */
if ( s - > iformat - > read_seek )
2004-10-11 01:05:43 +03:00
ret = s - > iformat - > read_seek ( s , stream_index , timestamp , flags ) ;
2003-11-10 20:37:55 +02:00
else
ret = - 1 ;
if ( ret > = 0 ) {
return 0 ;
}
2004-04-12 19:50:03 +03:00
if ( s - > iformat - > read_timestamp )
2004-10-11 01:05:43 +03:00
return av_seek_frame_binary ( s , stream_index , timestamp , flags ) ;
2004-04-12 19:50:03 +03:00
else
2004-10-11 01:05:43 +03:00
return av_seek_frame_generic ( s , stream_index , timestamp , flags ) ;
2003-11-10 20:37:55 +02:00
}
2003-10-29 16:20:56 +02:00
/*******************************************************/
2003-08-08 21:02:23 +03:00
2005-06-28 15:55:08 +03:00
/**
2007-09-05 19:47:48 +03:00
* Returns TRUE if the stream has accurate duration in any stream .
2005-06-28 15:55:08 +03:00
*
2007-09-05 19:47:48 +03:00
* @ return TRUE if the stream has accurate duration for at least one component .
2005-06-28 15:55:08 +03:00
*/
2007-09-05 19:47:48 +03:00
static int av_has_duration ( AVFormatContext * ic )
2003-08-08 21:02:23 +03:00
{
int i ;
AVStream * st ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2007-09-05 19:47:48 +03:00
if ( st - > duration ! = AV_NOPTS_VALUE )
2003-08-08 21:02:23 +03:00
return 1 ;
}
return 0 ;
}
2005-06-28 15:55:08 +03:00
/**
* Estimate the stream timings from the one of each components .
*
* Also computes the global bitrate if possible .
*/
2003-08-08 21:02:23 +03:00
static void av_update_stream_timings ( AVFormatContext * ic )
{
2005-05-01 00:43:59 +03:00
int64_t start_time , start_time1 , end_time , end_time1 ;
2007-09-05 19:47:48 +03:00
int64_t duration , duration1 ;
2003-08-08 21:02:23 +03:00
int i ;
AVStream * st ;
2006-12-07 02:47:37 +02:00
start_time = INT64_MAX ;
end_time = INT64_MIN ;
2007-09-05 19:47:48 +03:00
duration = INT64_MIN ;
2003-08-08 21:02:23 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( st - > start_time ! = AV_NOPTS_VALUE ) {
2005-05-01 00:43:59 +03:00
start_time1 = av_rescale_q ( st - > start_time , st - > time_base , AV_TIME_BASE_Q ) ;
if ( start_time1 < start_time )
start_time = start_time1 ;
2003-08-08 21:02:23 +03:00
if ( st - > duration ! = AV_NOPTS_VALUE ) {
2005-05-01 00:43:59 +03:00
end_time1 = start_time1
+ av_rescale_q ( st - > duration , st - > time_base , AV_TIME_BASE_Q ) ;
2003-08-08 21:02:23 +03:00
if ( end_time1 > end_time )
end_time = end_time1 ;
}
}
2007-09-05 19:47:48 +03:00
if ( st - > duration ! = AV_NOPTS_VALUE ) {
duration1 = av_rescale_q ( st - > duration , st - > time_base , AV_TIME_BASE_Q ) ;
if ( duration1 > duration )
duration = duration1 ;
}
2003-08-08 21:02:23 +03:00
}
2006-12-07 02:47:37 +02:00
if ( start_time ! = INT64_MAX ) {
2003-08-08 21:02:23 +03:00
ic - > start_time = start_time ;
2006-12-07 02:47:37 +02:00
if ( end_time ! = INT64_MIN ) {
2007-09-05 19:47:48 +03:00
if ( end_time - start_time > duration )
duration = end_time - start_time ;
}
}
if ( duration ! = INT64_MIN ) {
ic - > duration = duration ;
if ( ic - > file_size > 0 ) {
2008-01-17 00:14:26 +02:00
/* compute the bitrate */
2007-09-05 19:47:48 +03:00
ic - > bit_rate = ( double ) ic - > file_size * 8.0 * AV_TIME_BASE /
( double ) ic - > duration ;
2003-08-08 21:02:23 +03:00
}
}
}
static void fill_all_stream_timings ( AVFormatContext * ic )
{
int i ;
AVStream * st ;
av_update_stream_timings ( ic ) ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( st - > start_time = = AV_NOPTS_VALUE ) {
2005-05-01 00:43:59 +03:00
if ( ic - > start_time ! = AV_NOPTS_VALUE )
st - > start_time = av_rescale_q ( ic - > start_time , AV_TIME_BASE_Q , st - > time_base ) ;
if ( ic - > duration ! = AV_NOPTS_VALUE )
st - > duration = av_rescale_q ( ic - > duration , AV_TIME_BASE_Q , st - > time_base ) ;
2003-08-08 21:02:23 +03:00
}
}
}
static void av_estimate_timings_from_bit_rate ( AVFormatContext * ic )
{
int64_t filesize , duration ;
int bit_rate , i ;
AVStream * st ;
/* if bit_rate is already set, we believe it */
if ( ic - > bit_rate = = 0 ) {
bit_rate = 0 ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
bit_rate + = st - > codec - > bit_rate ;
2003-08-08 21:02:23 +03:00
}
ic - > bit_rate = bit_rate ;
}
/* if duration is already set, we believe it */
2005-12-17 20:14:38 +02:00
if ( ic - > duration = = AV_NOPTS_VALUE & &
ic - > bit_rate ! = 0 & &
2003-08-08 21:02:23 +03:00
ic - > file_size ! = 0 ) {
filesize = ic - > file_size ;
if ( filesize > 0 ) {
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-05-01 00:43:59 +03:00
duration = av_rescale ( 8 * filesize , st - > time_base . den , ic - > bit_rate * ( int64_t ) st - > time_base . num ) ;
2007-08-18 04:26:06 +03:00
if ( st - > duration = = AV_NOPTS_VALUE )
2003-08-08 21:02:23 +03:00
st - > duration = duration ;
}
}
}
}
# define DURATION_MAX_READ_SIZE 250000
/* only usable for MPEG-PS streams */
2007-02-05 04:08:57 +02:00
static void av_estimate_timings_from_pts ( AVFormatContext * ic , offset_t old_offset )
2003-08-08 21:02:23 +03:00
{
AVPacket pkt1 , * pkt = & pkt1 ;
AVStream * st ;
int read_size , i , ret ;
2005-08-14 18:42:40 +03:00
int64_t end_time ;
2003-08-08 21:02:23 +03:00
int64_t filesize , offset , duration ;
2005-12-17 20:14:38 +02:00
2007-04-26 13:49:48 +03:00
/* free previous packet */
if ( ic - > cur_st & & ic - > cur_st - > parser )
av_free_packet ( & ic - > cur_pkt ) ;
ic - > cur_st = NULL ;
/* flush packet queue */
flush_packet_queue ( ic ) ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
st - > parser = NULL ;
}
}
2005-12-17 20:14:38 +02:00
2003-08-08 21:02:23 +03:00
/* we read the first packets to get the first PTS (not fully
accurate , but it is enough now ) */
2007-11-21 09:41:00 +02:00
url_fseek ( ic - > pb , 0 , SEEK_SET ) ;
2003-08-08 21:02:23 +03:00
read_size = 0 ;
for ( ; ; ) {
if ( read_size > = DURATION_MAX_READ_SIZE )
break ;
/* if all info is available, we can stop */
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( st - > start_time = = AV_NOPTS_VALUE )
break ;
}
if ( i = = ic - > nb_streams )
break ;
ret = av_read_packet ( ic , pkt ) ;
if ( ret ! = 0 )
break ;
read_size + = pkt - > size ;
st = ic - > streams [ pkt - > stream_index ] ;
if ( pkt - > pts ! = AV_NOPTS_VALUE ) {
if ( st - > start_time = = AV_NOPTS_VALUE )
2005-05-01 00:43:59 +03:00
st - > start_time = pkt - > pts ;
2003-09-07 12:26:39 +03:00
}
av_free_packet ( pkt ) ;
}
2003-08-08 21:02:23 +03:00
/* estimate the end time (duration) */
/* XXX: may need to support wrapping */
filesize = ic - > file_size ;
offset = filesize - DURATION_MAX_READ_SIZE ;
if ( offset < 0 )
offset = 0 ;
2007-11-21 09:41:00 +02:00
url_fseek ( ic - > pb , offset , SEEK_SET ) ;
2003-08-08 21:02:23 +03:00
read_size = 0 ;
for ( ; ; ) {
if ( read_size > = DURATION_MAX_READ_SIZE )
break ;
2005-12-17 20:14:38 +02:00
2003-08-08 21:02:23 +03:00
ret = av_read_packet ( ic , pkt ) ;
if ( ret ! = 0 )
break ;
read_size + = pkt - > size ;
st = ic - > streams [ pkt - > stream_index ] ;
2007-08-18 03:45:44 +03:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & &
st - > start_time ! = AV_NOPTS_VALUE ) {
2005-05-01 00:43:59 +03:00
end_time = pkt - > pts ;
2003-08-08 21:02:23 +03:00
duration = end_time - st - > start_time ;
if ( duration > 0 ) {
if ( st - > duration = = AV_NOPTS_VALUE | |
st - > duration < duration )
st - > duration = duration ;
}
}
av_free_packet ( pkt ) ;
}
2005-12-17 20:14:38 +02:00
2005-05-01 00:43:59 +03:00
fill_all_stream_timings ( ic ) ;
2003-08-08 21:02:23 +03:00
2007-11-21 09:41:00 +02:00
url_fseek ( ic - > pb , old_offset , SEEK_SET ) ;
2007-08-18 03:44:14 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
st - > cur_dts = st - > first_dts ;
2007-09-05 17:11:33 +03:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2007-08-18 03:44:14 +03:00
}
2003-08-08 21:02:23 +03:00
}
2007-02-05 04:08:57 +02:00
static void av_estimate_timings ( AVFormatContext * ic , offset_t old_offset )
2003-08-08 21:02:23 +03:00
{
int64_t file_size ;
/* get the file size, if possible */
if ( ic - > iformat - > flags & AVFMT_NOFILE ) {
file_size = 0 ;
} else {
2007-11-21 09:41:00 +02:00
file_size = url_fsize ( ic - > pb ) ;
2003-08-08 21:02:23 +03:00
if ( file_size < 0 )
file_size = 0 ;
}
ic - > file_size = file_size ;
2006-07-11 00:14:37 +03:00
if ( ( ! strcmp ( ic - > iformat - > name , " mpeg " ) | |
! strcmp ( ic - > iformat - > name , " mpegts " ) ) & &
2007-12-20 01:26:18 +02:00
file_size & & ! url_is_streamed ( ic - > pb ) ) {
2003-08-08 21:02:23 +03:00
/* get accurate estimate from the PTSes */
2007-02-05 04:08:57 +02:00
av_estimate_timings_from_pts ( ic , old_offset ) ;
2007-09-05 19:47:48 +03:00
} else if ( av_has_duration ( ic ) ) {
2008-01-17 00:14:26 +02:00
/* at least one component has timings - we use them for all
2003-08-08 21:02:23 +03:00
the components */
fill_all_stream_timings ( ic ) ;
} else {
2008-01-17 00:14:26 +02:00
/* less precise: use bitrate info */
2003-08-08 21:02:23 +03:00
av_estimate_timings_from_bit_rate ( ic ) ;
}
av_update_stream_timings ( ic ) ;
#if 0
{
int i ;
AVStream * st ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-12-17 20:14:38 +02:00
printf ( " %d: start_time: %0.3f duration: %0.3f \n " ,
i , ( double ) st - > start_time / AV_TIME_BASE ,
2003-08-08 21:02:23 +03:00
( double ) st - > duration / AV_TIME_BASE ) ;
}
2005-12-17 20:14:38 +02:00
printf ( " stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s \n " ,
( double ) ic - > start_time / AV_TIME_BASE ,
2003-08-08 21:02:23 +03:00
( double ) ic - > duration / AV_TIME_BASE ,
ic - > bit_rate / 1000 ) ;
}
# endif
}
2002-05-20 19:28:47 +03:00
static int has_codec_parameters ( AVCodecContext * enc )
{
int val ;
switch ( enc - > codec_type ) {
case CODEC_TYPE_AUDIO :
val = enc - > sample_rate ;
break ;
case CODEC_TYPE_VIDEO :
2005-04-25 21:29:06 +03:00
val = enc - > width & & enc - > pix_fmt ! = PIX_FMT_NONE ;
2002-05-20 19:28:47 +03:00
break ;
default :
val = 1 ;
break ;
}
2007-10-02 01:11:10 +03:00
return ( enc - > codec_id ! = CODEC_ID_NONE & & val ! = 0 ) ;
2002-05-20 19:28:47 +03:00
}
2003-11-10 20:37:55 +02:00
static int try_decode_frame ( AVStream * st , const uint8_t * data , int size )
{
int16_t * samples ;
AVCodec * codec ;
2007-02-27 15:07:38 +02:00
int got_picture , data_size , ret = 0 ;
2003-11-10 20:37:55 +02:00
AVFrame picture ;
2005-12-17 20:14:38 +02:00
2005-07-18 01:24:36 +03:00
if ( ! st - > codec - > codec ) {
codec = avcodec_find_decoder ( st - > codec - > codec_id ) ;
2003-11-10 20:37:55 +02:00
if ( ! codec )
return - 1 ;
2005-07-18 01:24:36 +03:00
ret = avcodec_open ( st - > codec , codec ) ;
2003-11-10 20:37:55 +02:00
if ( ret < 0 )
return ret ;
2005-06-27 23:54:36 +03:00
}
2005-04-25 21:29:06 +03:00
2005-07-18 01:24:36 +03:00
if ( ! has_codec_parameters ( st - > codec ) ) {
switch ( st - > codec - > codec_type ) {
2003-11-10 20:37:55 +02:00
case CODEC_TYPE_VIDEO :
2005-12-17 20:14:38 +02:00
ret = avcodec_decode_video ( st - > codec , & picture ,
2003-11-10 20:37:55 +02:00
& got_picture , ( uint8_t * ) data , size ) ;
break ;
case CODEC_TYPE_AUDIO :
2007-02-27 15:07:38 +02:00
data_size = FFMAX ( size , AVCODEC_MAX_AUDIO_FRAME_SIZE ) ;
samples = av_malloc ( data_size ) ;
2003-11-10 20:37:55 +02:00
if ( ! samples )
goto fail ;
2007-02-27 15:07:38 +02:00
ret = avcodec_decode_audio2 ( st - > codec , samples ,
& data_size , ( uint8_t * ) data , size ) ;
2003-11-10 20:37:55 +02:00
av_free ( samples ) ;
break ;
default :
break ;
}
2005-04-25 21:29:06 +03:00
}
2003-11-10 20:37:55 +02:00
fail :
return ret ;
}
2007-04-12 11:11:33 +03:00
static int set_codec_from_probe_data ( AVStream * st , AVProbeData * pd , int score )
{
AVInputFormat * fmt ;
fmt = av_probe_input_format2 ( pd , 1 , & score ) ;
if ( fmt ) {
if ( strncmp ( fmt - > name , " mp3 " , 3 ) = = 0 )
st - > codec - > codec_id = CODEC_ID_MP3 ;
else if ( strncmp ( fmt - > name , " ac3 " , 3 ) = = 0 )
st - > codec - > codec_id = CODEC_ID_AC3 ;
}
2007-05-02 12:18:41 +03:00
return ! ! fmt ;
2007-04-12 11:11:33 +03:00
}
2007-07-11 15:45:14 +03:00
unsigned int codec_get_tag ( const AVCodecTag * tags , int id )
{
while ( tags - > id ! = CODEC_ID_NONE ) {
if ( tags - > id = = id )
return tags - > tag ;
tags + + ;
}
return 0 ;
}
enum CodecID codec_get_id ( const AVCodecTag * tags , unsigned int tag )
{
2007-07-27 14:36:17 +03:00
int i ;
for ( i = 0 ; tags [ i ] . id ! = CODEC_ID_NONE ; i + + ) {
if ( tag = = tags [ i ] . tag )
return tags [ i ] . id ;
}
for ( i = 0 ; tags [ i ] . id ! = CODEC_ID_NONE ; i + + ) {
if ( toupper ( ( tag > > 0 ) & 0xFF ) = = toupper ( ( tags [ i ] . tag > > 0 ) & 0xFF )
& & toupper ( ( tag > > 8 ) & 0xFF ) = = toupper ( ( tags [ i ] . tag > > 8 ) & 0xFF )
& & toupper ( ( tag > > 16 ) & 0xFF ) = = toupper ( ( tags [ i ] . tag > > 16 ) & 0xFF )
& & toupper ( ( tag > > 24 ) & 0xFF ) = = toupper ( ( tags [ i ] . tag > > 24 ) & 0xFF ) )
return tags [ i ] . id ;
2007-07-11 15:45:14 +03:00
}
return CODEC_ID_NONE ;
}
unsigned int av_codec_get_tag ( const AVCodecTag * tags [ 4 ] , enum CodecID id )
{
int i ;
for ( i = 0 ; tags & & tags [ i ] ; i + + ) {
int tag = codec_get_tag ( tags [ i ] , id ) ;
if ( tag ) return tag ;
}
return 0 ;
}
enum CodecID av_codec_get_id ( const AVCodecTag * tags [ 4 ] , unsigned int tag )
{
int i ;
for ( i = 0 ; tags & & tags [ i ] ; i + + ) {
enum CodecID id = codec_get_id ( tags [ i ] , tag ) ;
if ( id ! = CODEC_ID_NONE ) return id ;
}
return CODEC_ID_NONE ;
}
2003-11-10 20:37:55 +02:00
/* absolute maximum size we read until we abort */
# define MAX_READ_SIZE 5000000
2006-12-12 16:07:46 +02:00
# define MAX_STD_TIMEBASES (60*12+5)
2006-12-11 18:59:10 +02:00
static int get_std_framerate ( int i ) {
if ( i < 60 * 12 ) return i * 1001 ;
2006-12-12 16:07:46 +02:00
else return ( ( int [ ] ) { 24 , 30 , 60 , 12 , 15 } ) [ i - 60 * 12 ] * 1000 * 12 ;
2006-12-11 18:59:10 +02:00
}
2007-12-27 02:16:48 +02:00
/*
* Is the time base unreliable .
* This is a heuristic to balance between quick acceptance of the values in
* the headers vs . some extra checks .
2008-01-17 00:14:26 +02:00
* Old DivX and Xvid often have nonsense timebases like 1f ps or 2f ps .
* MPEG - 2 commonly misuses field repeat flags to store different framerates .
2007-12-27 02:16:48 +02:00
* And there are " variable " fps files this needs to detect as well .
*/
static int tb_unreliable ( AVCodecContext * c ) {
if ( c - > time_base . den > = 101L * c - > time_base . num
| | c - > time_base . den < 5L * c - > time_base . num
/* || c->codec_tag == ff_get_fourcc("DIVX")
| | c - > codec_tag = = ff_get_fourcc ( " XVID " ) */
| | c - > codec_id = = CODEC_ID_MPEG2VIDEO )
return 1 ;
return 0 ;
}
2002-05-20 19:28:47 +03:00
int av_find_stream_info ( AVFormatContext * ic )
{
2006-02-02 22:54:41 +02:00
int i , count , ret , read_size , j ;
2002-05-20 19:28:47 +03:00
AVStream * st ;
2003-11-10 20:37:55 +02:00
AVPacket pkt1 , * pkt ;
2004-12-19 03:23:22 +02:00
int64_t last_dts [ MAX_STREAMS ] ;
2005-05-07 02:41:47 +03:00
int duration_count [ MAX_STREAMS ] = { 0 } ;
2007-03-02 15:23:06 +02:00
double ( * duration_error ) [ MAX_STD_TIMEBASES ] ;
2007-11-21 09:41:00 +02:00
offset_t old_offset = url_ftell ( ic - > pb ) ;
2007-03-12 12:59:47 +02:00
int64_t codec_info_duration [ MAX_STREAMS ] = { 0 } ;
int codec_info_nb_frames [ MAX_STREAMS ] = { 0 } ;
2007-04-12 11:11:33 +03:00
AVProbeData probe_data [ MAX_STREAMS ] ;
int codec_identified [ MAX_STREAMS ] = { 0 } ;
2002-05-20 19:28:47 +03:00
2007-03-02 15:23:06 +02:00
duration_error = av_mallocz ( MAX_STREAMS * sizeof ( * duration_error ) ) ;
2007-07-19 18:21:30 +03:00
if ( ! duration_error ) return AVERROR ( ENOMEM ) ;
2007-03-02 15:23:06 +02:00
2005-05-01 00:43:59 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) {
2005-05-01 00:43:59 +03:00
/* if(!st->time_base.num)
st - > time_base = */
2005-07-18 01:24:36 +03:00
if ( ! st - > codec - > time_base . num )
st - > codec - > time_base = st - > time_base ;
2005-05-01 00:43:59 +03:00
}
2005-06-27 03:04:03 +03:00
//only for the split stuff
if ( ! st - > parser ) {
2005-07-18 01:24:36 +03:00
st - > parser = av_parser_init ( st - > codec - > codec_id ) ;
2007-04-15 16:51:57 +03:00
if ( st - > need_parsing = = AVSTREAM_PARSE_HEADERS & & st - > parser ) {
2005-08-15 18:58:21 +03:00
st - > parser - > flags | = PARSER_FLAG_COMPLETE_FRAMES ;
}
2005-06-27 03:04:03 +03:00
}
2005-05-01 00:43:59 +03:00
}
2004-12-19 03:23:22 +02:00
for ( i = 0 ; i < MAX_STREAMS ; i + + ) {
last_dts [ i ] = AV_NOPTS_VALUE ;
}
2005-12-17 20:14:38 +02:00
2007-04-12 11:11:33 +03:00
memset ( probe_data , 0 , sizeof ( probe_data ) ) ;
2002-05-20 19:28:47 +03:00
count = 0 ;
read_size = 0 ;
for ( ; ; ) {
/* check if one codec still needs to be handled */
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( ! has_codec_parameters ( st - > codec ) )
2002-05-20 19:28:47 +03:00
break ;
2004-12-21 04:16:11 +02:00
/* variable fps and no guess at the real fps */
2007-12-27 02:16:48 +02:00
if ( tb_unreliable ( st - > codec )
2005-07-18 01:24:36 +03:00
& & duration_count [ i ] < 20 & & st - > codec - > codec_type = = CODEC_TYPE_VIDEO )
2004-12-21 04:16:11 +02:00
break ;
2005-07-18 01:24:36 +03:00
if ( st - > parser & & st - > parser - > parser - > split & & ! st - > codec - > extradata )
2005-06-27 03:04:03 +03:00
break ;
2007-08-05 01:46:13 +03:00
if ( st - > first_dts = = AV_NOPTS_VALUE )
break ;
2002-05-20 19:28:47 +03:00
}
if ( i = = ic - > nb_streams ) {
/* NOTE: if the format has no header, then we need to read
some packets to get most of the streams , so we cannot
stop here */
2003-11-10 20:37:55 +02:00
if ( ! ( ic - > ctx_flags & AVFMTCTX_NOHEADER ) ) {
2002-05-20 19:28:47 +03:00
/* if we found the info for all the codecs, we can stop */
ret = count ;
break ;
}
2006-09-26 20:25:28 +03:00
}
2006-09-26 20:27:08 +03:00
/* we did not get all the codec info, but we read too much data */
if ( read_size > = MAX_READ_SIZE ) {
ret = count ;
break ;
}
2002-05-20 19:28:47 +03:00
2003-11-10 20:37:55 +02:00
/* NOTE: a new stream can be added there if no header in file
( AVFMTCTX_NOHEADER ) */
ret = av_read_frame_internal ( ic , & pkt1 ) ;
if ( ret < 0 ) {
/* EOF or error */
ret = - 1 ; /* we could not have all the codec parameters before EOF */
2005-01-22 04:30:45 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2006-03-21 13:29:50 +02:00
if ( ! has_codec_parameters ( st - > codec ) ) {
char buf [ 256 ] ;
avcodec_string ( buf , sizeof ( buf ) , st - > codec , 0 ) ;
av_log ( ic , AV_LOG_INFO , " Could not find codec parameters (%s) \n " , buf ) ;
2006-06-29 22:02:15 +03:00
} else {
ret = 0 ;
2006-03-21 13:29:50 +02:00
}
2005-01-22 04:30:45 +02:00
}
2003-11-10 20:37:55 +02:00
break ;
}
2007-08-03 11:56:00 +03:00
pkt = add_to_pktbuf ( ic , & pkt1 ) ;
if ( av_dup_packet ( pkt ) < 0 )
return AVERROR ( ENOMEM ) ;
2002-05-20 19:28:47 +03:00
2003-11-10 20:37:55 +02:00
read_size + = pkt - > size ;
2002-05-20 19:28:47 +03:00
st = ic - > streams [ pkt - > stream_index ] ;
2007-03-12 12:59:47 +02:00
if ( codec_info_nb_frames [ st - > index ] > 1 )
codec_info_duration [ st - > index ] + = pkt - > duration ;
2003-11-10 20:37:55 +02:00
if ( pkt - > duration ! = 0 )
2007-03-12 12:59:47 +02:00
codec_info_nb_frames [ st - > index ] + + ;
2003-11-10 20:37:55 +02:00
2005-05-22 11:47:09 +03:00
{
2005-05-07 02:41:47 +03:00
int index = pkt - > stream_index ;
int64_t last = last_dts [ index ] ;
int64_t duration = pkt - > dts - last ;
if ( pkt - > dts ! = AV_NOPTS_VALUE & & last ! = AV_NOPTS_VALUE & & duration > 0 ) {
2006-12-11 18:59:10 +02:00
double dur = duration * av_q2d ( st - > time_base ) ;
// if(st->codec->codec_type == CODEC_TYPE_VIDEO)
// av_log(NULL, AV_LOG_ERROR, "%f\n", dur);
2007-01-02 22:32:01 +02:00
if ( duration_count [ index ] < 2 )
2007-03-02 15:23:06 +02:00
memset ( duration_error , 0 , MAX_STREAMS * sizeof ( * duration_error ) ) ;
2007-01-02 22:35:46 +02:00
for ( i = 1 ; i < MAX_STD_TIMEBASES ; i + + ) {
int framerate = get_std_framerate ( i ) ;
int ticks = lrintf ( dur * framerate / ( 1001 * 12 ) ) ;
double error = dur - ticks * 1001 * 12 / ( double ) framerate ;
duration_error [ index ] [ i ] + = error * error ;
}
2006-12-11 18:59:10 +02:00
duration_count [ index ] + + ;
2004-12-19 03:23:22 +02:00
}
2006-12-12 16:07:46 +02:00
if ( last = = AV_NOPTS_VALUE | | duration_count [ index ] < = 1 )
last_dts [ pkt - > stream_index ] = pkt - > dts ;
2007-04-12 11:11:33 +03:00
if ( st - > codec - > codec_id = = CODEC_ID_NONE ) {
AVProbeData * pd = & ( probe_data [ st - > index ] ) ;
2007-09-03 08:19:59 +03:00
pd - > buf = av_realloc ( pd - > buf , pd - > buf_size + pkt - > size + AVPROBE_PADDING_SIZE ) ;
2007-04-12 11:11:33 +03:00
memcpy ( pd - > buf + pd - > buf_size , pkt - > data , pkt - > size ) ;
pd - > buf_size + = pkt - > size ;
2007-09-03 08:19:59 +03:00
memset ( pd - > buf + pd - > buf_size , 0 , AVPROBE_PADDING_SIZE ) ;
2007-04-12 11:11:33 +03:00
}
2004-12-19 03:23:22 +02:00
}
2005-07-18 01:24:36 +03:00
if ( st - > parser & & st - > parser - > parser - > split & & ! st - > codec - > extradata ) {
int i = st - > parser - > parser - > split ( st - > codec , pkt - > data , pkt - > size ) ;
2005-06-27 03:04:03 +03:00
if ( i ) {
2005-07-18 01:24:36 +03:00
st - > codec - > extradata_size = i ;
2006-06-29 22:42:34 +03:00
st - > codec - > extradata = av_malloc ( st - > codec - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-07-18 01:24:36 +03:00
memcpy ( st - > codec - > extradata , pkt - > data , st - > codec - > extradata_size ) ;
2006-06-29 22:42:34 +03:00
memset ( st - > codec - > extradata + i , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-06-27 03:04:03 +03:00
}
}
2005-12-17 20:14:38 +02:00
2003-11-10 20:37:55 +02:00
/* if still no information, we try to open the codec and to
decompress the frame . We try to avoid that in most cases as
2008-01-17 00:14:26 +02:00
it takes longer and uses more memory . For MPEG - 4 , we need to
decompress for QuickTime . */
2005-07-18 01:24:36 +03:00
if ( ! has_codec_parameters ( st - > codec ) /*&&
( st - > codec - > codec_id = = CODEC_ID_FLV1 | |
st - > codec - > codec_id = = CODEC_ID_H264 | |
st - > codec - > codec_id = = CODEC_ID_H263 | |
st - > codec - > codec_id = = CODEC_ID_H261 | |
st - > codec - > codec_id = = CODEC_ID_VORBIS | |
st - > codec - > codec_id = = CODEC_ID_MJPEG | |
st - > codec - > codec_id = = CODEC_ID_PNG | |
st - > codec - > codec_id = = CODEC_ID_PAM | |
st - > codec - > codec_id = = CODEC_ID_PGM | |
st - > codec - > codec_id = = CODEC_ID_PGMYUV | |
st - > codec - > codec_id = = CODEC_ID_PBM | |
st - > codec - > codec_id = = CODEC_ID_PPM | |
st - > codec - > codec_id = = CODEC_ID_SHORTEN | |
( st - > codec - > codec_id = = CODEC_ID_MPEG4 & & ! st - > need_parsing ) ) */ )
2003-11-10 20:37:55 +02:00
try_decode_frame ( st , pkt - > data , pkt - > size ) ;
2005-12-17 20:14:38 +02:00
2007-07-14 15:42:57 +03:00
if ( st - > time_base . den > 0 & & av_rescale_q ( codec_info_duration [ st - > index ] , st - > time_base , AV_TIME_BASE_Q ) > = ic - > max_analyze_duration ) {
2003-11-10 20:37:55 +02:00
break ;
2002-05-20 19:28:47 +03:00
}
count + + ;
}
2005-06-27 23:54:36 +03:00
// close codecs which where opened in try_decode_frame()
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec )
avcodec_close ( st - > codec ) ;
2005-06-27 23:54:36 +03:00
}
2002-05-20 19:28:47 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) {
if ( st - > codec - > codec_id = = CODEC_ID_RAWVIDEO & & ! st - > codec - > codec_tag & & ! st - > codec - > bits_per_sample )
st - > codec - > codec_tag = avcodec_pix_fmt_to_codec_tag ( st - > codec - > pix_fmt ) ;
2004-12-19 03:23:22 +02:00
2007-01-02 22:32:01 +02:00
if ( duration_count [ i ]
2007-12-27 02:16:48 +02:00
& & tb_unreliable ( st - > codec ) /*&&
2008-01-17 00:14:26 +02:00
//FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ...
2006-12-11 18:59:10 +02:00
st - > time_base . num * duration_sum [ i ] / duration_count [ i ] * 101LL > st - > time_base . den */ ) {
double best_error = 2 * av_q2d ( st - > time_base ) ;
best_error = best_error * best_error * duration_count [ i ] * 1000 * 12 * 30 ;
for ( j = 1 ; j < MAX_STD_TIMEBASES ; j + + ) {
double error = duration_error [ i ] [ j ] * get_std_framerate ( j ) ;
// if(st->codec->codec_type == CODEC_TYPE_VIDEO)
// av_log(NULL, AV_LOG_ERROR, "%f %f\n", get_std_framerate(j) / 12.0/1001, error);
2006-02-02 22:54:41 +02:00
if ( error < best_error ) {
best_error = error ;
2006-12-11 18:59:10 +02:00
av_reduce ( & st - > r_frame_rate . num , & st - > r_frame_rate . den , get_std_framerate ( j ) , 12 * 1001 , INT_MAX ) ;
2006-02-02 22:54:41 +02:00
}
2005-05-07 02:41:47 +03:00
}
2004-12-19 03:23:22 +02:00
}
2005-05-01 00:43:59 +03:00
if ( ! st - > r_frame_rate . num ) {
2006-10-03 22:13:27 +03:00
if ( st - > codec - > time_base . den * ( int64_t ) st - > time_base . num
< = st - > codec - > time_base . num * ( int64_t ) st - > time_base . den ) {
st - > r_frame_rate . num = st - > codec - > time_base . den ;
st - > r_frame_rate . den = st - > codec - > time_base . num ;
} else {
st - > r_frame_rate . num = st - > time_base . den ;
st - > r_frame_rate . den = st - > time_base . num ;
}
2003-03-12 17:16:19 +02:00
}
2007-02-20 18:18:59 +02:00
} else if ( st - > codec - > codec_type = = CODEC_TYPE_AUDIO ) {
2007-06-10 23:35:01 +03:00
if ( st - > codec - > codec_id = = CODEC_ID_NONE & & probe_data [ st - > index ] . buf_size > 0 ) {
2007-07-25 23:39:43 +03:00
codec_identified [ st - > index ] = set_codec_from_probe_data ( st , & ( probe_data [ st - > index ] ) , 1 ) ;
2007-04-12 11:11:33 +03:00
if ( codec_identified [ st - > index ] ) {
2007-04-15 16:51:57 +03:00
st - > need_parsing = AVSTREAM_PARSE_FULL ;
2007-04-12 11:11:33 +03:00
}
}
2007-02-20 18:18:59 +02:00
if ( ! st - > codec - > bits_per_sample )
st - > codec - > bits_per_sample = av_get_bits_per_sample ( st - > codec - > codec_id ) ;
2002-05-20 19:28:47 +03:00
}
2001-07-22 17:18:56 +03:00
}
2002-05-20 19:28:47 +03:00
2007-02-05 04:08:57 +02:00
av_estimate_timings ( ic , old_offset ) ;
2007-04-12 11:11:33 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2007-08-07 00:14:29 +03:00
if ( codec_identified [ st - > index ] )
break ;
}
//FIXME this is a mess
if ( i ! = ic - > nb_streams ) {
av_read_frame_flush ( ic ) ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( codec_identified [ st - > index ] ) {
av_seek_frame ( ic , st - > index , 0.0 , 0 ) ;
}
st - > cur_dts = st - > first_dts ;
2007-04-12 11:11:33 +03:00
}
2007-11-21 09:41:00 +02:00
url_fseek ( ic - > pb , ic - > data_offset , SEEK_SET ) ;
2007-04-12 11:11:33 +03:00
}
2004-05-29 05:06:32 +03:00
#if 0
2008-01-17 00:14:26 +02:00
/* correct DTS for B-frame streams with no timestamps */
2004-05-29 05:06:32 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) {
2004-05-29 05:06:32 +03:00
if ( b - frames ) {
ppktl = & ic - > packet_buffer ;
while ( ppkt1 ) {
if ( ppkt1 - > stream_index ! = i )
continue ;
if ( ppkt1 - > pkt - > dts < 0 )
break ;
if ( ppkt1 - > pkt - > pts ! = AV_NOPTS_VALUE )
break ;
ppkt1 - > pkt - > dts - = delta ;
ppkt1 = ppkt1 - > next ;
}
if ( ppkt1 )
continue ;
st - > cur_dts - = delta ;
}
}
}
# endif
2007-03-02 15:23:06 +02:00
av_free ( duration_error ) ;
2007-04-12 11:11:33 +03:00
for ( i = 0 ; i < MAX_STREAMS ; i + + ) {
av_freep ( & ( probe_data [ i ] . buf ) ) ;
}
2007-03-02 15:23:06 +02:00
2002-05-20 19:28:47 +03:00
return ret ;
2001-07-22 17:18:56 +03:00
}
2003-11-10 20:37:55 +02:00
/*******************************************************/
int av_read_play ( AVFormatContext * s )
{
2007-12-17 11:28:46 +02:00
if ( s - > iformat - > read_play )
return s - > iformat - > read_play ( s ) ;
2007-12-20 02:25:18 +02:00
if ( s - > pb )
2007-12-19 22:57:13 +02:00
return av_url_read_fpause ( s - > pb , 0 ) ;
2007-12-17 11:28:46 +02:00
return AVERROR ( ENOSYS ) ;
2003-11-10 20:37:55 +02:00
}
int av_read_pause ( AVFormatContext * s )
{
2007-12-17 11:28:46 +02:00
if ( s - > iformat - > read_pause )
return s - > iformat - > read_pause ( s ) ;
2007-12-20 02:25:18 +02:00
if ( s - > pb )
2007-12-19 22:57:13 +02:00
return av_url_read_fpause ( s - > pb , 1 ) ;
2007-12-17 11:28:46 +02:00
return AVERROR ( ENOSYS ) ;
2003-11-10 20:37:55 +02:00
}
2007-12-19 16:07:13 +02:00
void av_close_input_stream ( AVFormatContext * s )
2001-07-22 17:18:56 +03:00
{
2007-12-17 21:12:43 +02:00
int i ;
2003-10-29 16:20:56 +02:00
AVStream * st ;
2001-07-22 17:18:56 +03:00
2003-11-10 20:37:55 +02:00
/* free previous packet */
if ( s - > cur_st & & s - > cur_st - > parser )
2005-12-17 20:14:38 +02:00
av_free_packet ( & s - > cur_pkt ) ;
2003-11-10 20:37:55 +02:00
2002-05-20 19:28:47 +03:00
if ( s - > iformat - > read_close )
s - > iformat - > read_close ( s ) ;
2001-07-22 17:18:56 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2003-10-29 16:20:56 +02:00
/* free all data in a stream component */
st = s - > streams [ i ] ;
2003-11-10 20:37:55 +02:00
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
2001-07-22 17:18:56 +03:00
}
2003-11-10 20:37:55 +02:00
av_free ( st - > index_entries ) ;
2006-06-16 10:54:37 +03:00
av_free ( st - > codec - > extradata ) ;
2005-07-18 01:24:36 +03:00
av_free ( st - > codec ) ;
2003-11-10 20:37:55 +02:00
av_free ( st ) ;
2001-07-22 17:18:56 +03:00
}
2007-09-25 23:45:46 +03:00
for ( i = s - > nb_programs - 1 ; i > = 0 ; i - - ) {
av_freep ( & s - > programs [ i ] - > provider_name ) ;
av_freep ( & s - > programs [ i ] - > name ) ;
2007-10-20 11:25:13 +03:00
av_freep ( & s - > programs [ i ] - > stream_index ) ;
2007-09-25 23:45:46 +03:00
av_freep ( & s - > programs [ i ] ) ;
}
2003-11-10 20:37:55 +02:00
flush_packet_queue ( s ) ;
2002-05-24 05:09:40 +03:00
av_freep ( & s - > priv_data ) ;
2002-05-19 02:11:09 +03:00
av_free ( s ) ;
2001-07-22 17:18:56 +03:00
}
2007-12-19 16:07:13 +02:00
void av_close_input_file ( AVFormatContext * s )
{
ByteIOContext * pb = s - > iformat - > flags & AVFMT_NOFILE ? NULL : s - > pb ;
av_close_input_stream ( s ) ;
if ( pb )
url_fclose ( pb ) ;
}
2002-05-20 19:28:47 +03:00
AVStream * av_new_stream ( AVFormatContext * s , int id )
{
AVStream * st ;
2006-08-31 00:18:17 +03:00
int i ;
2002-05-20 19:28:47 +03:00
if ( s - > nb_streams > = MAX_STREAMS )
return NULL ;
st = av_mallocz ( sizeof ( AVStream ) ) ;
if ( ! st )
return NULL ;
2005-12-17 20:14:38 +02:00
2005-07-18 01:24:36 +03:00
st - > codec = avcodec_alloc_context ( ) ;
2003-08-08 21:13:43 +03:00
if ( s - > iformat ) {
/* no default bitrate if decoding */
2005-07-18 01:24:36 +03:00
st - > codec - > bit_rate = 0 ;
2003-08-08 21:13:43 +03:00
}
2002-05-20 19:28:47 +03:00
st - > index = s - > nb_streams ;
st - > id = id ;
2003-08-08 21:02:23 +03:00
st - > start_time = AV_NOPTS_VALUE ;
st - > duration = AV_NOPTS_VALUE ;
2004-05-29 05:06:32 +03:00
st - > cur_dts = AV_NOPTS_VALUE ;
2007-08-05 01:46:13 +03:00
st - > first_dts = AV_NOPTS_VALUE ;
2004-05-21 23:43:21 +03:00
2008-01-17 00:14:26 +02:00
/* default pts setting is MPEG-like */
2004-05-21 23:43:21 +03:00
av_set_pts_info ( st , 33 , 1 , 90000 ) ;
2004-05-24 00:36:23 +03:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2006-08-31 00:18:17 +03:00
for ( i = 0 ; i < MAX_REORDER_DELAY + 1 ; i + + )
st - > pts_buffer [ i ] = AV_NOPTS_VALUE ;
2004-05-21 23:43:21 +03:00
2002-05-20 19:28:47 +03:00
s - > streams [ s - > nb_streams + + ] = st ;
return st ;
}
2007-09-25 23:45:46 +03:00
AVProgram * av_new_program ( AVFormatContext * ac , int id )
{
AVProgram * program = NULL ;
int i ;
# ifdef DEBUG_SI
av_log ( ac , AV_LOG_DEBUG , " new_program: id=0x%04x \n " , id ) ;
# endif
for ( i = 0 ; i < ac - > nb_programs ; i + + )
if ( ac - > programs [ i ] - > id = = id )
program = ac - > programs [ i ] ;
if ( ! program ) {
program = av_mallocz ( sizeof ( AVProgram ) ) ;
if ( ! program )
return NULL ;
dynarray_add ( & ac - > programs , & ac - > nb_programs , program ) ;
program - > discard = AVDISCARD_NONE ;
}
program - > id = id ;
return program ;
}
void av_set_program_name ( AVProgram * program , char * provider_name , char * name )
{
assert ( ! provider_name = = ! name ) ;
if ( name ) {
av_free ( program - > provider_name ) ;
av_free ( program - > name ) ;
program - > provider_name = av_strdup ( provider_name ) ;
program - > name = av_strdup ( name ) ;
}
}
2002-05-20 19:28:47 +03:00
/************************************************************/
/* output media file */
2001-07-22 17:18:56 +03:00
2003-01-11 07:02:14 +02:00
int av_set_parameters ( AVFormatContext * s , AVFormatParameters * ap )
{
int ret ;
2005-12-17 20:14:38 +02:00
2003-01-24 00:00:57 +02:00
if ( s - > oformat - > priv_data_size > 0 ) {
s - > priv_data = av_mallocz ( s - > oformat - > priv_data_size ) ;
if ( ! s - > priv_data )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2003-01-24 00:00:57 +02:00
} else
s - > priv_data = NULL ;
2005-12-17 20:14:38 +02:00
2003-01-11 07:02:14 +02:00
if ( s - > oformat - > set_parameters ) {
ret = s - > oformat - > set_parameters ( s , ap ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2002-05-20 19:28:47 +03:00
int av_write_header ( AVFormatContext * s )
{
2002-10-21 20:40:23 +03:00
int ret , i ;
AVStream * st ;
2005-08-14 19:19:20 +03:00
// some sanity checks
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
switch ( st - > codec - > codec_type ) {
case CODEC_TYPE_AUDIO :
if ( st - > codec - > sample_rate < = 0 ) {
av_log ( s , AV_LOG_ERROR , " sample rate not set \n " ) ;
return - 1 ;
}
break ;
case CODEC_TYPE_VIDEO :
if ( st - > codec - > time_base . num < = 0 | | st - > codec - > time_base . den < = 0 ) { //FIXME audio too?
av_log ( s , AV_LOG_ERROR , " time base not set \n " ) ;
return - 1 ;
}
if ( st - > codec - > width < = 0 | | st - > codec - > height < = 0 ) {
av_log ( s , AV_LOG_ERROR , " dimensions not set \n " ) ;
return - 1 ;
}
break ;
}
2007-01-21 14:31:58 +02:00
if ( s - > oformat - > codec_tag ) {
if ( st - > codec - > codec_tag ) {
//FIXME
//check that tag + id is in the table
2008-01-17 00:14:26 +02:00
//if neither is in the table -> OK
2007-01-21 14:31:58 +02:00
//if tag is in the table with another id -> FAIL
//if id is in the table with another tag -> FAIL unless strict < ?
} else
st - > codec - > codec_tag = av_codec_get_tag ( s - > oformat - > codec_tag , st - > codec - > codec_id ) ;
}
2005-08-14 19:19:20 +03:00
}
2007-01-08 16:22:00 +02:00
if ( ! s - > priv_data & & s - > oformat - > priv_data_size > 0 ) {
2007-01-08 14:57:08 +02:00
s - > priv_data = av_mallocz ( s - > oformat - > priv_data_size ) ;
if ( ! s - > priv_data )
2007-07-19 18:21:30 +03:00
return AVERROR ( ENOMEM ) ;
2007-01-08 16:22:00 +02:00
}
2007-01-08 14:57:08 +02:00
2005-11-05 01:50:11 +02:00
if ( s - > oformat - > write_header ) {
ret = s - > oformat - > write_header ( s ) ;
if ( ret < 0 )
return ret ;
}
2002-10-21 20:40:23 +03:00
/* init PTS generation */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2005-08-14 19:37:29 +03:00
int64_t den = AV_NOPTS_VALUE ;
2002-10-21 20:40:23 +03:00
st = s - > streams [ i ] ;
2005-07-18 01:24:36 +03:00
switch ( st - > codec - > codec_type ) {
2002-10-21 20:40:23 +03:00
case CODEC_TYPE_AUDIO :
2005-08-14 19:37:29 +03:00
den = ( int64_t ) st - > time_base . num * st - > codec - > sample_rate ;
2002-10-21 20:40:23 +03:00
break ;
case CODEC_TYPE_VIDEO :
2005-08-14 19:37:29 +03:00
den = ( int64_t ) st - > time_base . num * st - > codec - > time_base . den ;
2002-10-21 20:40:23 +03:00
break ;
default :
break ;
}
2005-08-14 19:37:29 +03:00
if ( den ! = AV_NOPTS_VALUE ) {
if ( den < = 0 )
return AVERROR_INVALIDDATA ;
av_frac_init ( & st - > pts , 0 , 0 , den ) ;
}
2002-10-21 20:40:23 +03:00
}
return 0 ;
2002-05-20 19:28:47 +03:00
}
2004-05-29 21:50:31 +03:00
//FIXME merge with compute_pkt_fields
2004-12-14 18:19:26 +02:00
static int compute_pkt_fields2 ( AVStream * st , AVPacket * pkt ) {
2006-08-31 00:18:17 +03:00
int delay = FFMAX ( st - > codec - > has_b_frames , ! ! st - > codec - > max_b_frames ) ;
int num , den , frame_size , i ;
2004-04-04 21:33:07 +03:00
2006-11-02 00:39:58 +02:00
// av_log(st->codec, AV_LOG_DEBUG, "av_write_frame: pts:%"PRId64" dts:%"PRId64" cur_dts:%"PRId64" b:%d size:%d st:%d\n", pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index);
2005-12-17 20:14:38 +02:00
2004-05-29 05:06:32 +03:00
/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
return - 1 ; */
2005-12-17 20:14:38 +02:00
2004-05-29 05:06:32 +03:00
/* duration field */
2004-05-29 21:50:31 +03:00
if ( pkt - > duration = = 0 ) {
compute_frame_duration ( & num , & den , st , NULL , pkt ) ;
if ( den & & num ) {
pkt - > duration = av_rescale ( 1 , num * ( int64_t ) st - > time_base . den , den * ( int64_t ) st - > time_base . num ) ;
}
}
2004-05-29 05:06:32 +03:00
//XXX/FIXME this is a temporary hack until all encoders output pts
2006-08-31 00:18:17 +03:00
if ( ( pkt - > pts = = 0 | | pkt - > pts = = AV_NOPTS_VALUE ) & & pkt - > dts = = AV_NOPTS_VALUE & & ! delay ) {
2004-05-29 05:06:32 +03:00
pkt - > dts =
// pkt->pts= st->cur_dts;
pkt - > pts = st - > pts . val ;
}
2005-12-17 20:14:38 +02:00
//calculate dts from pts
2004-05-29 05:06:32 +03:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > dts = = AV_NOPTS_VALUE ) {
2006-08-31 00:18:17 +03:00
st - > pts_buffer [ 0 ] = pkt - > pts ;
for ( i = 1 ; i < delay + 1 & & st - > pts_buffer [ i ] = = AV_NOPTS_VALUE ; i + + )
st - > pts_buffer [ i ] = ( i - delay - 1 ) * pkt - > duration ;
for ( i = 0 ; i < delay & & st - > pts_buffer [ i ] > st - > pts_buffer [ i + 1 ] ; i + + )
2006-11-01 23:28:36 +02:00
FFSWAP ( int64_t , st - > pts_buffer [ i ] , st - > pts_buffer [ i + 1 ] ) ;
2006-08-31 00:18:17 +03:00
pkt - > dts = st - > pts_buffer [ 0 ] ;
2004-05-29 05:06:32 +03:00
}
2005-12-17 20:14:38 +02:00
2004-12-14 18:19:26 +02:00
if ( st - > cur_dts & & st - > cur_dts ! = AV_NOPTS_VALUE & & st - > cur_dts > = pkt - > dts ) {
2007-04-26 13:49:48 +03:00
av_log ( NULL , AV_LOG_ERROR , " error, non monotone timestamps % " PRId64 " >= % " PRId64 " \n " , st - > cur_dts , pkt - > dts ) ;
2004-12-14 18:19:26 +02:00
return - 1 ;
}
if ( pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > pts < pkt - > dts ) {
2007-04-26 13:49:48 +03:00
av_log ( NULL , AV_LOG_ERROR , " error, pts < dts \n " ) ;
2004-12-14 18:19:26 +02:00
return - 1 ;
}
2006-11-02 00:39:58 +02:00
// av_log(NULL, AV_LOG_DEBUG, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n", pkt->pts, pkt->dts);
2004-05-29 05:06:32 +03:00
st - > cur_dts = pkt - > dts ;
st - > pts . val = pkt - > dts ;
2002-10-21 20:40:23 +03:00
/* update pts */
2005-07-18 01:24:36 +03:00
switch ( st - > codec - > codec_type ) {
2002-10-21 20:40:23 +03:00
case CODEC_TYPE_AUDIO :
2005-07-18 01:24:36 +03:00
frame_size = get_audio_frame_size ( st - > codec , pkt - > size ) ;
2004-04-04 17:39:20 +03:00
2008-01-17 00:14:26 +02:00
/* HACK/FIXME, we skip the initial 0 size packets as they are most
likely equal to the encoder delay , but it would be better if we
had the real timestamps from the encoder */
2004-05-29 05:06:32 +03:00
if ( frame_size > = 0 & & ( pkt - > size | | st - > pts . num ! = st - > pts . den > > 1 | | st - > pts . val ) ) {
2004-05-21 23:43:21 +03:00
av_frac_add ( & st - > pts , ( int64_t ) st - > time_base . den * frame_size ) ;
2002-11-19 20:30:03 +02:00
}
2002-10-21 20:40:23 +03:00
break ;
case CODEC_TYPE_VIDEO :
2005-07-18 01:24:36 +03:00
av_frac_add ( & st - > pts , ( int64_t ) st - > time_base . den * st - > codec - > time_base . num ) ;
2002-10-21 20:40:23 +03:00
break ;
default :
break ;
}
2004-12-14 18:19:26 +02:00
return 0 ;
2004-05-29 21:50:31 +03:00
}
static void truncate_ts ( AVStream * st , AVPacket * pkt ) {
int64_t pts_mask = ( 2LL < < ( st - > pts_wrap_bits - 1 ) ) - 1 ;
2005-12-17 20:14:38 +02:00
2004-10-03 15:58:14 +03:00
// if(pkt->dts < 0)
2008-01-17 00:14:26 +02:00
// pkt->dts= 0; //this happens for low_delay=0 and B-frames, FIXME, needs further investigation about what we should do here
2005-12-17 20:14:38 +02:00
2006-12-06 19:17:33 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE )
2006-12-06 17:46:12 +02:00
pkt - > pts & = pts_mask ;
2006-12-06 19:17:33 +02:00
if ( pkt - > dts ! = AV_NOPTS_VALUE )
2006-12-06 17:46:12 +02:00
pkt - > dts & = pts_mask ;
2004-05-29 21:50:31 +03:00
}
int av_write_frame ( AVFormatContext * s , AVPacket * pkt )
{
2004-10-08 23:09:52 +03:00
int ret ;
2004-12-14 18:19:26 +02:00
ret = compute_pkt_fields2 ( s - > streams [ pkt - > stream_index ] , pkt ) ;
2006-08-08 23:31:19 +03:00
if ( ret < 0 & & ! ( s - > oformat - > flags & AVFMT_NOTIMESTAMPS ) )
2004-12-14 18:19:26 +02:00
return ret ;
2005-12-17 20:14:38 +02:00
2004-05-29 21:50:31 +03:00
truncate_ts ( s - > streams [ pkt - > stream_index ] , pkt ) ;
2004-10-08 23:09:52 +03:00
ret = s - > oformat - > write_packet ( s , pkt ) ;
if ( ! ret )
2007-11-21 09:41:00 +02:00
ret = url_ferror ( s - > pb ) ;
2004-10-08 23:09:52 +03:00
return ret ;
2004-05-29 21:50:31 +03:00
}
2006-08-12 00:21:51 +03:00
int av_interleave_packet_per_dts ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush ) {
2004-09-30 02:25:01 +03:00
AVPacketList * pktl , * * next_point , * this_pktl ;
int stream_count = 0 ;
int streams [ MAX_STREAMS ] ;
if ( pkt ) {
AVStream * st = s - > streams [ pkt - > stream_index ] ;
2005-06-29 11:48:26 +03:00
// assert(pkt->destruct != av_destruct_packet); //FIXME
2004-09-30 02:25:01 +03:00
this_pktl = av_mallocz ( sizeof ( AVPacketList ) ) ;
this_pktl - > pkt = * pkt ;
2005-06-29 11:48:26 +03:00
if ( pkt - > destruct = = av_destruct_packet )
2008-01-17 00:14:26 +02:00
pkt - > destruct = NULL ; // not shared -> must keep original from being freed
2005-06-29 11:48:26 +03:00
else
av_dup_packet ( & this_pktl - > pkt ) ; //shared -> must dup
2004-09-30 02:25:01 +03:00
next_point = & s - > packet_buffer ;
while ( * next_point ) {
AVStream * st2 = s - > streams [ ( * next_point ) - > pkt . stream_index ] ;
int64_t left = st2 - > time_base . num * ( int64_t ) st - > time_base . den ;
int64_t right = st - > time_base . num * ( int64_t ) st2 - > time_base . den ;
if ( ( * next_point ) - > pkt . dts * left > pkt - > dts * right ) //FIXME this can overflow
break ;
next_point = & ( * next_point ) - > next ;
}
this_pktl - > next = * next_point ;
* next_point = this_pktl ;
}
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
memset ( streams , 0 , sizeof ( streams ) ) ;
pktl = s - > packet_buffer ;
while ( pktl ) {
2006-11-02 00:39:58 +02:00
//av_log(s, AV_LOG_DEBUG, "show st:%d dts:%"PRId64"\n", pktl->pkt.stream_index, pktl->pkt.dts);
2004-09-30 02:25:01 +03:00
if ( streams [ pktl - > pkt . stream_index ] = = 0 )
stream_count + + ;
streams [ pktl - > pkt . stream_index ] + + ;
pktl = pktl - > next ;
}
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
if ( s - > nb_streams = = stream_count | | ( flush & & stream_count ) ) {
pktl = s - > packet_buffer ;
* out = pktl - > pkt ;
2005-12-17 20:14:38 +02:00
s - > packet_buffer = pktl - > next ;
2004-09-30 02:25:01 +03:00
av_freep ( & pktl ) ;
return 1 ;
} else {
av_init_packet ( out ) ;
return 0 ;
}
}
/**
2008-01-17 00:14:26 +02:00
* Interleaves an AVPacket correctly so it can be muxed .
2004-09-30 02:25:01 +03:00
* @ param out the interleaved packet will be output here
* @ param in the input packet
* @ param flush 1 if no further packets are available as input and all
* remaining packets should be output
2005-12-17 20:14:38 +02:00
* @ return 1 if a packet was output , 0 if no packet could be output ,
2004-09-30 02:25:01 +03:00
* < 0 if an error occured
*/
static int av_interleave_packet ( AVFormatContext * s , AVPacket * out , AVPacket * in , int flush ) {
if ( s - > oformat - > interleave_packet )
return s - > oformat - > interleave_packet ( s , out , in , flush ) ;
else
return av_interleave_packet_per_dts ( s , out , in , flush ) ;
}
2004-05-29 21:50:31 +03:00
int av_interleaved_write_frame ( AVFormatContext * s , AVPacket * pkt ) {
AVStream * st = s - > streams [ pkt - > stream_index ] ;
2004-06-23 00:14:01 +03:00
//FIXME/XXX/HACK drop zero sized packets
2005-07-18 01:24:36 +03:00
if ( st - > codec - > codec_type = = CODEC_TYPE_AUDIO & & pkt - > size = = 0 )
2004-06-23 00:14:01 +03:00
return 0 ;
2005-03-24 03:51:57 +02:00
2006-11-02 00:39:58 +02:00
//av_log(NULL, AV_LOG_DEBUG, "av_interleaved_write_frame %d %"PRId64" %"PRId64"\n", pkt->size, pkt->dts, pkt->pts);
2006-08-08 23:31:19 +03:00
if ( compute_pkt_fields2 ( st , pkt ) < 0 & & ! ( s - > oformat - > flags & AVFMT_NOTIMESTAMPS ) )
2005-03-24 03:51:57 +02:00
return - 1 ;
2005-12-17 20:14:38 +02:00
2004-05-29 21:50:31 +03:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
return - 1 ;
2004-09-30 02:25:01 +03:00
for ( ; ; ) {
AVPacket opkt ;
int ret = av_interleave_packet ( s , & opkt , pkt , 0 ) ;
if ( ret < = 0 ) //FIXME cleanup needed for ret<0 ?
return ret ;
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
truncate_ts ( s - > streams [ opkt . stream_index ] , & opkt ) ;
ret = s - > oformat - > write_packet ( s , & opkt ) ;
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
av_free_packet ( & opkt ) ;
pkt = NULL ;
2005-12-17 20:14:38 +02:00
2004-05-29 21:50:31 +03:00
if ( ret < 0 )
return ret ;
2007-11-21 09:41:00 +02:00
if ( url_ferror ( s - > pb ) )
return url_ferror ( s - > pb ) ;
2004-05-29 21:50:31 +03:00
}
2002-05-20 19:28:47 +03:00
}
int av_write_trailer ( AVFormatContext * s )
{
2004-10-01 19:30:15 +03:00
int ret , i ;
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
for ( ; ; ) {
AVPacket pkt ;
ret = av_interleave_packet ( s , & pkt , NULL , 1 ) ;
if ( ret < 0 ) //FIXME cleanup needed for ret<0 ?
2004-10-01 19:30:15 +03:00
goto fail ;
2004-09-30 02:25:01 +03:00
if ( ! ret )
break ;
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
truncate_ts ( s - > streams [ pkt . stream_index ] , & pkt ) ;
ret = s - > oformat - > write_packet ( s , & pkt ) ;
2005-12-17 20:14:38 +02:00
2004-09-30 02:25:01 +03:00
av_free_packet ( & pkt ) ;
2005-12-17 20:14:38 +02:00
2004-05-29 21:50:31 +03:00
if ( ret < 0 )
2004-10-01 19:30:15 +03:00
goto fail ;
2007-11-21 09:41:00 +02:00
if ( url_ferror ( s - > pb ) )
2004-10-08 23:09:52 +03:00
goto fail ;
2004-05-29 21:50:31 +03:00
}
2005-11-05 01:50:11 +02:00
if ( s - > oformat - > write_trailer )
ret = s - > oformat - > write_trailer ( s ) ;
2004-10-01 19:30:15 +03:00
fail :
2004-10-08 23:09:52 +03:00
if ( ret = = 0 )
2007-11-21 09:41:00 +02:00
ret = url_ferror ( s - > pb ) ;
2004-10-01 19:30:15 +03:00
for ( i = 0 ; i < s - > nb_streams ; i + + )
av_freep ( & s - > streams [ i ] - > priv_data ) ;
2002-05-20 19:28:47 +03:00
av_freep ( & s - > priv_data ) ;
return ret ;
2001-07-22 17:18:56 +03:00
}
2007-10-20 11:25:13 +03:00
void av_program_add_stream_index ( AVFormatContext * ac , int progid , unsigned int idx )
{
int i , j ;
AVProgram * program = NULL ;
void * tmp ;
for ( i = 0 ; i < ac - > nb_programs ; i + + ) {
if ( ac - > programs [ i ] - > id ! = progid )
continue ;
program = ac - > programs [ i ] ;
for ( j = 0 ; j < program - > nb_stream_indexes ; j + + )
if ( program - > stream_index [ j ] = = idx )
return ;
tmp = av_realloc ( program - > stream_index , sizeof ( unsigned int ) * ( program - > nb_stream_indexes + 1 ) ) ;
if ( ! tmp )
return ;
program - > stream_index = tmp ;
program - > stream_index [ program - > nb_stream_indexes + + ] = idx ;
return ;
}
}
2001-07-22 17:18:56 +03:00
/* "user interface" functions */
2007-10-22 02:10:15 +03:00
static void dump_stream_format ( AVFormatContext * ic , int i , int index , int is_output )
2007-10-20 11:17:01 +03:00
{
2007-10-22 02:10:15 +03:00
char buf [ 256 ] ;
2007-10-20 11:17:01 +03:00
int flags = ( is_output ? ic - > oformat - > flags : ic - > iformat - > flags ) ;
AVStream * st = ic - > streams [ i ] ;
int g = ff_gcd ( st - > time_base . num , st - > time_base . den ) ;
avcodec_string ( buf , sizeof ( buf ) , st - > codec , is_output ) ;
av_log ( NULL , AV_LOG_INFO , " Stream #%d.%d " , index , i ) ;
/* the pid is an important information, so we display it */
/* XXX: add a generic system */
if ( flags & AVFMT_SHOW_IDS )
av_log ( NULL , AV_LOG_INFO , " [0x%x] " , st - > id ) ;
if ( strlen ( st - > language ) > 0 )
av_log ( NULL , AV_LOG_INFO , " (%s) " , st - > language ) ;
av_log ( NULL , AV_LOG_DEBUG , " , %d/%d " , st - > time_base . num / g , st - > time_base . den / g ) ;
av_log ( NULL , AV_LOG_INFO , " : %s " , buf ) ;
if ( st - > codec - > codec_type = = CODEC_TYPE_VIDEO ) {
if ( st - > r_frame_rate . den & & st - > r_frame_rate . num )
2007-11-14 01:43:18 +02:00
av_log ( NULL , AV_LOG_INFO , " , %5.2f tb(r) " , av_q2d ( st - > r_frame_rate ) ) ;
2007-10-20 11:17:01 +03:00
/* else if(st->time_base.den && st->time_base.num)
2007-11-14 01:43:18 +02:00
av_log ( NULL , AV_LOG_INFO , " , %5.2f tb(m) " , 1 / av_q2d ( st - > time_base ) ) ; */
2007-10-20 11:17:01 +03:00
else
2007-11-14 01:43:18 +02:00
av_log ( NULL , AV_LOG_INFO , " , %5.2f tb(c) " , 1 / av_q2d ( st - > codec - > time_base ) ) ;
2007-10-20 11:17:01 +03:00
}
av_log ( NULL , AV_LOG_INFO , " \n " ) ;
}
2001-07-22 17:18:56 +03:00
void dump_format ( AVFormatContext * ic ,
2005-12-17 20:14:38 +02:00
int index ,
2001-07-22 17:18:56 +03:00
const char * url ,
int is_output )
{
2007-10-25 13:11:15 +03:00
int i ;
2001-07-22 17:18:56 +03:00
2005-12-17 20:14:38 +02:00
av_log ( NULL , AV_LOG_INFO , " %s #%d, %s, %s '%s': \n " ,
2001-07-22 17:18:56 +03:00
is_output ? " Output " : " Input " ,
2005-12-17 20:14:38 +02:00
index ,
is_output ? ic - > oformat - > name : ic - > iformat - > name ,
2001-07-22 17:18:56 +03:00
is_output ? " to " : " from " , url ) ;
2003-08-08 21:02:23 +03:00
if ( ! is_output ) {
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " Duration: " ) ;
2003-08-08 21:02:23 +03:00
if ( ic - > duration ! = AV_NOPTS_VALUE ) {
int hours , mins , secs , us ;
secs = ic - > duration / AV_TIME_BASE ;
us = ic - > duration % AV_TIME_BASE ;
mins = secs / 60 ;
secs % = 60 ;
hours = mins / 60 ;
mins % = 60 ;
2005-12-17 20:14:38 +02:00
av_log ( NULL , AV_LOG_INFO , " %02d:%02d:%02d.%01d " , hours , mins , secs ,
2003-08-08 21:02:23 +03:00
( 10 * us ) / AV_TIME_BASE ) ;
} else {
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " N/A " ) ;
2003-08-08 21:02:23 +03:00
}
2004-10-11 20:12:52 +03:00
if ( ic - > start_time ! = AV_NOPTS_VALUE ) {
int secs , us ;
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " , start: " ) ;
2004-10-11 20:12:52 +03:00
secs = ic - > start_time / AV_TIME_BASE ;
us = ic - > start_time % AV_TIME_BASE ;
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " %d.%06d " ,
2004-10-11 20:12:52 +03:00
secs , ( int ) av_rescale ( us , 1000000 , AV_TIME_BASE ) ) ;
}
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " , bitrate: " ) ;
2003-08-08 21:02:23 +03:00
if ( ic - > bit_rate ) {
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " %d kb/s " , ic - > bit_rate / 1000 ) ;
2003-08-08 21:02:23 +03:00
} else {
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " N/A " ) ;
2003-08-08 21:02:23 +03:00
}
2005-05-29 14:44:21 +03:00
av_log ( NULL , AV_LOG_INFO , " \n " ) ;
2003-08-08 21:02:23 +03:00
}
2007-10-20 11:25:13 +03:00
if ( ic - > nb_programs ) {
int j , k ;
for ( j = 0 ; j < ic - > nb_programs ; j + + ) {
2007-10-26 23:02:11 +03:00
av_log ( NULL , AV_LOG_INFO , " Program %d %s \n " , ic - > programs [ j ] - > id ,
ic - > programs [ j ] - > name ? ic - > programs [ j ] - > name : " " ) ;
2007-10-20 11:25:13 +03:00
for ( k = 0 ; k < ic - > programs [ j ] - > nb_stream_indexes ; k + + )
2007-10-22 02:10:15 +03:00
dump_stream_format ( ic , ic - > programs [ j ] - > stream_index [ k ] , index , is_output ) ;
2007-10-20 11:25:13 +03:00
}
} else
2007-10-20 11:17:01 +03:00
for ( i = 0 ; i < ic - > nb_streams ; i + + )
2007-10-22 02:10:15 +03:00
dump_stream_format ( ic , i , index , is_output ) ;
2001-07-22 17:18:56 +03:00
}
int parse_image_size ( int * width_ptr , int * height_ptr , const char * str )
{
2007-06-12 11:06:54 +03:00
return av_parse_video_frame_size ( width_ptr , height_ptr , str ) ;
2001-07-22 17:18:56 +03:00
}
2007-06-12 11:06:54 +03:00
int parse_frame_rate ( int * frame_rate_num , int * frame_rate_den , const char * arg )
2003-07-12 10:37:05 +03:00
{
2007-06-12 11:06:54 +03:00
AVRational frame_rate ;
int ret = av_parse_video_frame_rate ( & frame_rate , arg ) ;
* frame_rate_num = frame_rate . num ;
* frame_rate_den = frame_rate . den ;
return ret ;
2003-07-12 10:37:05 +03:00
}
2007-07-16 23:28:43 +03:00
/**
2008-01-17 00:14:26 +02:00
* Gets the current time in microseconds .
2007-07-16 23:28:43 +03:00
*/
int64_t av_gettime ( void )
{
struct timeval tv ;
gettimeofday ( & tv , NULL ) ;
return ( int64_t ) tv . tv_sec * 1000000 + tv . tv_usec ;
}
2003-02-11 18:35:48 +02:00
int64_t parse_date ( const char * datestr , int duration )
2001-07-22 17:18:56 +03:00
{
const char * p ;
2003-02-11 18:35:48 +02:00
int64_t t ;
2002-06-14 06:38:00 +03:00
struct tm dt ;
2002-07-27 05:54:10 +03:00
int i ;
static const char * date_fmt [ ] = {
" %Y-%m-%d " ,
" %Y%m%d " ,
} ;
static const char * time_fmt [ ] = {
" %H:%M:%S " ,
" %H%M%S " ,
} ;
const char * q ;
2002-10-21 18:54:49 +03:00
int is_utc , len ;
2002-07-27 05:54:10 +03:00
char lastch ;
2004-06-12 01:03:16 +03:00
int negative = 0 ;
2004-04-04 17:39:20 +03:00
# undef time
2002-07-27 05:54:10 +03:00
time_t now = time ( 0 ) ;
2002-10-21 18:54:49 +03:00
len = strlen ( datestr ) ;
if ( len > 0 )
lastch = datestr [ len - 1 ] ;
else
lastch = ' \0 ' ;
2002-07-27 05:54:10 +03:00
is_utc = ( lastch = = ' z ' | | lastch = = ' Z ' ) ;
2002-06-14 06:38:00 +03:00
memset ( & dt , 0 , sizeof ( dt ) ) ;
2001-07-22 17:18:56 +03:00
p = datestr ;
2002-10-21 18:54:49 +03:00
q = NULL ;
2001-07-22 17:18:56 +03:00
if ( ! duration ) {
2007-09-18 11:26:10 +03:00
/* parse the year-month-day part */
2002-07-27 05:54:10 +03:00
for ( i = 0 ; i < sizeof ( date_fmt ) / sizeof ( date_fmt [ 0 ] ) ; i + + ) {
2003-09-09 00:20:55 +03:00
q = small_strptime ( p , date_fmt [ i ] , & dt ) ;
2002-07-27 05:54:10 +03:00
if ( q ) {
break ;
}
}
2007-09-18 11:26:10 +03:00
/* if the year-month-day part is missing, then take the
* current year - month - day time */
2002-07-27 05:54:10 +03:00
if ( ! q ) {
if ( is_utc ) {
dt = * gmtime ( & now ) ;
} else {
dt = * localtime ( & now ) ;
}
dt . tm_hour = dt . tm_min = dt . tm_sec = 0 ;
2001-07-22 17:18:56 +03:00
} else {
2002-07-27 05:54:10 +03:00
p = q ;
2001-07-22 17:18:56 +03:00
}
2002-07-27 05:54:10 +03:00
if ( * p = = ' T ' | | * p = = ' t ' | | * p = = ' ' )
p + + ;
2007-09-18 11:26:10 +03:00
/* parse the hour-minute-second part */
2002-10-21 18:54:49 +03:00
for ( i = 0 ; i < sizeof ( time_fmt ) / sizeof ( time_fmt [ 0 ] ) ; i + + ) {
2003-09-09 00:20:55 +03:00
q = small_strptime ( p , time_fmt [ i ] , & dt ) ;
2002-10-21 18:54:49 +03:00
if ( q ) {
break ;
}
}
} else {
2007-09-18 11:26:10 +03:00
/* parse datestr as a duration */
2005-12-22 03:10:11 +02:00
if ( p [ 0 ] = = ' - ' ) {
negative = 1 ;
+ + p ;
}
2007-09-18 11:26:10 +03:00
/* parse datestr as HH:MM:SS */
2003-09-09 00:20:55 +03:00
q = small_strptime ( p , time_fmt [ 0 ] , & dt ) ;
2002-10-21 18:54:49 +03:00
if ( ! q ) {
2007-09-18 11:26:10 +03:00
/* parse datestr as S+ */
2002-10-21 18:54:49 +03:00
dt . tm_sec = strtol ( p , ( char * * ) & q , 10 ) ;
2007-09-19 15:38:07 +03:00
if ( q = = p )
/* the parsing didn't succeed */
return INT64_MIN ;
2002-10-21 18:54:49 +03:00
dt . tm_min = 0 ;
dt . tm_hour = 0 ;
2002-07-27 05:54:10 +03:00
}
}
/* Now we have all the fields that we can get */
if ( ! q ) {
2007-09-19 15:38:07 +03:00
return INT64_MIN ;
2001-07-22 17:18:56 +03:00
}
2002-06-14 06:38:00 +03:00
if ( duration ) {
2002-07-27 05:54:10 +03:00
t = dt . tm_hour * 3600 + dt . tm_min * 60 + dt . tm_sec ;
2002-06-14 06:38:00 +03:00
} else {
2002-07-27 05:54:10 +03:00
dt . tm_isdst = - 1 ; /* unknown */
if ( is_utc ) {
t = mktimegm ( & dt ) ;
} else {
t = mktime ( & dt ) ;
}
2001-07-22 17:18:56 +03:00
}
2002-06-14 06:38:00 +03:00
2002-07-27 05:54:10 +03:00
t * = 1000000 ;
2007-09-18 11:26:10 +03:00
/* parse the .m... part */
2002-07-27 05:54:10 +03:00
if ( * q = = ' . ' ) {
2001-07-22 17:18:56 +03:00
int val , n ;
2002-07-27 05:54:10 +03:00
q + + ;
for ( val = 0 , n = 100000 ; n > = 1 ; n / = 10 , q + + ) {
2005-12-17 20:14:38 +02:00
if ( ! isdigit ( * q ) )
2002-07-27 05:54:10 +03:00
break ;
val + = n * ( * q - ' 0 ' ) ;
2001-07-22 17:18:56 +03:00
}
t + = val ;
}
2004-06-12 01:03:16 +03:00
return negative ? - t : t ;
2001-07-22 17:18:56 +03:00
}
int find_info_tag ( char * arg , int arg_size , const char * tag1 , const char * info )
{
const char * p ;
char tag [ 128 ] , * q ;
p = info ;
if ( * p = = ' ? ' )
p + + ;
for ( ; ; ) {
q = tag ;
while ( * p ! = ' \0 ' & & * p ! = ' = ' & & * p ! = ' & ' ) {
if ( ( q - tag ) < sizeof ( tag ) - 1 )
* q + + = * p ;
p + + ;
}
* q = ' \0 ' ;
q = arg ;
if ( * p = = ' = ' ) {
p + + ;
while ( * p ! = ' & ' & & * p ! = ' \0 ' ) {
2002-06-14 06:38:00 +03:00
if ( ( q - arg ) < arg_size - 1 ) {
if ( * p = = ' + ' )
* q + + = ' ' ;
else
* q + + = * p ;
}
2001-07-22 17:18:56 +03:00
p + + ;
}
* q = ' \0 ' ;
}
2005-12-17 20:14:38 +02:00
if ( ! strcmp ( tag , tag1 ) )
2001-07-22 17:18:56 +03:00
return 1 ;
if ( * p ! = ' & ' )
break ;
2002-05-10 05:17:41 +03:00
p + + ;
2001-07-22 17:18:56 +03:00
}
return 0 ;
}
2006-09-04 12:57:47 +03:00
int av_get_frame_filename ( char * buf , int buf_size ,
const char * path , int number )
2001-09-17 00:50:48 +03:00
{
const char * p ;
2003-10-26 12:49:49 +02:00
char * q , buf1 [ 20 ] , c ;
int nd , len , percentd_found ;
2001-09-17 00:50:48 +03:00
q = buf ;
p = path ;
percentd_found = 0 ;
for ( ; ; ) {
c = * p + + ;
if ( c = = ' \0 ' )
break ;
if ( c = = ' % ' ) {
2002-12-11 05:20:05 +02:00
do {
nd = 0 ;
while ( isdigit ( * p ) ) {
nd = nd * 10 + * p + + - ' 0 ' ;
}
c = * p + + ;
} while ( isdigit ( c ) ) ;
2001-09-17 00:50:48 +03:00
switch ( c ) {
case ' % ' :
goto addchar ;
case ' d ' :
if ( percentd_found )
goto fail ;
percentd_found = 1 ;
snprintf ( buf1 , sizeof ( buf1 ) , " %0*d " , nd , number ) ;
len = strlen ( buf1 ) ;
if ( ( q - buf + len ) > buf_size - 1 )
goto fail ;
memcpy ( q , buf1 , len ) ;
q + = len ;
break ;
default :
goto fail ;
}
} else {
addchar :
if ( ( q - buf ) < buf_size - 1 )
* q + + = c ;
}
}
if ( ! percentd_found )
goto fail ;
* q = ' \0 ' ;
return 0 ;
fail :
* q = ' \0 ' ;
return - 1 ;
}
2007-03-12 16:17:26 +02:00
static void hex_dump_internal ( void * avcl , FILE * f , int level , uint8_t * buf , int size )
2002-05-20 19:28:47 +03:00
{
int len , i , j , c ;
2007-03-12 16:17:26 +02:00
# define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0)
2002-05-20 19:28:47 +03:00
for ( i = 0 ; i < size ; i + = 16 ) {
len = size - i ;
if ( len > 16 )
len = 16 ;
2007-03-12 16:17:26 +02:00
PRINT ( " %08x " , i ) ;
2002-05-20 19:28:47 +03:00
for ( j = 0 ; j < 16 ; j + + ) {
if ( j < len )
2007-03-12 16:17:26 +02:00
PRINT ( " %02x " , buf [ i + j ] ) ;
2002-05-20 19:28:47 +03:00
else
2007-03-12 16:17:26 +02:00
PRINT ( " " ) ;
2002-05-20 19:28:47 +03:00
}
2007-03-12 16:17:26 +02:00
PRINT ( " " ) ;
2002-05-20 19:28:47 +03:00
for ( j = 0 ; j < len ; j + + ) {
c = buf [ i + j ] ;
if ( c < ' ' | | c > ' ~ ' )
c = ' . ' ;
2007-03-12 16:17:26 +02:00
PRINT ( " %c " , c ) ;
2002-05-20 19:28:47 +03:00
}
2007-03-12 16:17:26 +02:00
PRINT ( " \n " ) ;
2002-05-20 19:28:47 +03:00
}
2007-03-12 16:17:26 +02:00
# undef PRINT
}
void av_hex_dump ( FILE * f , uint8_t * buf , int size )
{
hex_dump_internal ( NULL , f , 0 , buf , size ) ;
}
void av_hex_dump_log ( void * avcl , int level , uint8_t * buf , int size )
{
hex_dump_internal ( avcl , NULL , level , buf , size ) ;
2002-05-20 19:28:47 +03:00
}
2005-05-01 00:43:59 +03:00
//FIXME needs to know the time_base
2007-03-12 16:17:26 +02:00
static void pkt_dump_internal ( void * avcl , FILE * f , int level , AVPacket * pkt , int dump_payload )
2003-11-10 20:37:55 +02:00
{
2007-03-12 16:17:26 +02:00
# define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0)
PRINT ( " stream #%d: \n " , pkt - > stream_index ) ;
PRINT ( " keyframe=%d \n " , ( ( pkt - > flags & PKT_FLAG_KEY ) ! = 0 ) ) ;
PRINT ( " duration=%0.3f \n " , ( double ) pkt - > duration / AV_TIME_BASE ) ;
2003-12-15 16:45:37 +02:00
/* DTS is _always_ valid after av_read_frame() */
2007-03-12 16:17:26 +02:00
PRINT ( " dts= " ) ;
2003-12-15 16:45:37 +02:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
2007-03-12 16:17:26 +02:00
PRINT ( " N/A " ) ;
2003-12-15 16:45:37 +02:00
else
2007-03-12 16:17:26 +02:00
PRINT ( " %0.3f " , ( double ) pkt - > dts / AV_TIME_BASE ) ;
2008-01-17 00:14:26 +02:00
/* PTS may not be known if B-frames are present. */
2007-03-12 16:17:26 +02:00
PRINT ( " pts= " ) ;
2003-11-10 20:37:55 +02:00
if ( pkt - > pts = = AV_NOPTS_VALUE )
2007-03-12 16:17:26 +02:00
PRINT ( " N/A " ) ;
2003-11-10 20:37:55 +02:00
else
2007-03-12 16:17:26 +02:00
PRINT ( " %0.3f " , ( double ) pkt - > pts / AV_TIME_BASE ) ;
PRINT ( " \n " ) ;
PRINT ( " size=%d \n " , pkt - > size ) ;
# undef PRINT
2003-11-10 20:37:55 +02:00
if ( dump_payload )
av_hex_dump ( f , pkt - > data , pkt - > size ) ;
}
2007-03-12 16:17:26 +02:00
void av_pkt_dump ( FILE * f , AVPacket * pkt , int dump_payload )
{
pkt_dump_internal ( NULL , f , 0 , pkt , dump_payload ) ;
}
void av_pkt_dump_log ( void * avcl , int level , AVPacket * pkt , int dump_payload )
{
pkt_dump_internal ( avcl , NULL , level , pkt , dump_payload ) ;
}
2002-07-24 21:04:50 +03:00
void url_split ( char * proto , int proto_size ,
2004-08-12 03:09:32 +03:00
char * authorization , int authorization_size ,
2002-07-24 21:04:50 +03:00
char * hostname , int hostname_size ,
int * port_ptr ,
char * path , int path_size ,
const char * url )
{
2007-12-29 18:13:03 +02:00
const char * p , * ls , * at , * col , * brk ;
2007-09-27 22:18:07 +03:00
if ( port_ptr ) * port_ptr = - 1 ;
if ( proto_size > 0 ) proto [ 0 ] = 0 ;
if ( authorization_size > 0 ) authorization [ 0 ] = 0 ;
if ( hostname_size > 0 ) hostname [ 0 ] = 0 ;
if ( path_size > 0 ) path [ 0 ] = 0 ;
/* parse protocol */
if ( ( p = strchr ( url , ' : ' ) ) ) {
av_strlcpy ( proto , url , FFMIN ( proto_size , p + 1 - url ) ) ;
p + + ; /* skip ':' */
if ( * p = = ' / ' ) p + + ;
if ( * p = = ' / ' ) p + + ;
2002-07-24 21:04:50 +03:00
} else {
2007-09-27 22:18:07 +03:00
/* no protocol means plain filename */
av_strlcpy ( path , url , path_size ) ;
return ;
}
2004-08-12 03:09:32 +03:00
2007-09-27 22:18:07 +03:00
/* separate path from hostname */
2007-12-29 18:13:03 +02:00
ls = strchr ( p , ' / ' ) ;
if ( ! ls )
ls = strchr ( p , ' ? ' ) ;
if ( ls )
2007-12-29 18:34:51 +02:00
av_strlcpy ( path , ls , path_size ) ;
2007-12-29 18:13:03 +02:00
else
2007-09-27 22:18:07 +03:00
ls = & p [ strlen ( p ) ] ; // XXX
/* the rest is hostname, use that to parse auth/port */
if ( ls ! = p ) {
/* authorization (user[:pass]@hostname) */
if ( ( at = strchr ( p , ' @ ' ) ) & & at < ls ) {
av_strlcpy ( authorization , p ,
FFMIN ( authorization_size , at + 1 - p ) ) ;
p = at + 1 ; /* skip '@' */
2002-07-24 21:04:50 +03:00
}
2007-09-27 22:18:07 +03:00
2007-09-29 17:35:52 +03:00
if ( * p = = ' [ ' & & ( brk = strchr ( p , ' ] ' ) ) & & brk < ls ) {
/* [host]:port */
av_strlcpy ( hostname , p + 1 ,
FFMIN ( hostname_size , brk - p ) ) ;
if ( brk [ 1 ] = = ' : ' & & port_ptr )
* port_ptr = atoi ( brk + 2 ) ;
} else if ( ( col = strchr ( p , ' : ' ) ) & & col < ls ) {
av_strlcpy ( hostname , p ,
FFMIN ( col + 1 - p , hostname_size ) ) ;
if ( port_ptr ) * port_ptr = atoi ( col + 1 ) ;
} else
av_strlcpy ( hostname , p ,
FFMIN ( ls + 1 - p , hostname_size ) ) ;
2002-07-24 21:04:50 +03:00
}
}
2004-05-21 23:43:21 +03:00
void av_set_pts_info ( AVStream * s , int pts_wrap_bits ,
2002-10-21 18:54:49 +03:00
int pts_num , int pts_den )
{
s - > pts_wrap_bits = pts_wrap_bits ;
2004-05-21 23:43:21 +03:00
s - > time_base . num = pts_num ;
s - > time_base . den = pts_den ;
2002-10-21 18:54:49 +03:00
}
/* fraction handling */
/**
2005-06-28 15:55:08 +03:00
* f = val + ( num / den ) + 0.5 .
*
* ' num ' is normalized so that it is such as 0 < = num < den .
2002-10-21 18:54:49 +03:00
*
* @ param f fractional number
* @ param val integer value
* @ param num must be > = 0
2005-12-17 20:14:38 +02:00
* @ param den must be > = 1
2002-10-21 18:54:49 +03:00
*/
2006-06-25 20:37:12 +03:00
static void av_frac_init ( AVFrac * f , int64_t val , int64_t num , int64_t den )
2002-10-21 18:54:49 +03:00
{
num + = ( den > > 1 ) ;
if ( num > = den ) {
val + = num / den ;
num = num % den ;
}
f - > val = val ;
f - > num = num ;
f - > den = den ;
}
/**
2008-01-17 00:14:26 +02:00
* Fractional addition to f : f = f + ( incr / f - > den ) .
2002-10-21 18:54:49 +03:00
*
* @ param f fractional number
* @ param incr increment , can be positive or negative
*/
2006-06-25 20:37:12 +03:00
static void av_frac_add ( AVFrac * f , int64_t incr )
2002-10-21 18:54:49 +03:00
{
2003-02-11 18:35:48 +02:00
int64_t num , den ;
2002-10-21 18:54:49 +03:00
num = f - > num + incr ;
den = f - > den ;
if ( num < 0 ) {
f - > val + = num / den ;
num = num % den ;
if ( num < 0 ) {
num + = den ;
f - > val - - ;
}
} else if ( num > = den ) {
f - > val + = num / den ;
num = num % den ;
}
f - > num = num ;
}