2001-07-22 14:18:56 +00:00
/*
2008-01-16 22:14:26 +00:00
* various utility functions for use within FFmpeg
2002-05-25 22:34:32 +00:00
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
2001-07-22 14:18:56 +00:00
*
2006-10-07 15:30:46 +00:00
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
2002-05-25 22:34:32 +00:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
2006-10-07 15:30:46 +00:00
* version 2.1 of the License, or (at your option) any later version.
2001-07-22 14:18:56 +00:00
*
2006-10-07 15:30:46 +00:00
* FFmpeg is distributed in the hope that it will be useful,
2001-07-22 14:18:56 +00:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2002-05-25 22:34:32 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2001-07-22 14:18:56 +00:00
*
2002-05-25 22:34:32 +00:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 15:30:46 +00:00
* License along with FFmpeg; if not, write to the Free Software
2006-01-12 22:43:26 +00:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2001-07-22 14:18:56 +00:00
*/
2001-08-13 21:37:10 +00:00
#include "avformat.h"
2006-08-27 12:14:13 +00:00
#include "opt.h"
2007-06-23 23:10:32 +00:00
#include "avstring.h"
2007-07-11 12:45:14 +00:00
#include "riff.h"
2007-07-16 20:28:43 +00:00
#include <sys/time.h>
#include <time.h>
2002-07-27 02:54:10 +00:00
2004-01-13 22:02:49 +00:00
#undef NDEBUG
#include <assert.h>
2005-06-28 12:55:08 +00:00
/**
* @file libavformat/utils.c
2008-01-16 22:14:26 +00:00
* various utility functions for use within FFmpeg
2005-06-28 12:55:08 +00:00
*/
2006-06-25 17:37:12 +00: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-16 22:14:26 +00:00
/** head of registered input format linked list */
2004-08-13 15:30:42 +00:00
AVInputFormat * first_iformat = NULL ;
2008-01-16 22:14:26 +00:00
/** head of registered output format linked list */
2004-08-13 15:30:42 +00:00
AVOutputFormat * first_oformat = NULL ;
2001-07-22 14:18:56 +00:00
2007-12-12 19:01:58 +00: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 16:28:47 +00:00
void av_register_input_format ( AVInputFormat * format )
2001-07-22 14:18:56 +00:00
{
2002-05-20 16:28:47 +00: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 14:18:56 +00:00
while ( * p != NULL ) p = & ( * p ) -> next ;
* p = format ;
format -> next = NULL ;
}
2002-11-18 17:17:27 +00:00
int match_ext ( const char * filename , const char * extensions )
2001-07-22 14:18:56 +00:00
{
const char * ext , * p ;
char ext1 [ 32 ], * q ;
2004-04-27 02:55:05 +00:00
if ( ! filename )
return 0 ;
2005-12-17 18:14:38 +00:00
2001-07-22 14:18:56 +00:00
ext = strrchr ( filename , '.' );
if ( ext ) {
ext ++ ;
p = extensions ;
for (;;) {
q = ext1 ;
2005-12-17 18:14:38 +00:00
while ( * p != '\0' && * p != ',' && q - ext1 < sizeof ( ext1 ) - 1 )
2001-07-22 14:18:56 +00:00
* q ++ = * p ++ ;
* q = '\0' ;
2005-12-17 18:14:38 +00:00
if ( ! strcasecmp ( ext1 , ext ))
2001-07-22 14:18:56 +00:00
return 1 ;
2005-12-17 18:14:38 +00:00
if ( * p == '\0' )
2001-07-22 14:18:56 +00:00
break ;
p ++ ;
}
}
return 0 ;
}
2005-12-17 18:14:38 +00:00
AVOutputFormat * guess_format ( const char * short_name , const char * filename ,
2002-05-20 16:28:47 +00:00
const char * mime_type )
2001-07-22 14:18:56 +00:00
{
2002-05-20 16:28:47 +00:00
AVOutputFormat * fmt , * fmt_found ;
2001-07-22 14:18:56 +00:00
int score_max , score ;
2003-01-11 05:02:14 +00:00
/* specific test for image sequences */
2006-07-10 21:14:37 +00:00
#ifdef CONFIG_IMAGE2_MUXER
2005-12-17 18:14:38 +00:00
if ( ! short_name && filename &&
2006-09-04 09:57:47 +00:00
av_filename_number_test ( filename ) &&
2004-11-11 18:09:28 +00:00
av_guess_image2_codec ( filename ) != CODEC_ID_NONE ) {
return guess_format ( "image2" , NULL , NULL );
}
2006-07-10 21:14:37 +00:00
#endif
2008-01-16 22:14:26 +00:00
/* Find the proper file type. */
2001-07-22 14:18:56 +00:00
fmt_found = NULL ;
score_max = 0 ;
2002-05-20 16:28:47 +00:00
fmt = first_oformat ;
2001-07-22 14:18:56 +00: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 18:14:38 +00:00
if ( filename && fmt -> extensions &&
2001-07-22 14:18:56 +00: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 18:14:38 +00:00
}
2001-07-22 14:18:56 +00:00
2005-12-17 18:14:38 +00:00
AVOutputFormat * guess_stream_format ( const char * short_name , const char * filename ,
2002-07-27 02:54:10 +00: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 18:14:38 +00:00
enum CodecID av_guess_codec ( AVOutputFormat * fmt , const char * short_name ,
2004-11-11 18:09:28 +00: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-10 21:14:37 +00:00
#ifdef CONFIG_IMAGE2_MUXER
2004-11-12 22:51:52 +00:00
if ( ! strcmp ( fmt -> name , "image2" ) || ! strcmp ( fmt -> name , "image2pipe" )){
2004-11-11 18:09:28 +00:00
codec_id = av_guess_image2_codec ( filename );
}
2006-07-10 21:14:37 +00:00
#endif
2004-11-11 18:09:28 +00: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 16:28:47 +00: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 14:18:56 +00:00
/* memory handling */
2005-06-27 00:04:03 +00:00
void av_destruct_packet ( AVPacket * pkt )
2003-02-03 22:58:29 +00:00
{
av_free ( pkt -> data );
pkt -> data = NULL ; pkt -> size = 0 ;
}
2007-06-04 16:52:02 +00: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 14:18:56 +00:00
int av_new_packet ( AVPacket * pkt , int size )
{
2006-10-30 23:59:52 +00:00
uint8_t * data ;
2005-01-08 14:21:33 +00:00
if (( unsigned ) size > ( unsigned ) size + FF_INPUT_BUFFER_PADDING_SIZE )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2005-01-08 14:21:33 +00:00
data = av_malloc ( size + FF_INPUT_BUFFER_PADDING_SIZE );
2003-02-03 22:58:29 +00:00
if ( ! data )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2003-02-03 22:58:29 +00:00
memset ( data + size , 0 , FF_INPUT_BUFFER_PADDING_SIZE );
2002-11-09 15:53:52 +00:00
2003-02-03 22:58:29 +00:00
av_init_packet ( pkt );
2005-12-17 18:14:38 +00:00
pkt -> data = data ;
2003-02-03 22:58:29 +00:00
pkt -> size = size ;
pkt -> destruct = av_destruct_packet ;
2001-07-22 14:18:56 +00:00
return 0 ;
}
2005-05-26 20:17:12 +00: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 18:37:55 +00:00
int av_dup_packet ( AVPacket * pkt )
{
if ( pkt -> destruct != av_destruct_packet ) {
uint8_t * data ;
2008-01-16 22:14:26 +00:00
/* We duplicate the packet and don't forget to add the padding again. */
2005-01-08 14:21:33 +00:00
if (( unsigned ) pkt -> size > ( unsigned ) pkt -> size + FF_INPUT_BUFFER_PADDING_SIZE )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2003-12-09 15:34:44 +00:00
data = av_malloc ( pkt -> size + FF_INPUT_BUFFER_PADDING_SIZE );
2003-11-10 18:37:55 +00:00
if ( ! data ) {
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2003-11-10 18:37:55 +00:00
}
memcpy ( data , pkt -> data , pkt -> size );
2003-12-09 15:34:44 +00:00
memset ( data + pkt -> size , 0 , FF_INPUT_BUFFER_PADDING_SIZE );
2003-11-10 18:37:55 +00:00
pkt -> data = data ;
pkt -> destruct = av_destruct_packet ;
}
return 0 ;
}
2006-09-04 09:57:47 +00:00
int av_filename_number_test ( const char * filename )
2002-05-20 16:28:47 +00:00
{
char buf [ 1024 ];
2006-09-04 09:57:47 +00:00
return filename && ( av_get_frame_filename ( buf , sizeof ( buf ), filename , 1 ) >= 0 );
2002-05-20 16:28:47 +00:00
}
2007-03-27 19:28:40 +00:00
static AVInputFormat * av_probe_input_format2 ( AVProbeData * pd , int is_opened , int * score_max )
2002-05-20 16:28:47 +00:00
{
AVInputFormat * fmt1 , * fmt ;
2007-03-27 19:28:40 +00:00
int score ;
2002-05-20 16:28:47 +00:00
fmt = NULL ;
for ( fmt1 = first_iformat ; fmt1 != NULL ; fmt1 = fmt1 -> next ) {
2007-01-19 22:52:59 +00:00
if ( ! is_opened == ! ( fmt1 -> flags & AVFMT_NOFILE ))
2002-05-20 16:28:47 +00:00
continue ;
score = 0 ;
2002-05-24 02:09:40 +00:00
if ( fmt1 -> read_probe ) {
score = fmt1 -> read_probe ( pd );
} else if ( fmt1 -> extensions ) {
2002-05-20 16:28:47 +00:00
if ( match_ext ( pd -> filename , fmt1 -> extensions )) {
score = 50 ;
}
2005-12-17 18:14:38 +00:00
}
2007-03-27 19:28:40 +00:00
if ( score > * score_max ) {
* score_max = score ;
2002-05-20 16:28:47 +00:00
fmt = fmt1 ;
2008-04-15 13:50:02 +00:00
} else if ( score == * score_max )
fmt = NULL ;
2002-05-20 16:28:47 +00:00
}
return fmt ;
}
2007-03-27 19:28:40 +00: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 16:28:47 +00:00
/************************************************************/
/* input media file */
2003-10-29 14:20:56 +00:00
/**
2005-06-28 12:55:08 +00:00
* Open a media file from an IO stream. 'fmt' must be specified.
2003-10-29 14:20:56 +00:00
*/
2004-03-03 17:53:55 +00:00
static const char * format_to_name ( void * ptr )
2004-03-03 15:41:21 +00:00
{
2004-03-03 17:53:55 +00:00
AVFormatContext * fc = ( AVFormatContext * ) ptr ;
2004-03-03 15:41:21 +00:00
if ( fc -> iformat ) return fc -> iformat -> name ;
else if ( fc -> oformat ) return fc -> oformat -> name ;
else return "NULL" ;
}
2006-09-14 13:51:54 +00:00
#define OFFSET(x) offsetof(AVFormatContext,x)
2007-06-12 09:29:25 +00: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 12:14:13 +00: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-10 21:51:08 +00: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 08:23:01 +00:00
{ "muxrate" , "set mux rate" , OFFSET ( mux_rate ), FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E },
2006-09-20 08:24:17 +00:00
{ "packetsize" , "set packet size" , OFFSET ( packet_size ), FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E },
2006-10-27 10:53:08 +00:00
{ "fflags" , NULL , OFFSET ( flags ), FF_OPT_TYPE_FLAGS , DEFAULT , INT_MIN , INT_MAX , D | E , "fflags" },
2006-09-05 19:23:32 +00: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-10 21:51:08 +00:00
{ "track" , " set the track number" , OFFSET ( track ), FF_OPT_TYPE_INT , DEFAULT , 0 , INT_MAX , E },
2006-09-08 12:28:28 +00:00
{ "year" , "set the year" , OFFSET ( year ), FF_OPT_TYPE_INT , DEFAULT , INT_MIN , INT_MAX , E },
2007-04-06 09:43:32 +00: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 17:41:24 +00:00
{ "cryptokey" , "decryption key" , OFFSET ( key ), FF_OPT_TYPE_BINARY , 0 , 0 , 0 , D },
2008-02-24 16:28:35 +00:00
{ "indexmem" , "max memory used for timestamp index (per stream)" , OFFSET ( max_index_size ), FF_OPT_TYPE_INT , 1 << 20 , 0 , INT_MAX , D },
2008-03-08 21:59:11 +00:00
{ "rtbufsize" , "max memory used for buffering real-time frames" , OFFSET ( max_picture_buffer ), FF_OPT_TYPE_INT , 3041280 , 0 , INT_MAX , D }, /* defaults to 1s of 15fps 352x288 YUYV422 video */
2006-08-27 12:14:13 +00:00
{ NULL },
};
2006-09-09 08:49:28 +00:00
#undef E
#undef D
#undef DEFAULT
2006-08-27 12:14:13 +00:00
static const AVClass av_format_context_class = { "AVFormatContext" , format_to_name , options };
2007-01-08 14:42:01 +00:00
static void avformat_get_context_defaults ( AVFormatContext * s )
{
2006-08-27 12:14:13 +00:00
memset ( s , 0 , sizeof ( AVFormatContext ));
2006-08-27 12:21:19 +00:00
2006-09-10 20:21:40 +00:00
s -> av_class = & av_format_context_class ;
av_opt_set_defaults ( s );
2006-08-27 12:14:13 +00:00
}
2004-03-03 15:41:21 +00:00
AVFormatContext * av_alloc_format_context ( void )
{
AVFormatContext * ic ;
2006-09-14 12:04:07 +00:00
ic = av_malloc ( sizeof ( AVFormatContext ));
2004-03-03 15:41:21 +00:00
if ( ! ic ) return ic ;
2006-08-27 12:14:13 +00:00
avformat_get_context_defaults ( ic );
2004-03-03 17:53:55 +00:00
ic -> av_class = & av_format_context_class ;
2004-03-03 15:41:21 +00:00
return ic ;
}
2005-12-17 18:14:38 +00:00
int av_open_input_stream ( AVFormatContext ** ic_ptr ,
ByteIOContext * pb , const char * filename ,
2003-10-29 14:20:56 +00:00
AVInputFormat * fmt , AVFormatParameters * ap )
{
int err ;
AVFormatContext * ic ;
2006-03-11 00:22:21 +00:00
AVFormatParameters default_ap ;
if ( ! ap ){
ap =& default_ap ;
memset ( ap , 0 , sizeof ( default_ap ));
}
2003-10-29 14:20:56 +00:00
2006-08-27 12:14:13 +00:00
if ( ! ap -> prealloced_context )
ic = av_alloc_format_context ();
else
ic = * ic_ptr ;
2003-10-29 14:20:56 +00:00
if ( ! ic ) {
2007-07-19 15:21:30 +00:00
err = AVERROR ( ENOMEM );
2003-10-29 14:20:56 +00:00
goto fail ;
}
ic -> iformat = fmt ;
2007-11-21 07:41:00 +00:00
ic -> pb = pb ;
2003-10-29 14:20:56 +00:00
ic -> duration = AV_NOPTS_VALUE ;
ic -> start_time = AV_NOPTS_VALUE ;
2007-06-23 23:10:32 +00:00
av_strlcpy ( ic -> filename , filename , sizeof ( ic -> filename ));
2003-10-29 14:20:56 +00: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 15:21:30 +00:00
err = AVERROR ( ENOMEM );
2003-10-29 14:20:56 +00:00
goto fail ;
}
} else {
ic -> priv_data = NULL ;
}
err = ic -> iformat -> read_header ( ic , ap );
if ( err < 0 )
goto fail ;
2003-11-10 18:37:55 +00:00
2006-11-11 19:37:21 +00:00
if ( pb && ! ic -> data_offset )
2007-11-21 07:41:00 +00:00
ic -> data_offset = url_ftell ( ic -> pb );
2003-11-10 18:37:55 +00:00
2003-10-29 14:20:56 +00:00
* ic_ptr = ic ;
return 0 ;
fail :
if ( ic ) {
av_freep ( & ic -> priv_data );
}
av_free ( ic );
* ic_ptr = NULL ;
return err ;
}
2008-01-16 22:14:26 +00:00
/** size of probe buffer, for guessing file type from file contents */
2006-02-02 11:27:35 +00:00
#define PROBE_BUF_MIN 2048
2006-06-13 11:10:55 +00:00
#define PROBE_BUF_MAX (1<<20)
2002-05-20 16:28:47 +00:00
2005-12-17 18:14:38 +00:00
int av_open_input_file ( AVFormatContext ** ic_ptr , const char * filename ,
2002-05-20 16:28:47 +00:00
AVInputFormat * fmt ,
int buf_size ,
AVFormatParameters * ap )
2001-07-22 14:18:56 +00:00
{
2007-12-17 19:08:17 +00:00
int err , probe_size ;
2002-05-20 16:28:47 +00:00
AVProbeData probe_data , * pd = & probe_data ;
2007-12-17 19:08:17 +00:00
ByteIOContext * pb = NULL ;
2005-12-17 18:14:38 +00:00
2003-10-29 14:20:56 +00:00
pd -> filename = "" ;
if ( filename )
pd -> filename = filename ;
2006-02-02 11:27:35 +00:00
pd -> buf = NULL ;
2002-05-20 16:28:47 +00:00
pd -> buf_size = 0 ;
2001-07-22 14:18:56 +00:00
2002-05-20 16:28:47 +00:00
if ( ! fmt ) {
2008-01-16 22:14:26 +00:00
/* guess format if no file can be opened */
2002-07-25 16:05:52 +00:00
fmt = av_probe_input_format ( pd , 0 );
2001-07-22 14:18:56 +00:00
}
2008-01-16 22:14:26 +00:00
/* Do not open file if the format does not need it. XXX: specific
2003-07-15 16:57:35 +00:00
hack needed to handle RTSP/TCP */
2007-12-17 19:08:17 +00:00
if ( ! fmt || ! ( fmt -> flags & AVFMT_NOFILE )) {
2003-01-11 05:02:14 +00:00
/* if no file needed do not try to open one */
2007-11-21 07:41:00 +00:00
if (( err = url_fopen ( & pb , filename , URL_RDONLY )) < 0 ) {
2001-09-24 23:25:28 +00:00
goto fail ;
2002-05-20 16:28:47 +00:00
}
2001-09-24 23:25:28 +00:00
if ( buf_size > 0 ) {
2003-10-29 14:20:56 +00:00
url_setbufsize ( pb , buf_size );
2001-09-24 23:25:28 +00:00
}
2006-02-02 11:27:35 +00:00
for ( probe_size = PROBE_BUF_MIN ; probe_size <= PROBE_BUF_MAX && ! fmt ; probe_size <<= 1 ){
2007-03-27 19:28:40 +00:00
int score = probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX / 4 : 0 ;
2002-11-18 17:17:27 +00:00
/* read probe data */
2007-04-08 11:34:15 +00:00
pd -> buf = av_realloc ( pd -> buf , probe_size + AVPROBE_PADDING_SIZE );
2006-02-02 11:27:35 +00:00
pd -> buf_size = get_buffer ( pb , pd -> buf , probe_size );
2007-09-03 05:19:59 +00:00
memset ( pd -> buf + pd -> buf_size , 0 , AVPROBE_PADDING_SIZE );
2007-03-01 16:40:48 +00:00
if ( url_fseek ( pb , 0 , SEEK_SET ) < 0 ) {
2004-07-25 11:59:34 +00:00
url_fclose ( pb );
2007-11-21 07:41:00 +00:00
if ( url_fopen ( & pb , filename , URL_RDONLY ) < 0 ) {
2007-12-17 19:08:17 +00:00
pb = NULL ;
2007-07-19 15:23:32 +00:00
err = AVERROR ( EIO );
2004-07-25 11:59:34 +00:00
goto fail ;
}
}
2006-02-02 11:27:35 +00:00
/* guess file format */
2007-03-27 19:28:40 +00:00
fmt = av_probe_input_format2 ( pd , 1 , & score );
2002-11-18 17:17:27 +00:00
}
2006-02-02 11:27:35 +00:00
av_freep ( & pd -> buf );
2002-05-20 16:28:47 +00:00
}
/* if still no format found, error */
if ( ! fmt ) {
err = AVERROR_NOFMT ;
2003-10-29 14:20:56 +00:00
goto fail ;
2001-07-22 14:18:56 +00:00
}
2005-12-17 18:14:38 +00:00
2008-01-16 22:14:26 +00:00
/* check filename in case an image number is expected */
2003-10-29 14:20:56 +00:00
if ( fmt -> flags & AVFMT_NEEDNUMBER ) {
2006-09-04 09:57:47 +00:00
if ( ! av_filename_number_test ( filename )) {
2003-01-11 05:02:14 +00:00
err = AVERROR_NUMEXPECTED ;
2003-10-29 14:20:56 +00:00
goto fail ;
2003-01-11 05:02:14 +00:00
}
}
2003-10-29 14:20:56 +00:00
err = av_open_input_stream ( ic_ptr , pb , filename , fmt , ap );
if ( err )
goto fail ;
2002-05-20 16:28:47 +00:00
return 0 ;
2001-07-22 14:18:56 +00:00
fail :
2006-02-02 11:27:35 +00:00
av_freep ( & pd -> buf );
2007-12-17 19:08:17 +00:00
if ( pb )
2003-10-29 14:20:56 +00:00
url_fclose ( pb );
2002-05-20 16:28:47 +00:00
* ic_ptr = NULL ;
return err ;
2005-12-17 18:14:38 +00:00
2001-07-22 14:18:56 +00:00
}
2003-10-29 14:20:56 +00:00
/*******************************************************/
2001-07-22 14:18:56 +00:00
int av_read_packet ( AVFormatContext * s , AVPacket * pkt )
2003-11-10 18:37:55 +00:00
{
2007-12-19 10:56:17 +00:00
int ret ;
AVStream * st ;
2007-04-22 11:07:35 +00:00
av_init_packet ( pkt );
2007-12-19 10:56:17 +00:00
ret = s -> iformat -> read_packet ( s , pkt );
2007-12-23 13:16:55 +00:00
if ( ret < 0 )
return ret ;
2007-12-19 10:56:17 +00: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 18:37:55 +00:00
}
/**********************************************************/
2005-06-28 12:55:08 +00:00
/**
2008-01-16 22:14:26 +00:00
* Get the number of samples of an audio frame. Return -1 on error.
2005-06-28 12:55:08 +00:00
*/
2003-11-10 18:37:55 +00:00
static int get_audio_frame_size ( AVCodecContext * enc , int size )
{
int frame_size ;
if ( enc -> frame_size <= 1 ) {
2006-07-07 17:50:09 +00:00
int bits_per_sample = av_get_bits_per_sample ( enc -> codec_id );
if ( bits_per_sample ) {
2005-09-02 19:16:48 +00:00
if ( enc -> channels == 0 )
return - 1 ;
2006-07-08 07:14:00 +00:00
frame_size = ( size << 3 ) / ( bits_per_sample * enc -> channels );
2006-07-07 17:50:09 +00:00
} else {
2003-11-10 18:37:55 +00: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 12:55:08 +00:00
/**
2008-01-16 22:14:26 +00:00
* Return the frame duration in seconds. Return 0 if not available.
2005-06-28 12:55:08 +00:00
*/
2005-12-17 18:14:38 +00:00
static void compute_frame_duration ( int * pnum , int * pden , AVStream * st ,
2003-11-10 18:37:55 +00:00
AVCodecParserContext * pc , AVPacket * pkt )
{
int frame_size ;
* pnum = 0 ;
* pden = 0 ;
2005-07-17 22:24:36 +00:00
switch ( st -> codec -> codec_type ) {
2003-11-10 18:37:55 +00:00
case CODEC_TYPE_VIDEO :
2005-05-12 16:27:05 +00:00
if ( st -> time_base . num * 1000LL > st -> time_base . den ){
2005-04-30 21:43:59 +00:00
* pnum = st -> time_base . num ;
* pden = st -> time_base . den ;
2005-07-17 22:24:36 +00: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 20:26:50 +00:00
if ( pc && pc -> repeat_pict ) {
* pden *= 2 ;
* pnum = ( * pnum ) * ( 2 + pc -> repeat_pict );
}
2003-11-10 18:37:55 +00:00
}
break ;
case CODEC_TYPE_AUDIO :
2005-07-17 22:24:36 +00:00
frame_size = get_audio_frame_size ( st -> codec , pkt -> size );
2003-11-10 18:37:55 +00:00
if ( frame_size < 0 )
break ;
* pnum = frame_size ;
2005-07-17 22:24:36 +00:00
* pden = st -> codec -> sample_rate ;
2003-11-10 18:37:55 +00:00
break ;
default :
break ;
}
}
2004-10-22 01:51:17 +00: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 18:29:38 +00:00
case CODEC_ID_FFVHUFF :
2004-10-22 01:51:17 +00:00
case CODEC_ID_ASV1 :
case CODEC_ID_ASV2 :
case CODEC_ID_VCR1 :
return 1 ;
default : break ;
}
}
return 0 ;
}
2007-09-03 07:56:26 +00:00
static void update_initial_timestamps ( AVFormatContext * s , int stream_index ,
int64_t dts , int64_t pts )
{
2007-08-04 22:46:13 +00: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-04 22:54:46 +00:00
if ( st -> start_time == AV_NOPTS_VALUE && pktl -> pkt . pts != AV_NOPTS_VALUE )
st -> start_time = pktl -> pkt . pts ;
2007-08-04 22:46:13 +00:00
}
2007-09-03 07:56:26 +00:00
if ( st -> start_time == AV_NOPTS_VALUE )
st -> start_time = pts ;
2007-08-04 22:46:13 +00:00
}
2008-02-15 20:32:32 +00:00
static void update_initial_durations ( AVFormatContext * s , AVStream * st , AVPacket * pkt )
{
AVPacketList * pktl = s -> packet_buffer ;
assert ( pkt -> duration && ! st -> cur_dts );
for (; pktl ; pktl = pktl -> next ){
if ( pktl -> pkt . stream_index != pkt -> stream_index )
continue ;
2008-02-20 03:40:07 +00:00
if ( pktl -> pkt . pts == pktl -> pkt . dts && pktl -> pkt . dts == AV_NOPTS_VALUE
&& ! pktl -> pkt . duration ){
2008-02-15 20:32:32 +00:00
pktl -> pkt . pts = pktl -> pkt . dts = st -> cur_dts ;
st -> cur_dts += pkt -> duration ;
pktl -> pkt . duration = pkt -> duration ;
} else
break ;
}
}
2005-12-17 18:14:38 +00:00
static void compute_pkt_fields ( AVFormatContext * s , AVStream * st ,
2003-11-10 18:37:55 +00:00
AVCodecParserContext * pc , AVPacket * pkt )
{
2007-03-17 14:27:01 +00:00
int num , den , presentation_delayed , delay , i ;
2007-04-13 07:50:04 +00:00
int64_t offset ;
2005-12-17 18:14:38 +00:00
2007-07-31 15:06:27 +00: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 18:37:55 +00:00
if ( pkt -> duration == 0 ) {
2004-05-29 18:50:31 +00:00
compute_frame_duration ( & num , & den , st , pc , pkt );
2003-11-10 18:37:55 +00:00
if ( den && num ) {
2004-05-23 21:36:23 +00:00
pkt -> duration = av_rescale ( 1 , num * ( int64_t ) st -> time_base . den , den * ( int64_t ) st -> time_base . num );
2008-02-15 20:32:32 +00:00
2008-04-13 08:55:02 +00:00
if ( st -> cur_dts == 0 && pkt -> duration != 0 )
2008-02-15 20:32:32 +00:00
update_initial_durations ( s , st , pkt );
2003-11-10 18:37:55 +00:00
}
}
2008-01-16 22:14:26 +00:00
/* correct timestamps with byte offset if demuxers only have timestamps
on packet boundaries */
2007-04-13 07:50:04 +00: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-16 22:14:26 +00:00
/* do we have a video B-frame ? */
2007-03-16 22:59:45 +00:00
delay = st -> codec -> has_b_frames ;
2003-11-10 18:37:55 +00:00
presentation_delayed = 0 ;
2007-03-17 14:29:00 +00: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 09:29:25 +00:00
/* This may be redundant, but it should not hurt. */
2007-03-17 14:29:00 +00:00
if ( pkt -> dts != AV_NOPTS_VALUE && pkt -> pts != AV_NOPTS_VALUE && pkt -> pts > pkt -> dts )
presentation_delayed = 1 ;
2005-12-17 18:14:38 +00:00
2004-05-29 02:06:32 +00:00
if ( st -> cur_dts == AV_NOPTS_VALUE ){
2007-08-04 22:46:13 +00:00
st -> cur_dts = 0 ; //FIXME maybe set it to 0 during init
2004-05-29 02:06:32 +00:00
}
2003-11-10 18:37:55 +00:00
2006-11-01 22:39:58 +00: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 18:37:55 +00:00
/* interpolate PTS and DTS if they are not present */
2007-03-17 14:29:00 +00:00
if ( delay <= 1 ){
if ( presentation_delayed ) {
2008-01-16 22:14:26 +00:00
/* DTS = decompression timestamp */
/* PTS = presentation timestamp */
2007-03-17 14:29:00 +00:00
if ( pkt -> dts == AV_NOPTS_VALUE )
2008-02-20 20:24:38 +00:00
pkt -> dts = st -> last_IP_pts ;
2007-09-03 07:56:26 +00:00
update_initial_timestamps ( s , pkt -> stream_index , pkt -> dts , pkt -> pts );
2007-03-17 14:29:00 +00:00
if ( pkt -> dts == AV_NOPTS_VALUE )
pkt -> dts = st -> cur_dts ;
2007-03-17 02:03:59 +00:00
2007-03-17 14:29:00 +00:00
/* this is tricky: the dts must be incremented by the duration
2008-01-16 22:14:26 +00:00
of the frame we are displaying, i.e. the last I- or P-frame */
2008-02-20 20:24:38 +00: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 ;
2007-03-17 14:29:00 +00:00
/* cannot compute PTS if not present (we can compute it only
2008-01-16 22:14:26 +00:00
by knowing the future */
2007-03-20 13:59:59 +00:00
} else if ( pkt -> pts != AV_NOPTS_VALUE || pkt -> dts != AV_NOPTS_VALUE || pkt -> duration ){
2007-03-17 14:29:00 +00: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 02:36:03 +00:00
}
2005-12-17 18:14:38 +00:00
2007-03-17 14:29:00 +00:00
/* presentation is not delayed : PTS and DTS are the same */
if ( pkt -> pts == AV_NOPTS_VALUE )
pkt -> pts = pkt -> dts ;
2007-09-03 07:56:26 +00:00
update_initial_timestamps ( s , pkt -> stream_index , pkt -> pts , pkt -> pts );
2007-03-17 14:29:00 +00: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 18:37:55 +00:00
}
2007-03-17 14:27:01 +00: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-04 22:46:13 +00:00
if ( delay > 1 ){
2007-09-03 07:56:26 +00:00
update_initial_timestamps ( s , pkt -> stream_index , pkt -> dts , pkt -> pts ); // this should happen on the first packet
2007-08-04 22:46:13 +00:00
}
2007-03-17 14:27:01 +00: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 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
/* update flags */
2007-10-24 04:54:44 +00:00
if ( is_intra_only ( st -> codec ))
pkt -> flags |= PKT_FLAG_KEY ;
else if ( pc ) {
2003-11-10 18:37:55 +00:00
pkt -> flags = 0 ;
2008-01-16 22:14:26 +00:00
/* keyframe computation */
2003-11-10 18:37:55 +00:00
if ( pc -> pict_type == FF_I_TYPE )
pkt -> flags |= PKT_FLAG_KEY ;
}
}
2004-09-28 21:09:25 +00:00
void av_destruct_packet_nofree ( AVPacket * pkt )
2003-11-10 18:37:55 +00:00
{
pkt -> data = NULL ; pkt -> size = 0 ;
}
static int av_read_frame_internal ( AVFormatContext * s , AVPacket * pkt )
{
AVStream * st ;
2003-12-15 14:45:37 +00:00
int len , ret , i ;
2003-11-10 18:37:55 +00:00
2007-04-22 11:07:35 +00:00
av_init_packet ( pkt );
2003-11-10 18:37:55 +00:00
for (;;) {
/* select current input stream component */
st = s -> cur_st ;
if ( st ) {
2005-06-27 00:04:03 +00:00
if ( ! st -> need_parsing || ! st -> parser ) {
2003-11-10 18:37:55 +00: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 19:55:32 +00:00
break ;
2005-03-17 01:25:01 +00:00
} else if ( s -> cur_len > 0 && st -> discard < AVDISCARD_ALL ) {
2005-12-17 18:14:38 +00:00
len = av_parser_parse ( st -> parser , st -> codec , & pkt -> data , & pkt -> size ,
2003-12-16 11:21:25 +00: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 18:37:55 +00:00
/* increment read pointer */
s -> cur_ptr += len ;
s -> cur_len -= len ;
2005-12-17 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
/* return packet if any */
if ( pkt -> size ) {
2003-12-15 14:45:37 +00:00
got_packet :
2007-05-02 13:36:45 +00:00
pkt -> pos = s -> cur_pkt . pos ; // Isn't quite accurate but close.
2003-11-10 18:37:55 +00:00
pkt -> duration = 0 ;
pkt -> stream_index = st -> index ;
2003-12-16 11:21:25 +00:00
pkt -> pts = st -> parser -> pts ;
pkt -> dts = st -> parser -> dts ;
2003-11-10 18:37:55 +00:00
pkt -> destruct = av_destruct_packet_nofree ;
compute_pkt_fields ( s , st , st -> parser , pkt );
2007-02-05 23:04:48 +00:00
if (( s -> iformat -> flags & AVFMT_GENERIC_INDEX ) && pkt -> flags & PKT_FLAG_KEY ){
2008-01-13 13:33:37 +00:00
ff_reduce_index ( s , st -> index );
2007-02-05 23:04:48 +00:00
av_add_index_entry ( st , st -> parser -> frame_offset , pkt -> dts ,
0 , 0 , AVINDEX_KEYFRAME );
}
2006-08-08 19:55:32 +00:00
break ;
2003-11-10 18:37:55 +00:00
}
} else {
2003-11-20 11:22:25 +00:00
/* free packet */
2005-12-17 18:14:38 +00:00
av_free_packet ( & s -> cur_pkt );
2003-11-10 18:37:55 +00:00
s -> cur_st = NULL ;
}
} else {
/* read next packet */
ret = av_read_packet ( s , & s -> cur_pkt );
2003-12-15 14:45:37 +00:00
if ( ret < 0 ) {
2007-02-13 18:26:14 +00:00
if ( ret == AVERROR ( EAGAIN ))
2003-12-15 14:45:37 +00:00
return ret ;
/* return the last frames, if any */
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
st = s -> streams [ i ];
2005-06-27 00:04:03 +00:00
if ( st -> parser && st -> need_parsing ) {
2005-12-17 18:14:38 +00:00
av_parser_parse ( st -> parser , st -> codec ,
& pkt -> data , & pkt -> size ,
NULL , 0 ,
2003-12-16 11:21:25 +00:00
AV_NOPTS_VALUE , AV_NOPTS_VALUE );
2003-12-15 14:45:37 +00:00
if ( pkt -> size )
goto got_packet ;
}
}
2008-01-16 22:14:26 +00:00
/* no more packets: really terminate parsing */
2003-11-10 18:37:55 +00:00
return ret ;
2003-12-15 14:45:37 +00:00
}
2005-12-17 18:14:38 +00:00
2004-05-21 20:43:21 +00:00
st = s -> streams [ s -> cur_pkt . stream_index ];
2006-08-08 19:55:32 +00:00
if ( st -> codec -> debug & FF_DEBUG_PTS )
2006-10-14 20:43:39 +00:00
av_log ( s , AV_LOG_DEBUG , "av_read_packet stream=%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d \n " ,
2006-08-08 19:55:32 +00:00
s -> cur_pkt . stream_index ,
s -> cur_pkt . pts ,
s -> cur_pkt . dts ,
s -> cur_pkt . size );
2003-11-10 18:37:55 +00: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-17 22:24:36 +00:00
st -> parser = av_parser_init ( st -> codec -> codec_id );
2003-11-10 18:37:55 +00:00
if ( ! st -> parser ) {
2008-01-16 22:14:26 +00:00
/* no parser available: just output the raw packets */
2007-04-15 13:51:57 +00:00
st -> need_parsing = AVSTREAM_PARSE_NONE ;
} else if ( st -> need_parsing == AVSTREAM_PARSE_HEADERS ){
2005-08-15 15:58:21 +00:00
st -> parser -> flags |= PARSER_FLAG_COMPLETE_FRAMES ;
2003-11-10 18:37:55 +00:00
}
2007-02-05 23:04:48 +00: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 18:37:55 +00:00
}
}
}
2006-08-08 19:55:32 +00:00
if ( st -> codec -> debug & FF_DEBUG_PTS )
2006-10-14 20:43:39 +00:00
av_log ( s , AV_LOG_DEBUG , "av_read_frame_internal stream=%d, pts=%" PRId64 ", dts=%" PRId64 ", size=%d \n " ,
2006-08-08 19:55:32 +00:00
pkt -> stream_index ,
pkt -> pts ,
pkt -> dts ,
pkt -> size );
return 0 ;
2003-11-10 18:37:55 +00:00
}
2007-08-03 08:56:00 +00: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 18:37:55 +00:00
int av_read_frame ( AVFormatContext * s , AVPacket * pkt )
2001-07-22 14:18:56 +00:00
{
AVPacketList * pktl ;
2005-08-15 14:22:43 +00:00
int eof = 0 ;
const int genpts = s -> flags & AVFMT_FLAG_GENPTS ;
2001-07-22 14:18:56 +00:00
2005-08-15 14:22:43 +00:00
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 18:14:38 +00:00
if ( pktl -> pkt . stream_index == next_pkt -> stream_index
2005-08-15 14:22:43 +00: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 18:14:38 +00:00
if ( next_pkt -> pts != AV_NOPTS_VALUE
|| next_pkt -> dts == AV_NOPTS_VALUE
2005-08-15 14:22:43 +00: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 18:26:14 +00:00
if ( pktl && ret != AVERROR ( EAGAIN )){
2005-08-15 14:22:43 +00:00
eof = 1 ;
continue ;
} else
return ret ;
}
2005-12-17 18:14:38 +00:00
2007-08-03 08:56:00 +00:00
if ( av_dup_packet ( add_to_pktbuf ( s , pkt )) < 0 )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2005-08-15 14:22:43 +00:00
} else {
assert ( ! s -> packet_buffer );
return av_read_frame_internal ( s , pkt );
}
2001-07-22 14:18:56 +00:00
}
}
2003-11-10 18:37:55 +00:00
/* XXX: suppress the packet queue */
static void flush_packet_queue ( AVFormatContext * s )
{
AVPacketList * pktl ;
for (;;) {
pktl = s -> packet_buffer ;
2005-12-17 18:14:38 +00:00
if ( ! pktl )
2003-11-10 18:37:55 +00:00
break ;
s -> packet_buffer = pktl -> next ;
av_free_packet ( & pktl -> pkt );
av_free ( pktl );
}
}
/*******************************************************/
/* seek support */
2004-01-13 22:02:49 +00: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-17 22:24:36 +00:00
if ( st -> codec -> codec_type == CODEC_TYPE_VIDEO ) {
2004-01-13 22:02:49 +00:00
return i ;
}
}
return 0 ;
}
2005-06-28 12:55:08 +00:00
/**
* Flush the frame reader.
*/
2003-11-10 18:37:55 +00: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 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
/* for each stream, reset read state */
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
st = s -> streams [ i ];
2005-12-17 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
if ( st -> parser ) {
av_parser_close ( st -> parser );
st -> parser = NULL ;
}
2008-02-20 20:24:38 +00:00
st -> last_IP_pts = AV_NOPTS_VALUE ;
2007-03-20 13:01:39 +00:00
st -> cur_dts = AV_NOPTS_VALUE ; /* we set the current DTS to an unspecified origin */
2003-11-10 18:37:55 +00:00
}
}
2006-07-23 18:19:33 +00:00
void av_update_cur_dts ( AVFormatContext * s , AVStream * ref_st , int64_t timestamp ){
2004-10-12 10:28:27 +00:00
int i ;
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
2004-10-22 13:15:18 +00:00
AVStream * st = s -> streams [ i ];
2004-10-12 10:28:27 +00:00
2005-12-17 18:14:38 +00:00
st -> cur_dts = av_rescale ( timestamp ,
2004-10-22 13:15:18 +00: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 10:28:27 +00:00
}
}
2008-01-13 13:33:37 +00: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 18:06:52 +00:00
int av_add_index_entry ( AVStream * st ,
2006-03-01 11:29:55 +00:00
int64_t pos , int64_t timestamp , int size , int distance , int flags )
2003-11-10 18:37:55 +00:00
{
AVIndexEntry * entries , * ie ;
2004-01-13 22:02:49 +00:00
int index ;
2005-12-17 18:14:38 +00:00
2005-01-08 14:21:33 +00:00
if (( unsigned ) st -> nb_index_entries + 1 >= UINT_MAX / sizeof ( AVIndexEntry ))
return - 1 ;
2005-12-17 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
entries = av_fast_realloc ( st -> index_entries ,
& st -> index_entries_allocated_size ,
2005-12-17 18:14:38 +00:00
( st -> nb_index_entries + 1 ) *
2003-11-10 18:37:55 +00:00
sizeof ( AVIndexEntry ));
2005-01-08 14:21:33 +00:00
if ( ! entries )
return - 1 ;
2004-01-13 22:02:49 +00:00
st -> index_entries = entries ;
2005-03-13 00:13:01 +00:00
index = av_index_search_timestamp ( st , timestamp , AVSEEK_FLAG_ANY );
2004-01-13 22:02:49 +00:00
2004-10-10 22:05:43 +00:00
if ( index < 0 ){
2004-01-17 18:06:52 +00:00
index = st -> nb_index_entries ++ ;
ie = & entries [ index ];
2004-10-10 22:05:43 +00:00
assert ( index == 0 || ie [ - 1 ]. timestamp < timestamp );
} else {
ie = & entries [ index ];
if ( ie -> timestamp != timestamp ){
2004-10-13 23:58:28 +00:00
if ( ie -> timestamp <= timestamp )
return - 1 ;
2004-10-10 22:05:43 +00:00
memmove ( entries + index + 1 , entries + index , sizeof ( AVIndexEntry ) * ( st -> nb_index_entries - index ));
st -> nb_index_entries ++ ;
2007-06-12 09:29:25 +00:00
} else if ( ie -> pos == pos && distance < ie -> min_distance ) //do not reduce the distance
2004-10-10 22:05:43 +00:00
distance = ie -> min_distance ;
2004-01-17 18:06:52 +00:00
}
2004-10-10 22:05:43 +00:00
2004-01-13 22:02:49 +00:00
ie -> pos = pos ;
ie -> timestamp = timestamp ;
2004-01-17 18:06:52 +00:00
ie -> min_distance = distance ;
2006-03-01 11:29:55 +00:00
ie -> size = size ;
2004-01-13 22:02:49 +00:00
ie -> flags = flags ;
2005-12-17 18:14:38 +00:00
2004-01-17 18:06:52 +00:00
return index ;
2003-11-10 18:37:55 +00:00
}
2004-11-23 18:23:56 +00:00
int av_index_search_timestamp ( AVStream * st , int64_t wanted_timestamp ,
2005-03-13 00:13:01 +00:00
int flags )
2003-11-10 18:37:55 +00:00
{
2004-01-13 22:02:49 +00:00
AVIndexEntry * entries = st -> index_entries ;
int nb_entries = st -> nb_index_entries ;
2003-11-10 18:37:55 +00:00
int a , b , m ;
int64_t timestamp ;
2004-10-10 22:05:43 +00:00
a = - 1 ;
b = nb_entries ;
2004-01-13 22:02:49 +00:00
2004-10-10 22:05:43 +00:00
while ( b - a > 1 ) {
m = ( a + b ) >> 1 ;
2003-11-10 18:37:55 +00:00
timestamp = entries [ m ]. timestamp ;
2004-10-10 22:05:43 +00:00
if ( timestamp >= wanted_timestamp )
b = m ;
if ( timestamp <= wanted_timestamp )
2004-01-13 22:02:49 +00:00
a = m ;
2003-11-10 18:37:55 +00:00
}
2005-03-13 00:13:01 +00:00
m = ( flags & AVSEEK_FLAG_BACKWARD ) ? a : b ;
2005-12-17 18:14:38 +00:00
2005-03-13 00:13:01 +00: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-10 22:05:43 +00:00
2005-12-17 18:14:38 +00:00
if ( m == nb_entries )
2004-10-10 22:05:43 +00:00
return - 1 ;
return m ;
2003-11-10 18:37:55 +00:00
}
2007-10-16 19:50:08 +00:00
#define DEBUG_SEEK
2004-04-12 16:50:03 +00:00
2004-10-10 22:05:43 +00:00
int av_seek_frame_binary ( AVFormatContext * s , int stream_index , int64_t target_ts , int flags ){
2004-04-12 16:50:03 +00:00
AVInputFormat * avif = s -> iformat ;
int64_t pos_min , pos_max , pos , pos_limit ;
int64_t ts_min , ts_max , ts ;
2006-11-14 01:34:36 +00:00
int index ;
2004-04-12 16:50:03 +00:00
AVStream * st ;
2004-05-23 16:26:12 +00:00
if ( stream_index < 0 )
return - 1 ;
2005-12-17 18:14:38 +00:00
2004-04-12 16:50:03 +00:00
#ifdef DEBUG_SEEK
2005-12-12 01:56:46 +00:00
av_log ( s , AV_LOG_DEBUG , "read_seek: %d %" PRId64 " \n " , stream_index , target_ts );
2004-04-12 16:50:03 +00:00
#endif
ts_max =
ts_min = AV_NOPTS_VALUE ;
2007-06-12 18:50:50 +00:00
pos_limit = - 1 ; //gcc falsely says it may be uninitialized
2004-04-12 16:50:03 +00:00
st = s -> streams [ stream_index ];
if ( st -> index_entries ){
AVIndexEntry * e ;
2008-01-16 22:14:26 +00: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-10 22:05:43 +00:00
index = FFMAX ( index , 0 );
2004-04-12 16:50:03 +00: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 18:14:38 +00:00
av_log ( s , AV_LOG_DEBUG , "using cached pos_min=0x%" PRIx64 " dts_min=%" PRId64 " \n " ,
2004-04-12 16:50:03 +00:00
pos_min , ts_min );
#endif
} else {
assert ( index == 0 );
}
2005-12-17 18:14:38 +00:00
index = av_index_search_timestamp ( st , target_ts , flags & ~ AVSEEK_FLAG_BACKWARD );
2005-03-13 00:13:01 +00:00
assert ( index < st -> nb_index_entries );
if ( index >= 0 ){
2004-04-12 16:50:03 +00: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 18:14:38 +00:00
av_log ( s , AV_LOG_DEBUG , "using cached pos_max=0x%" PRIx64 " pos_limit=0x%" PRIx64 " dts_max=%" PRId64 " \n " ,
2004-04-12 16:50:03 +00:00
pos_max , pos_limit , ts_max );
#endif
}
}
2006-11-14 01:34:36 +00: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 07:41:00 +00:00
url_fseek ( s -> pb , pos , SEEK_SET );
2006-11-14 01:34:36 +00: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 16:50:03 +00:00
if ( ts_min == AV_NOPTS_VALUE ){
pos_min = s -> data_offset ;
2006-11-14 01:34:36 +00:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX );
2004-04-12 16:50:03 +00:00
if ( ts_min == AV_NOPTS_VALUE )
return - 1 ;
}
if ( ts_max == AV_NOPTS_VALUE ){
int step = 1024 ;
2007-11-21 07:41:00 +00:00
filesize = url_fsize ( s -> pb );
2005-07-08 09:14:05 +00:00
pos_max = filesize - 1 ;
2004-04-12 16:50:03 +00:00
do {
pos_max -= step ;
2006-11-14 01:34:36 +00:00
ts_max = read_timestamp ( s , stream_index , & pos_max , pos_max + step );
2004-04-12 16:50:03 +00:00
step += step ;
} while ( ts_max == AV_NOPTS_VALUE && pos_max >= step );
if ( ts_max == AV_NOPTS_VALUE )
return - 1 ;
2005-12-17 18:14:38 +00:00
2004-04-12 16:50:03 +00:00
for (;;){
int64_t tmp_pos = pos_max + 1 ;
2006-11-14 01:34:36 +00:00
int64_t tmp_ts = read_timestamp ( s , stream_index , & tmp_pos , INT64_MAX );
2004-04-12 16:50:03 +00:00
if ( tmp_ts == AV_NOPTS_VALUE )
break ;
ts_max = tmp_ts ;
pos_max = tmp_pos ;
2005-07-08 09:14:05 +00:00
if ( tmp_pos >= filesize )
break ;
2004-04-12 16:50:03 +00:00
}
pos_limit = pos_max ;
}
2006-02-02 19:23:33 +00:00
if ( ts_min > ts_max ){
return - 1 ;
} else if ( ts_min == ts_max ){
pos_limit = pos_min ;
}
2004-04-12 16:50:03 +00:00
no_change = 0 ;
while ( pos_min < pos_limit ) {
#ifdef DEBUG_SEEK
2005-12-17 18:14:38 +00: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 16:50:03 +00: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-10 22:05:43 +00:00
pos = av_rescale ( target_ts - ts_min , pos_max - pos_min , ts_max - ts_min )
+ pos_min - approximate_keyframe_distance ;
2004-04-12 16:50:03 +00: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-16 22:14:26 +00:00
/* linear search if bisection failed, can only happen if there
are very few or no keyframes between min/max */
2004-04-12 16:50:03 +00: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 01:34:36 +00:00
ts = read_timestamp ( s , stream_index , & pos , INT64_MAX ); //may pass pos_limit instead of -1
2004-04-12 16:50:03 +00:00
if ( pos == pos_max )
no_change ++ ;
else
no_change = 0 ;
#ifdef DEBUG_SEEK
2005-12-12 01:56:46 +00: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 16:50:03 +00:00
#endif
2007-04-22 18:48:07 +00:00
if ( ts == AV_NOPTS_VALUE ){
av_log ( s , AV_LOG_ERROR , "read_timestamp() failed in the middle \n " );
return - 1 ;
}
2004-04-12 16:50:03 +00:00
assert ( ts != AV_NOPTS_VALUE );
2004-10-10 22:05:43 +00:00
if ( target_ts <= ts ) {
2004-04-12 16:50:03 +00:00
pos_limit = start_pos - 1 ;
pos_max = pos ;
ts_max = ts ;
2004-10-10 22:05:43 +00:00
}
if ( target_ts >= ts ) {
2004-04-12 16:50:03 +00:00
pos_min = pos ;
ts_min = ts ;
}
}
2005-12-17 18:14:38 +00:00
2004-10-10 22:05:43 +00:00
pos = ( flags & AVSEEK_FLAG_BACKWARD ) ? pos_min : pos_max ;
ts = ( flags & AVSEEK_FLAG_BACKWARD ) ? ts_min : ts_max ;
2004-04-12 16:50:03 +00:00
#ifdef DEBUG_SEEK
pos_min = pos ;
2006-11-14 01:34:36 +00:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX );
2004-04-12 16:50:03 +00:00
pos_min ++ ;
2006-11-14 01:34:36 +00:00
ts_max = read_timestamp ( s , stream_index , & pos_min , INT64_MAX );
2005-12-17 18:14:38 +00:00
av_log ( s , AV_LOG_DEBUG , "pos=0x%" PRIx64 " %" PRId64 "<=%" PRId64 "<=%" PRId64 " \n " ,
2004-04-12 16:50:03 +00:00
pos , ts_min , target_ts , ts_max );
#endif
2006-11-14 01:34:36 +00:00
* ts_ret = ts ;
return pos ;
2004-04-12 16:50:03 +00:00
}
2004-10-10 22:05:43 +00: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 07:41:00 +00:00
pos_max = url_fsize ( s -> pb ) - 1 ;
2004-10-10 22:05:43 +00:00
if ( pos < pos_min ) pos = pos_min ;
else if ( pos > pos_max ) pos = pos_max ;
2007-11-21 07:41:00 +00:00
url_fseek ( s -> pb , pos , SEEK_SET );
2004-10-10 22:05:43 +00:00
#if 0
2004-10-12 10:28:27 +00:00
av_update_cur_dts(s, st, ts);
2004-10-10 22:05:43 +00:00
#endif
return 0 ;
}
2005-12-17 18:14:38 +00:00
static int av_seek_frame_generic ( AVFormatContext * s ,
2004-10-10 22:05:43 +00:00
int stream_index , int64_t timestamp , int flags )
2003-11-10 18:37:55 +00:00
{
2004-10-12 10:28:27 +00:00
int index ;
2003-11-10 18:37:55 +00:00
AVStream * st ;
AVIndexEntry * ie ;
st = s -> streams [ stream_index ];
2007-02-05 23:04:48 +00:00
2005-03-13 00:13:01 +00:00
index = av_index_search_timestamp ( st , timestamp , flags );
2007-02-05 23:04:48 +00:00
2007-04-22 16:23:44 +00:00
if ( index < 0 || index == st -> nb_index_entries - 1 ){
2007-02-05 23:04:48 +00: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 07:41:00 +00:00
url_fseek ( s -> pb , ie -> pos , SEEK_SET );
2007-02-05 23:04:48 +00:00
av_update_cur_dts ( s , st , ie -> timestamp );
} else
2007-11-21 07:41:00 +00:00
url_fseek ( s -> pb , 0 , SEEK_SET );
2007-02-05 23:04:48 +00: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 18:37:55 +00:00
if ( index < 0 )
return - 1 ;
av_read_frame_flush ( s );
2007-02-05 23:04:48 +00: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 07:41:00 +00:00
url_fseek ( s -> pb , ie -> pos , SEEK_SET );
2004-05-23 16:26:12 +00:00
2004-10-12 10:28:27 +00:00
av_update_cur_dts ( s , st , ie -> timestamp );
2004-05-23 16:26:12 +00:00
2003-11-10 18:37:55 +00:00
return 0 ;
}
2004-10-10 22:05:43 +00:00
int av_seek_frame ( AVFormatContext * s , int stream_index , int64_t timestamp , int flags )
2003-11-10 18:37:55 +00:00
{
int ret ;
2004-05-23 16:26:12 +00:00
AVStream * st ;
2005-12-17 18:14:38 +00:00
2003-11-10 18:37:55 +00:00
av_read_frame_flush ( s );
2005-12-17 18:14:38 +00:00
2004-10-10 22:05:43 +00:00
if ( flags & AVSEEK_FLAG_BYTE )
return av_seek_frame_byte ( s , stream_index , timestamp , flags );
2005-12-17 18:14:38 +00:00
2004-05-23 16:26:12 +00:00
if ( stream_index < 0 ){
stream_index = av_find_default_stream_index ( s );
if ( stream_index < 0 )
return - 1 ;
2005-12-17 18:14:38 +00:00
2004-10-10 22:05:43 +00:00
st = s -> streams [ stream_index ];
2004-10-11 19:42:18 +00:00
/* timestamp for default must be expressed in AV_TIME_BASE units */
2004-10-10 22:05:43 +00:00
timestamp = av_rescale ( timestamp , st -> time_base . den , AV_TIME_BASE * ( int64_t ) st -> time_base . num );
2004-05-23 16:26:12 +00:00
}
st = s -> streams [ stream_index ];
2003-11-10 18:37:55 +00:00
/* first, we try the format specific seek */
if ( s -> iformat -> read_seek )
2004-10-10 22:05:43 +00:00
ret = s -> iformat -> read_seek ( s , stream_index , timestamp , flags );
2003-11-10 18:37:55 +00:00
else
ret = - 1 ;
if ( ret >= 0 ) {
return 0 ;
}
2004-04-12 16:50:03 +00:00
if ( s -> iformat -> read_timestamp )
2004-10-10 22:05:43 +00:00
return av_seek_frame_binary ( s , stream_index , timestamp , flags );
2004-04-12 16:50:03 +00:00
else
2004-10-10 22:05:43 +00:00
return av_seek_frame_generic ( s , stream_index , timestamp , flags );
2003-11-10 18:37:55 +00:00
}
2003-10-29 14:20:56 +00:00
/*******************************************************/
2003-08-08 18:02:23 +00:00
2005-06-28 12:55:08 +00:00
/**
2007-09-05 16:47:48 +00:00
* Returns TRUE if the stream has accurate duration in any stream.
2005-06-28 12:55:08 +00:00
*
2007-09-05 16:47:48 +00:00
* @return TRUE if the stream has accurate duration for at least one component.
2005-06-28 12:55:08 +00:00
*/
2007-09-05 16:47:48 +00:00
static int av_has_duration ( AVFormatContext * ic )
2003-08-08 18:02:23 +00:00
{
int i ;
AVStream * st ;
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2007-09-05 16:47:48 +00:00
if ( st -> duration != AV_NOPTS_VALUE )
2003-08-08 18:02:23 +00:00
return 1 ;
}
return 0 ;
}
2005-06-28 12:55:08 +00:00
/**
* Estimate the stream timings from the one of each components.
*
* Also computes the global bitrate if possible.
*/
2003-08-08 18:02:23 +00:00
static void av_update_stream_timings ( AVFormatContext * ic )
{
2005-04-30 21:43:59 +00:00
int64_t start_time , start_time1 , end_time , end_time1 ;
2007-09-05 16:47:48 +00:00
int64_t duration , duration1 ;
2003-08-08 18:02:23 +00:00
int i ;
AVStream * st ;
2006-12-07 00:47:37 +00:00
start_time = INT64_MAX ;
end_time = INT64_MIN ;
2007-09-05 16:47:48 +00:00
duration = INT64_MIN ;
2003-08-08 18:02:23 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2008-01-21 23:43:25 +00:00
if ( st -> start_time != AV_NOPTS_VALUE && st -> time_base . den ) {
2005-04-30 21:43:59 +00: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 18:02:23 +00:00
if ( st -> duration != AV_NOPTS_VALUE ) {
2005-04-30 21:43:59 +00:00
end_time1 = start_time1
+ av_rescale_q ( st -> duration , st -> time_base , AV_TIME_BASE_Q );
2003-08-08 18:02:23 +00:00
if ( end_time1 > end_time )
end_time = end_time1 ;
}
}
2007-09-05 16:47:48 +00: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 18:02:23 +00:00
}
2006-12-07 00:47:37 +00:00
if ( start_time != INT64_MAX ) {
2003-08-08 18:02:23 +00:00
ic -> start_time = start_time ;
2006-12-07 00:47:37 +00:00
if ( end_time != INT64_MIN ) {
2007-09-05 16:47:48 +00: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-16 22:14:26 +00:00
/* compute the bitrate */
2007-09-05 16:47:48 +00:00
ic -> bit_rate = ( double ) ic -> file_size * 8.0 * AV_TIME_BASE /
( double ) ic -> duration ;
2003-08-08 18:02:23 +00: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-04-30 21:43:59 +00: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 18:02:23 +00: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-17 22:24:36 +00:00
bit_rate += st -> codec -> bit_rate ;
2003-08-08 18:02:23 +00:00
}
ic -> bit_rate = bit_rate ;
}
/* if duration is already set, we believe it */
2005-12-17 18:14:38 +00:00
if ( ic -> duration == AV_NOPTS_VALUE &&
ic -> bit_rate != 0 &&
2003-08-08 18:02:23 +00: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-04-30 21:43:59 +00:00
duration = av_rescale ( 8 * filesize , st -> time_base . den , ic -> bit_rate * ( int64_t ) st -> time_base . num );
2007-08-18 01:26:06 +00:00
if ( st -> duration == AV_NOPTS_VALUE )
2003-08-08 18:02:23 +00:00
st -> duration = duration ;
}
}
}
}
#define DURATION_MAX_READ_SIZE 250000
/* only usable for MPEG-PS streams */
2007-02-05 02:08:57 +00:00
static void av_estimate_timings_from_pts ( AVFormatContext * ic , offset_t old_offset )
2003-08-08 18:02:23 +00:00
{
AVPacket pkt1 , * pkt = & pkt1 ;
AVStream * st ;
int read_size , i , ret ;
2005-08-14 15:42:40 +00:00
int64_t end_time ;
2003-08-08 18:02:23 +00:00
int64_t filesize , offset , duration ;
2005-12-17 18:14:38 +00:00
2007-04-26 10:49:48 +00: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 18:14:38 +00:00
2003-08-08 18:02:23 +00:00
/* we read the first packets to get the first PTS (not fully
accurate, but it is enough now) */
2007-11-21 07:41:00 +00:00
url_fseek ( ic -> pb , 0 , SEEK_SET );
2003-08-08 18:02:23 +00: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-04-30 21:43:59 +00:00
st -> start_time = pkt -> pts ;
2003-09-07 09:26:39 +00:00
}
av_free_packet ( pkt );
}
2003-08-08 18:02:23 +00: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 07:41:00 +00:00
url_fseek ( ic -> pb , offset , SEEK_SET );
2003-08-08 18:02:23 +00:00
read_size = 0 ;
for (;;) {
if ( read_size >= DURATION_MAX_READ_SIZE )
break ;
2005-12-17 18:14:38 +00:00
2003-08-08 18:02:23 +00:00
ret = av_read_packet ( ic , pkt );
if ( ret != 0 )
break ;
read_size += pkt -> size ;
st = ic -> streams [ pkt -> stream_index ];
2007-08-18 00:45:44 +00:00
if ( pkt -> pts != AV_NOPTS_VALUE &&
st -> start_time != AV_NOPTS_VALUE ) {
2005-04-30 21:43:59 +00:00
end_time = pkt -> pts ;
2003-08-08 18:02:23 +00: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 18:14:38 +00:00
2005-04-30 21:43:59 +00:00
fill_all_stream_timings ( ic );
2003-08-08 18:02:23 +00:00
2007-11-21 07:41:00 +00:00
url_fseek ( ic -> pb , old_offset , SEEK_SET );
2007-08-18 00:44:14 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ){
st = ic -> streams [ i ];
st -> cur_dts = st -> first_dts ;
2008-02-20 20:24:38 +00:00
st -> last_IP_pts = AV_NOPTS_VALUE ;
2007-08-18 00:44:14 +00:00
}
2003-08-08 18:02:23 +00:00
}
2007-02-05 02:08:57 +00:00
static void av_estimate_timings ( AVFormatContext * ic , offset_t old_offset )
2003-08-08 18:02:23 +00:00
{
int64_t file_size ;
/* get the file size, if possible */
if ( ic -> iformat -> flags & AVFMT_NOFILE ) {
file_size = 0 ;
} else {
2007-11-21 07:41:00 +00:00
file_size = url_fsize ( ic -> pb );
2003-08-08 18:02:23 +00:00
if ( file_size < 0 )
file_size = 0 ;
}
ic -> file_size = file_size ;
2006-07-10 21:14:37 +00:00
if (( ! strcmp ( ic -> iformat -> name , "mpeg" ) ||
! strcmp ( ic -> iformat -> name , "mpegts" )) &&
2007-12-19 23:26:18 +00:00
file_size && ! url_is_streamed ( ic -> pb )) {
2003-08-08 18:02:23 +00:00
/* get accurate estimate from the PTSes */
2007-02-05 02:08:57 +00:00
av_estimate_timings_from_pts ( ic , old_offset );
2007-09-05 16:47:48 +00:00
} else if ( av_has_duration ( ic )) {
2008-01-16 22:14:26 +00:00
/* at least one component has timings - we use them for all
2003-08-08 18:02:23 +00:00
the components */
fill_all_stream_timings ( ic );
} else {
2008-01-16 22:14:26 +00:00
/* less precise: use bitrate info */
2003-08-08 18:02:23 +00: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 18:14:38 +00:00
printf("%d: start_time: %0.3f duration: %0.3f\n",
i, (double)st->start_time / AV_TIME_BASE,
2003-08-08 18:02:23 +00:00
(double)st->duration / AV_TIME_BASE);
}
2005-12-17 18:14:38 +00: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 18:02:23 +00:00
(double)ic->duration / AV_TIME_BASE,
ic->bit_rate / 1000);
}
#endif
}
2002-05-20 16:28:47 +00: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 18:29:06 +00:00
val = enc -> width && enc -> pix_fmt != PIX_FMT_NONE ;
2002-05-20 16:28:47 +00:00
break ;
default :
val = 1 ;
break ;
}
2007-10-01 22:11:10 +00:00
return ( enc -> codec_id != CODEC_ID_NONE && val != 0 );
2002-05-20 16:28:47 +00:00
}
2003-11-10 18:37:55 +00:00
static int try_decode_frame ( AVStream * st , const uint8_t * data , int size )
{
int16_t * samples ;
AVCodec * codec ;
2007-02-27 13:07:38 +00:00
int got_picture , data_size , ret = 0 ;
2003-11-10 18:37:55 +00:00
AVFrame picture ;
2005-12-17 18:14:38 +00:00
2005-07-17 22:24:36 +00:00
if ( ! st -> codec -> codec ){
codec = avcodec_find_decoder ( st -> codec -> codec_id );
2003-11-10 18:37:55 +00:00
if ( ! codec )
return - 1 ;
2005-07-17 22:24:36 +00:00
ret = avcodec_open ( st -> codec , codec );
2003-11-10 18:37:55 +00:00
if ( ret < 0 )
return ret ;
2005-06-27 20:54:36 +00:00
}
2005-04-25 18:29:06 +00:00
2005-07-17 22:24:36 +00:00
if ( ! has_codec_parameters ( st -> codec )){
switch ( st -> codec -> codec_type ) {
2003-11-10 18:37:55 +00:00
case CODEC_TYPE_VIDEO :
2005-12-17 18:14:38 +00:00
ret = avcodec_decode_video ( st -> codec , & picture ,
2008-02-02 22:55:58 +00:00
& got_picture , data , size );
2003-11-10 18:37:55 +00:00
break ;
case CODEC_TYPE_AUDIO :
2007-02-27 13:07:38 +00:00
data_size = FFMAX ( size , AVCODEC_MAX_AUDIO_FRAME_SIZE );
samples = av_malloc ( data_size );
2003-11-10 18:37:55 +00:00
if ( ! samples )
goto fail ;
2007-02-27 13:07:38 +00:00
ret = avcodec_decode_audio2 ( st -> codec , samples ,
2008-02-02 22:55:58 +00:00
& data_size , data , size );
2003-11-10 18:37:55 +00:00
av_free ( samples );
break ;
default :
break ;
}
2005-04-25 18:29:06 +00:00
}
2003-11-10 18:37:55 +00:00
fail :
return ret ;
}
2007-04-12 08:11:33 +00: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 09:18:41 +00:00
return !! fmt ;
2007-04-12 08:11:33 +00:00
}
2007-07-11 12:45:14 +00: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 11:36:17 +00: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 12:45:14 +00: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 18:37:55 +00:00
/* absolute maximum size we read until we abort */
#define MAX_READ_SIZE 5000000
2006-12-12 14:07:46 +00:00
#define MAX_STD_TIMEBASES (60*12+5)
2006-12-11 16:59:10 +00:00
static int get_std_framerate ( int i ){
if ( i < 60 * 12 ) return i * 1001 ;
2006-12-12 14:07:46 +00:00
else return (( int []){ 24 , 30 , 60 , 12 , 15 })[ i - 60 * 12 ] * 1000 * 12 ;
2006-12-11 16:59:10 +00:00
}
2007-12-27 00:16:48 +00: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-16 22:14:26 +00:00
* Old DivX and Xvid often have nonsense timebases like 1fps or 2fps.
* MPEG-2 commonly misuses field repeat flags to store different framerates.
2007-12-27 00:16:48 +00: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 16:28:47 +00:00
int av_find_stream_info ( AVFormatContext * ic )
{
2006-02-02 20:54:41 +00:00
int i , count , ret , read_size , j ;
2002-05-20 16:28:47 +00:00
AVStream * st ;
2003-11-10 18:37:55 +00:00
AVPacket pkt1 , * pkt ;
2004-12-19 01:23:22 +00:00
int64_t last_dts [ MAX_STREAMS ];
2005-05-06 23:41:47 +00:00
int duration_count [ MAX_STREAMS ] = { 0 };
2007-03-02 13:23:06 +00:00
double ( * duration_error )[ MAX_STD_TIMEBASES ];
2007-11-21 07:41:00 +00:00
offset_t old_offset = url_ftell ( ic -> pb );
2007-03-12 10:59:47 +00:00
int64_t codec_info_duration [ MAX_STREAMS ] = { 0 };
int codec_info_nb_frames [ MAX_STREAMS ] = { 0 };
2007-04-12 08:11:33 +00:00
AVProbeData probe_data [ MAX_STREAMS ];
int codec_identified [ MAX_STREAMS ] = { 0 };
2002-05-20 16:28:47 +00:00
2007-03-02 13:23:06 +00:00
duration_error = av_mallocz ( MAX_STREAMS * sizeof ( * duration_error ));
2007-07-19 15:21:30 +00:00
if ( ! duration_error ) return AVERROR ( ENOMEM );
2007-03-02 13:23:06 +00:00
2005-04-30 21:43:59 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2005-07-17 22:24:36 +00:00
if ( st -> codec -> codec_type == CODEC_TYPE_VIDEO ){
2005-04-30 21:43:59 +00:00
/* if(!st->time_base.num)
st->time_base= */
2005-07-17 22:24:36 +00:00
if ( ! st -> codec -> time_base . num )
st -> codec -> time_base = st -> time_base ;
2005-04-30 21:43:59 +00:00
}
2005-06-27 00:04:03 +00:00
//only for the split stuff
if ( ! st -> parser ) {
2005-07-17 22:24:36 +00:00
st -> parser = av_parser_init ( st -> codec -> codec_id );
2007-04-15 13:51:57 +00:00
if ( st -> need_parsing == AVSTREAM_PARSE_HEADERS && st -> parser ){
2005-08-15 15:58:21 +00:00
st -> parser -> flags |= PARSER_FLAG_COMPLETE_FRAMES ;
}
2005-06-27 00:04:03 +00:00
}
2005-04-30 21:43:59 +00:00
}
2004-12-19 01:23:22 +00:00
for ( i = 0 ; i < MAX_STREAMS ; i ++ ){
last_dts [ i ] = AV_NOPTS_VALUE ;
}
2005-12-17 18:14:38 +00:00
2007-04-12 08:11:33 +00:00
memset ( probe_data , 0 , sizeof ( probe_data ));
2002-05-20 16:28:47 +00: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-17 22:24:36 +00:00
if ( ! has_codec_parameters ( st -> codec ))
2002-05-20 16:28:47 +00:00
break ;
2004-12-21 02:16:11 +00:00
/* variable fps and no guess at the real fps */
2007-12-27 00:16:48 +00:00
if ( tb_unreliable ( st -> codec )
2005-07-17 22:24:36 +00:00
&& duration_count [ i ] < 20 && st -> codec -> codec_type == CODEC_TYPE_VIDEO )
2004-12-21 02:16:11 +00:00
break ;
2005-07-17 22:24:36 +00:00
if ( st -> parser && st -> parser -> parser -> split && ! st -> codec -> extradata )
2005-06-27 00:04:03 +00:00
break ;
2007-08-04 22:46:13 +00:00
if ( st -> first_dts == AV_NOPTS_VALUE )
break ;
2002-05-20 16:28:47 +00: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 18:37:55 +00:00
if ( ! ( ic -> ctx_flags & AVFMTCTX_NOHEADER )) {
2002-05-20 16:28:47 +00:00
/* if we found the info for all the codecs, we can stop */
ret = count ;
break ;
}
2006-09-26 17:25:28 +00:00
}
2006-09-26 17:27:08 +00: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 16:28:47 +00:00
2003-11-10 18:37:55 +00: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 02:30:45 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2006-03-21 11:29:50 +00: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 19:02:15 +00:00
} else {
ret = 0 ;
2006-03-21 11:29:50 +00:00
}
2005-01-22 02:30:45 +00:00
}
2003-11-10 18:37:55 +00:00
break ;
}
2007-08-03 08:56:00 +00:00
pkt = add_to_pktbuf ( ic , & pkt1 );
if ( av_dup_packet ( pkt ) < 0 )
return AVERROR ( ENOMEM );
2003-11-10 18:37:55 +00:00
2002-05-20 16:28:47 +00:00
read_size += pkt -> size ;
st = ic -> streams [ pkt -> stream_index ];
2007-03-12 10:59:47 +00:00
if ( codec_info_nb_frames [ st -> index ] > 1 )
codec_info_duration [ st -> index ] += pkt -> duration ;
2003-11-10 18:37:55 +00:00
if ( pkt -> duration != 0 )
2007-03-12 10:59:47 +00:00
codec_info_nb_frames [ st -> index ] ++ ;
2003-11-10 18:37:55 +00:00
2005-05-22 08:47:09 +00:00
{
2005-05-06 23:41:47 +00: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 16:59:10 +00: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 20:32:01 +00:00
if ( duration_count [ index ] < 2 )
2008-03-06 17:44:42 +00:00
memset ( duration_error [ index ], 0 , sizeof ( * duration_error ));
2007-01-02 20:35:46 +00: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 16:59:10 +00:00
duration_count [ index ] ++ ;
2004-12-19 01:23:22 +00:00
}
2006-12-12 14:07:46 +00:00
if ( last == AV_NOPTS_VALUE || duration_count [ index ] <= 1 )
last_dts [ pkt -> stream_index ] = pkt -> dts ;
2007-04-12 08:11:33 +00:00
if ( st -> codec -> codec_id == CODEC_ID_NONE ) {
AVProbeData * pd = & ( probe_data [ st -> index ]);
2007-09-03 05:19:59 +00:00
pd -> buf = av_realloc ( pd -> buf , pd -> buf_size + pkt -> size + AVPROBE_PADDING_SIZE );
2007-04-12 08:11:33 +00:00
memcpy ( pd -> buf + pd -> buf_size , pkt -> data , pkt -> size );
pd -> buf_size += pkt -> size ;
2007-09-03 05:19:59 +00:00
memset ( pd -> buf + pd -> buf_size , 0 , AVPROBE_PADDING_SIZE );
2007-04-12 08:11:33 +00:00
}
2004-12-19 01:23:22 +00:00
}
2005-07-17 22:24:36 +00: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 00:04:03 +00:00
if ( i ){
2005-07-17 22:24:36 +00:00
st -> codec -> extradata_size = i ;
2006-06-29 19:42:34 +00:00
st -> codec -> extradata = av_malloc ( st -> codec -> extradata_size + FF_INPUT_BUFFER_PADDING_SIZE );
2005-07-17 22:24:36 +00:00
memcpy ( st -> codec -> extradata , pkt -> data , st -> codec -> extradata_size );
2006-06-29 19:42:34 +00:00
memset ( st -> codec -> extradata + i , 0 , FF_INPUT_BUFFER_PADDING_SIZE );
2005-06-27 00:04:03 +00:00
}
}
2005-12-17 18:14:38 +00:00
2003-11-10 18:37:55 +00: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-16 22:14:26 +00:00
it takes longer and uses more memory. For MPEG-4, we need to
decompress for QuickTime. */
2005-07-17 22:24:36 +00: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 18:37:55 +00:00
try_decode_frame ( st , pkt -> data , pkt -> size );
2005-12-17 18:14:38 +00:00
2007-07-14 12:42:57 +00: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 18:37:55 +00:00
break ;
2002-05-20 16:28:47 +00:00
}
count ++ ;
}
2008-03-15 16:15:47 +00:00
// close codecs which were opened in try_decode_frame()
2005-06-27 20:54:36 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2005-07-17 22:24:36 +00:00
if ( st -> codec -> codec )
avcodec_close ( st -> codec );
2005-06-27 20:54:36 +00:00
}
2002-05-20 16:28:47 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2005-07-17 22:24:36 +00: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 01:23:22 +00:00
2007-01-02 20:32:01 +00:00
if ( duration_count [ i ]
2007-12-27 00:16:48 +00:00
&& tb_unreliable ( st -> codec ) /*&&
2008-01-16 22:14:26 +00:00
//FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ...
2006-12-11 16:59:10 +00: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 ;
2004-12-21 02:27:40 +00:00
2006-12-11 16:59:10 +00:00
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 20:54:41 +00:00
if ( error < best_error ){
best_error = error ;
2006-12-11 16:59:10 +00:00
av_reduce ( & st -> r_frame_rate . num , & st -> r_frame_rate . den , get_std_framerate ( j ), 12 * 1001 , INT_MAX );
2006-02-02 20:54:41 +00:00
}
2005-05-06 23:41:47 +00:00
}
2004-12-19 01:23:22 +00:00
}
2005-04-30 21:43:59 +00:00
if ( ! st -> r_frame_rate . num ){
2006-10-03 19:13:27 +00: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 15:16:19 +00:00
}
2007-02-20 16:18:59 +00:00
} else if ( st -> codec -> codec_type == CODEC_TYPE_AUDIO ) {
2007-06-10 20:35:01 +00:00
if ( st -> codec -> codec_id == CODEC_ID_NONE && probe_data [ st -> index ]. buf_size > 0 ) {
2007-07-25 20:39:43 +00:00
codec_identified [ st -> index ] = set_codec_from_probe_data ( st , & ( probe_data [ st -> index ]), 1 );
2007-04-12 08:11:33 +00:00
if ( codec_identified [ st -> index ]) {
2007-04-15 13:51:57 +00:00
st -> need_parsing = AVSTREAM_PARSE_FULL ;
2007-04-12 08:11:33 +00:00
}
}
2007-02-20 16:18:59 +00:00
if ( ! st -> codec -> bits_per_sample )
st -> codec -> bits_per_sample = av_get_bits_per_sample ( st -> codec -> codec_id );
2002-05-20 16:28:47 +00:00
}
}
2007-02-05 02:08:57 +00:00
av_estimate_timings ( ic , old_offset );
2007-04-12 08:11:33 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ ) {
st = ic -> streams [ i ];
2007-08-06 21:14:29 +00: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 08:11:33 +00:00
}
2007-11-21 07:41:00 +00:00
url_fseek ( ic -> pb , ic -> data_offset , SEEK_SET );
2007-04-12 08:11:33 +00:00
}
2004-05-29 02:06:32 +00:00
#if 0
2008-01-16 22:14:26 +00:00
/* correct DTS for B-frame streams with no timestamps */
2004-05-29 02:06:32 +00:00
for(i=0;i<ic->nb_streams;i++) {
st = ic->streams[i];
2005-07-17 22:24:36 +00:00
if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
2004-05-29 02:06:32 +00: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 13:23:06 +00:00
av_free ( duration_error );
2007-04-12 08:11:33 +00:00
for ( i = 0 ; i < MAX_STREAMS ; i ++ ){
av_freep ( & ( probe_data [ i ]. buf ));
}
2007-03-02 13:23:06 +00:00
2002-05-20 16:28:47 +00:00
return ret ;
}
2003-11-10 18:37:55 +00:00
/*******************************************************/
int av_read_play ( AVFormatContext * s )
{
2007-12-17 09:28:46 +00:00
if ( s -> iformat -> read_play )
return s -> iformat -> read_play ( s );
2007-12-20 00:25:18 +00:00
if ( s -> pb )
2007-12-19 20:57:13 +00:00
return av_url_read_fpause ( s -> pb , 0 );
2007-12-17 09:28:46 +00:00
return AVERROR ( ENOSYS );
2003-11-10 18:37:55 +00:00
}
int av_read_pause ( AVFormatContext * s )
{
2007-12-17 09:28:46 +00:00
if ( s -> iformat -> read_pause )
return s -> iformat -> read_pause ( s );
2007-12-20 00:25:18 +00:00
if ( s -> pb )
2007-12-19 20:57:13 +00:00
return av_url_read_fpause ( s -> pb , 1 );
2007-12-17 09:28:46 +00:00
return AVERROR ( ENOSYS );
2003-11-10 18:37:55 +00:00
}
2007-12-19 14:07:13 +00:00
void av_close_input_stream ( AVFormatContext * s )
2001-07-22 14:18:56 +00:00
{
2007-12-17 19:12:43 +00:00
int i ;
2003-10-29 14:20:56 +00:00
AVStream * st ;
2001-07-22 14:18:56 +00:00
2003-11-10 18:37:55 +00:00
/* free previous packet */
if ( s -> cur_st && s -> cur_st -> parser )
2005-12-17 18:14:38 +00:00
av_free_packet ( & s -> cur_pkt );
2003-11-10 18:37:55 +00:00
2002-05-20 16:28:47 +00:00
if ( s -> iformat -> read_close )
s -> iformat -> read_close ( s );
2001-07-22 14:18:56 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
2003-10-29 14:20:56 +00:00
/* free all data in a stream component */
st = s -> streams [ i ];
2003-11-10 18:37:55 +00:00
if ( st -> parser ) {
av_parser_close ( st -> parser );
}
av_free ( st -> index_entries );
2006-06-16 07:54:37 +00:00
av_free ( st -> codec -> extradata );
2005-07-17 22:24:36 +00:00
av_free ( st -> codec );
2008-01-27 15:43:17 +00:00
av_free ( st -> filename );
2003-10-29 14:20:56 +00:00
av_free ( st );
2001-07-22 14:18:56 +00:00
}
2007-09-25 20:45:46 +00: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 08:25:13 +00:00
av_freep ( & s -> programs [ i ] -> stream_index );
2007-09-25 20:45:46 +00:00
av_freep ( & s -> programs [ i ]);
}
2003-11-10 18:37:55 +00:00
flush_packet_queue ( s );
2002-05-24 02:09:40 +00:00
av_freep ( & s -> priv_data );
2002-05-18 23:11:09 +00:00
av_free ( s );
2001-07-22 14:18:56 +00:00
}
2007-12-19 14:07:13 +00: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 16:28:47 +00:00
AVStream * av_new_stream ( AVFormatContext * s , int id )
{
AVStream * st ;
2006-08-30 21:18:17 +00:00
int i ;
2001-07-22 14:18:56 +00:00
2002-05-20 16:28:47 +00:00
if ( s -> nb_streams >= MAX_STREAMS )
return NULL ;
st = av_mallocz ( sizeof ( AVStream ));
if ( ! st )
return NULL ;
2005-12-17 18:14:38 +00:00
2005-07-17 22:24:36 +00:00
st -> codec = avcodec_alloc_context ();
2003-08-08 18:13:43 +00:00
if ( s -> iformat ) {
/* no default bitrate if decoding */
2005-07-17 22:24:36 +00:00
st -> codec -> bit_rate = 0 ;
2003-08-08 18:13:43 +00:00
}
2002-05-20 16:28:47 +00:00
st -> index = s -> nb_streams ;
st -> id = id ;
2003-08-08 18:02:23 +00:00
st -> start_time = AV_NOPTS_VALUE ;
st -> duration = AV_NOPTS_VALUE ;
2004-05-29 02:06:32 +00:00
st -> cur_dts = AV_NOPTS_VALUE ;
2007-08-04 22:46:13 +00:00
st -> first_dts = AV_NOPTS_VALUE ;
2004-05-21 20:43:21 +00:00
2008-01-16 22:14:26 +00:00
/* default pts setting is MPEG-like */
2004-05-21 20:43:21 +00:00
av_set_pts_info ( st , 33 , 1 , 90000 );
2008-02-20 20:24:38 +00:00
st -> last_IP_pts = AV_NOPTS_VALUE ;
2006-08-30 21:18:17 +00:00
for ( i = 0 ; i < MAX_REORDER_DELAY + 1 ; i ++ )
st -> pts_buffer [ i ] = AV_NOPTS_VALUE ;
2004-05-21 20:43:21 +00:00
2002-05-20 16:28:47 +00:00
s -> streams [ s -> nb_streams ++ ] = st ;
return st ;
}
2007-09-25 20:45:46 +00: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 16:28:47 +00:00
/************************************************************/
/* output media file */
2003-01-11 05:02:14 +00:00
int av_set_parameters ( AVFormatContext * s , AVFormatParameters * ap )
{
int ret ;
2005-12-17 18:14:38 +00:00
2003-01-23 22:00:57 +00: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 15:21:30 +00:00
return AVERROR ( ENOMEM );
2003-01-23 22:00:57 +00:00
} else
s -> priv_data = NULL ;
2005-12-17 18:14:38 +00:00
2003-01-11 05:02:14 +00:00
if ( s -> oformat -> set_parameters ) {
ret = s -> oformat -> set_parameters ( s , ap );
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2002-05-20 16:28:47 +00:00
int av_write_header ( AVFormatContext * s )
{
2002-10-21 17:40:23 +00:00
int ret , i ;
AVStream * st ;
2005-08-14 16:19:20 +00: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 12:31:58 +00:00
if ( s -> oformat -> codec_tag ){
if ( st -> codec -> codec_tag ){
//FIXME
//check that tag + id is in the table
2008-01-16 22:14:26 +00:00
//if neither is in the table -> OK
2007-01-21 12:31:58 +00: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 16:19:20 +00:00
}
2007-01-08 14:22:00 +00:00
if ( ! s -> priv_data && s -> oformat -> priv_data_size > 0 ) {
2007-01-08 12:57:08 +00:00
s -> priv_data = av_mallocz ( s -> oformat -> priv_data_size );
if ( ! s -> priv_data )
2007-07-19 15:21:30 +00:00
return AVERROR ( ENOMEM );
2007-01-08 14:22:00 +00:00
}
2007-01-08 12:57:08 +00:00
2005-11-04 23:50:11 +00:00
if ( s -> oformat -> write_header ){
ret = s -> oformat -> write_header ( s );
if ( ret < 0 )
return ret ;
}
2002-10-21 17:40:23 +00:00
/* init PTS generation */
for ( i = 0 ; i < s -> nb_streams ; i ++ ) {
2005-08-14 16:37:29 +00:00
int64_t den = AV_NOPTS_VALUE ;
2002-10-21 17:40:23 +00:00
st = s -> streams [ i ];
2005-07-17 22:24:36 +00:00
switch ( st -> codec -> codec_type ) {
2002-10-21 17:40:23 +00:00
case CODEC_TYPE_AUDIO :
2005-08-14 16:37:29 +00:00
den = ( int64_t ) st -> time_base . num * st -> codec -> sample_rate ;
2002-10-21 17:40:23 +00:00
break ;
case CODEC_TYPE_VIDEO :
2005-08-14 16:37:29 +00:00
den = ( int64_t ) st -> time_base . num * st -> codec -> time_base . den ;
2002-10-21 17:40:23 +00:00
break ;
default :
break ;
}
2005-08-14 16:37:29 +00:00
if ( den != AV_NOPTS_VALUE ) {
if ( den <= 0 )
return AVERROR_INVALIDDATA ;
av_frac_init ( & st -> pts , 0 , 0 , den );
}
2002-10-21 17:40:23 +00:00
}
return 0 ;
2002-05-20 16:28:47 +00:00
}
2004-05-29 18:50:31 +00:00
//FIXME merge with compute_pkt_fields
2004-12-14 16:19:26 +00:00
static int compute_pkt_fields2 ( AVStream * st , AVPacket * pkt ){
2006-08-30 21:18:17 +00:00
int delay = FFMAX ( st -> codec -> has_b_frames , !! st -> codec -> max_b_frames );
int num , den , frame_size , i ;
2002-10-21 17:40:23 +00:00
2006-11-01 22:39:58 +00: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 18:14:38 +00:00
2004-05-29 02:06:32 +00:00
/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
return -1;*/
2005-12-17 18:14:38 +00:00
2004-05-29 02:06:32 +00:00
/* duration field */
2004-05-29 18:50:31 +00: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 02:06:32 +00:00
//XXX/FIXME this is a temporary hack until all encoders output pts
2006-08-30 21:18:17 +00:00
if (( pkt -> pts == 0 || pkt -> pts == AV_NOPTS_VALUE ) && pkt -> dts == AV_NOPTS_VALUE && ! delay ){
2004-05-29 02:06:32 +00:00
pkt -> dts =
// pkt->pts= st->cur_dts;
pkt -> pts = st -> pts . val ;
}
2005-12-17 18:14:38 +00:00
//calculate dts from pts
2004-05-29 02:06:32 +00:00
if ( pkt -> pts != AV_NOPTS_VALUE && pkt -> dts == AV_NOPTS_VALUE ){
2006-08-30 21:18:17 +00: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 21:28:36 +00:00
FFSWAP ( int64_t , st -> pts_buffer [ i ], st -> pts_buffer [ i + 1 ]);
2006-08-30 21:18:17 +00:00
pkt -> dts = st -> pts_buffer [ 0 ];
2004-05-29 02:06:32 +00:00
}
2005-12-17 18:14:38 +00:00
2004-12-14 16:19:26 +00:00
if ( st -> cur_dts && st -> cur_dts != AV_NOPTS_VALUE && st -> cur_dts >= pkt -> dts ){
2007-04-26 10:49:48 +00:00
av_log ( NULL , AV_LOG_ERROR , "error, non monotone timestamps %" PRId64 " >= %" PRId64 " \n " , st -> cur_dts , pkt -> dts );
2004-12-14 16:19:26 +00:00
return - 1 ;
}
if ( pkt -> dts != AV_NOPTS_VALUE && pkt -> pts != AV_NOPTS_VALUE && pkt -> pts < pkt -> dts ){
2007-04-26 10:49:48 +00:00
av_log ( NULL , AV_LOG_ERROR , "error, pts < dts \n " );
2004-12-14 16:19:26 +00:00
return - 1 ;
}
2006-11-01 22:39:58 +00:00
// av_log(NULL, AV_LOG_DEBUG, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n", pkt->pts, pkt->dts);
2004-05-29 02:06:32 +00:00
st -> cur_dts = pkt -> dts ;
st -> pts . val = pkt -> dts ;
2002-10-21 17:40:23 +00:00
/* update pts */
2005-07-17 22:24:36 +00:00
switch ( st -> codec -> codec_type ) {
2002-10-21 17:40:23 +00:00
case CODEC_TYPE_AUDIO :
2005-07-17 22:24:36 +00:00
frame_size = get_audio_frame_size ( st -> codec , pkt -> size );
2004-04-04 14:39:20 +00:00
2008-01-16 22:14:26 +00: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 02:06:32 +00:00
if ( frame_size >= 0 && ( pkt -> size || st -> pts . num != st -> pts . den >> 1 || st -> pts . val )) {
2004-05-21 20:43:21 +00:00
av_frac_add ( & st -> pts , ( int64_t ) st -> time_base . den * frame_size );
2002-11-19 18:30:03 +00:00
}
2002-10-21 17:40:23 +00:00
break ;
case CODEC_TYPE_VIDEO :
2005-07-17 22:24:36 +00:00
av_frac_add ( & st -> pts , ( int64_t ) st -> time_base . den * st -> codec -> time_base . num );
2002-10-21 17:40:23 +00:00
break ;
default :
break ;
}
2004-12-14 16:19:26 +00:00
return 0 ;
2004-05-29 18:50:31 +00:00
}
static void truncate_ts ( AVStream * st , AVPacket * pkt ){
int64_t pts_mask = ( 2LL << ( st -> pts_wrap_bits - 1 )) - 1 ;
2005-12-17 18:14:38 +00:00
2004-10-03 12:58:14 +00:00
// if(pkt->dts < 0)
2008-01-16 22:14:26 +00: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 18:14:38 +00:00
2006-12-06 17:17:33 +00:00
if ( pkt -> pts != AV_NOPTS_VALUE )
2006-12-06 15:46:12 +00:00
pkt -> pts &= pts_mask ;
2006-12-06 17:17:33 +00:00
if ( pkt -> dts != AV_NOPTS_VALUE )
2006-12-06 15:46:12 +00:00
pkt -> dts &= pts_mask ;
2004-05-29 18:50:31 +00:00
}
int av_write_frame ( AVFormatContext * s , AVPacket * pkt )
{
2004-10-08 20:09:52 +00:00
int ret ;
2004-12-14 16:19:26 +00:00
ret = compute_pkt_fields2 ( s -> streams [ pkt -> stream_index ], pkt );
2006-08-08 20:31:19 +00:00
if ( ret < 0 && ! ( s -> oformat -> flags & AVFMT_NOTIMESTAMPS ))
2004-12-14 16:19:26 +00:00
return ret ;
2005-12-17 18:14:38 +00:00
2004-05-29 18:50:31 +00:00
truncate_ts ( s -> streams [ pkt -> stream_index ], pkt );
2004-10-08 20:09:52 +00:00
ret = s -> oformat -> write_packet ( s , pkt );
if ( ! ret )
2007-11-21 07:41:00 +00:00
ret = url_ferror ( s -> pb );
2004-10-08 20:09:52 +00:00
return ret ;
2004-05-29 18:50:31 +00:00
}
2006-08-11 21:21:51 +00:00
int av_interleave_packet_per_dts ( AVFormatContext * s , AVPacket * out , AVPacket * pkt , int flush ){
2004-05-29 18:50:31 +00:00
AVPacketList * pktl , ** next_point , * this_pktl ;
int stream_count = 0 ;
int streams [ MAX_STREAMS ];
2004-09-29 23:25:01 +00:00
if ( pkt ){
AVStream * st = s -> streams [ pkt -> stream_index ];
2004-05-29 18:50:31 +00:00
2005-06-29 08:48:26 +00:00
// assert(pkt->destruct != av_destruct_packet); //FIXME
2004-05-29 18:50:31 +00:00
2004-09-29 23:25:01 +00:00
this_pktl = av_mallocz ( sizeof ( AVPacketList ));
this_pktl -> pkt = * pkt ;
2005-06-29 08:48:26 +00:00
if ( pkt -> destruct == av_destruct_packet )
2008-01-16 22:14:26 +00:00
pkt -> destruct = NULL ; // not shared -> must keep original from being freed
2005-06-29 08:48:26 +00:00
else
av_dup_packet ( & this_pktl -> pkt ); //shared -> must dup
2004-05-29 18:50:31 +00:00
2004-09-29 23:25:01 +00: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 ;
2004-05-29 18:50:31 +00:00
}
2005-12-17 18:14:38 +00:00
2004-05-29 18:50:31 +00:00
memset ( streams , 0 , sizeof ( streams ));
pktl = s -> packet_buffer ;
while ( pktl ){
2006-11-01 22:39:58 +00:00
//av_log(s, AV_LOG_DEBUG, "show st:%d dts:%"PRId64"\n", pktl->pkt.stream_index, pktl->pkt.dts);
2004-05-29 18:50:31 +00:00
if ( streams [ pktl -> pkt . stream_index ] == 0 )
stream_count ++ ;
streams [ pktl -> pkt . stream_index ] ++ ;
pktl = pktl -> next ;
}
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
if ( s -> nb_streams == stream_count || ( flush && stream_count )){
2004-05-29 18:50:31 +00:00
pktl = s -> packet_buffer ;
2004-09-29 23:25:01 +00:00
* out = pktl -> pkt ;
2005-12-17 18:14:38 +00:00
s -> packet_buffer = pktl -> next ;
2004-05-29 18:50:31 +00:00
av_freep ( & pktl );
2004-09-29 23:25:01 +00:00
return 1 ;
} else {
av_init_packet ( out );
return 0 ;
}
}
/**
2008-01-16 22:14:26 +00:00
* Interleaves an AVPacket correctly so it can be muxed.
2004-09-29 23:25:01 +00: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 18:14:38 +00:00
* @return 1 if a packet was output, 0 if no packet could be output,
2008-03-22 01:06:57 +00:00
* < 0 if an error occurred
2004-09-29 23:25:01 +00:00
*/
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 );
}
int av_interleaved_write_frame ( AVFormatContext * s , AVPacket * pkt ){
AVStream * st = s -> streams [ pkt -> stream_index ];
//FIXME/XXX/HACK drop zero sized packets
2005-07-17 22:24:36 +00:00
if ( st -> codec -> codec_type == CODEC_TYPE_AUDIO && pkt -> size == 0 )
2004-09-29 23:25:01 +00:00
return 0 ;
2005-03-24 01:51:57 +00:00
2006-11-01 22:39:58 +00:00
//av_log(NULL, AV_LOG_DEBUG, "av_interleaved_write_frame %d %"PRId64" %"PRId64"\n", pkt->size, pkt->dts, pkt->pts);
2006-08-08 20:31:19 +00:00
if ( compute_pkt_fields2 ( st , pkt ) < 0 && ! ( s -> oformat -> flags & AVFMT_NOTIMESTAMPS ))
2005-03-24 01:51:57 +00:00
return - 1 ;
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
if ( pkt -> dts == AV_NOPTS_VALUE )
return - 1 ;
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 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
truncate_ts ( s -> streams [ opkt . stream_index ], & opkt );
ret = s -> oformat -> write_packet ( s , & opkt );
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
av_free_packet ( & opkt );
pkt = NULL ;
2005-12-17 18:14:38 +00:00
2004-05-29 18:50:31 +00:00
if ( ret < 0 )
return ret ;
2007-11-21 07:41:00 +00:00
if ( url_ferror ( s -> pb ))
return url_ferror ( s -> pb );
2004-05-29 18:50:31 +00:00
}
2002-05-20 16:28:47 +00:00
}
int av_write_trailer ( AVFormatContext * s )
{
2004-10-01 16:30:15 +00:00
int ret , i ;
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
for (;;){
AVPacket pkt ;
ret = av_interleave_packet ( s , & pkt , NULL , 1 );
if ( ret < 0 ) //FIXME cleanup needed for ret<0 ?
2004-10-01 16:30:15 +00:00
goto fail ;
2004-09-29 23:25:01 +00:00
if ( ! ret )
break ;
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
truncate_ts ( s -> streams [ pkt . stream_index ], & pkt );
ret = s -> oformat -> write_packet ( s , & pkt );
2005-12-17 18:14:38 +00:00
2004-09-29 23:25:01 +00:00
av_free_packet ( & pkt );
2005-12-17 18:14:38 +00:00
2004-05-29 18:50:31 +00:00
if ( ret < 0 )
2004-10-01 16:30:15 +00:00
goto fail ;
2007-11-21 07:41:00 +00:00
if ( url_ferror ( s -> pb ))
2004-10-08 20:09:52 +00:00
goto fail ;
2004-05-29 18:50:31 +00:00
}
2005-11-04 23:50:11 +00:00
if ( s -> oformat -> write_trailer )
ret = s -> oformat -> write_trailer ( s );
2004-10-01 16:30:15 +00:00
fail :
2004-10-08 20:09:52 +00:00
if ( ret == 0 )
2007-11-21 07:41:00 +00:00
ret = url_ferror ( s -> pb );
2004-10-01 16:30:15 +00:00
for ( i = 0 ; i < s -> nb_streams ; i ++ )
av_freep ( & s -> streams [ i ] -> priv_data );
2002-05-20 16:28:47 +00:00
av_freep ( & s -> priv_data );
return ret ;
2001-07-22 14:18:56 +00:00
}
2007-10-20 08:25:13 +00: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 14:18:56 +00:00
/* "user interface" functions */
2007-10-21 23:10:15 +00:00
static void dump_stream_format ( AVFormatContext * ic , int i , int index , int is_output )
2007-10-20 08:17:01 +00:00
{
2007-10-21 23:10:15 +00:00
char buf [ 256 ];
2007-10-20 08:17:01 +00: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-13 23:43:18 +00:00
av_log ( NULL , AV_LOG_INFO , ", %5.2f tb(r)" , av_q2d ( st -> r_frame_rate ));
2007-10-20 08:17:01 +00:00
/* else if(st->time_base.den && st->time_base.num)
2007-11-13 23:43:18 +00:00
av_log(NULL, AV_LOG_INFO, ", %5.2f tb(m)", 1/av_q2d(st->time_base));*/
2007-10-20 08:17:01 +00:00
else
2007-11-13 23:43:18 +00:00
av_log ( NULL , AV_LOG_INFO , ", %5.2f tb(c)" , 1 / av_q2d ( st -> codec -> time_base ));
2007-10-20 08:17:01 +00:00
}
av_log ( NULL , AV_LOG_INFO , " \n " );
}
2001-07-22 14:18:56 +00:00
void dump_format ( AVFormatContext * ic ,
2005-12-17 18:14:38 +00:00
int index ,
2001-07-22 14:18:56 +00:00
const char * url ,
int is_output )
{
2007-10-25 10:11:15 +00:00
int i ;
2001-07-22 14:18:56 +00:00
2005-12-17 18:14:38 +00:00
av_log ( NULL , AV_LOG_INFO , "%s #%d, %s, %s '%s': \n " ,
2001-07-22 14:18:56 +00:00
is_output ? "Output" : "Input" ,
2005-12-17 18:14:38 +00:00
index ,
is_output ? ic -> oformat -> name : ic -> iformat -> name ,
2001-07-22 14:18:56 +00:00
is_output ? "to" : "from" , url );
2003-08-08 18:02:23 +00:00
if ( ! is_output ) {
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , " Duration: " );
2003-08-08 18:02:23 +00: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 ;
2008-04-16 06:46:54 +00:00
av_log ( NULL , AV_LOG_INFO , "%02d:%02d:%02d.%02d" , hours , mins , secs ,
( 100 * us ) / AV_TIME_BASE );
2003-08-08 18:02:23 +00:00
} else {
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , "N/A" );
2003-08-08 18:02:23 +00:00
}
2004-10-11 17:12:52 +00:00
if ( ic -> start_time != AV_NOPTS_VALUE ) {
int secs , us ;
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , ", start: " );
2004-10-11 17:12:52 +00:00
secs = ic -> start_time / AV_TIME_BASE ;
us = ic -> start_time % AV_TIME_BASE ;
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , "%d.%06d" ,
2004-10-11 17:12:52 +00:00
secs , ( int ) av_rescale ( us , 1000000 , AV_TIME_BASE ));
}
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , ", bitrate: " );
2003-08-08 18:02:23 +00:00
if ( ic -> bit_rate ) {
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , "%d kb/s" , ic -> bit_rate / 1000 );
2003-08-08 18:02:23 +00:00
} else {
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , "N/A" );
2003-08-08 18:02:23 +00:00
}
2005-05-29 11:44:21 +00:00
av_log ( NULL , AV_LOG_INFO , " \n " );
2003-08-08 18:02:23 +00:00
}
2007-10-20 08:25:13 +00:00
if ( ic -> nb_programs ) {
int j , k ;
for ( j = 0 ; j < ic -> nb_programs ; j ++ ) {
2007-10-26 20:02:11 +00: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 08:25:13 +00:00
for ( k = 0 ; k < ic -> programs [ j ] -> nb_stream_indexes ; k ++ )
2007-10-21 23:10:15 +00:00
dump_stream_format ( ic , ic -> programs [ j ] -> stream_index [ k ], index , is_output );
2007-10-20 08:25:13 +00:00
}
} else
2007-10-20 08:17:01 +00:00
for ( i = 0 ; i < ic -> nb_streams ; i ++ )
2007-10-21 23:10:15 +00:00
dump_stream_format ( ic , i , index , is_output );
2001-07-22 14:18:56 +00:00
}
int parse_image_size ( int * width_ptr , int * height_ptr , const char * str )
{
2007-06-12 08:06:54 +00:00
return av_parse_video_frame_size ( width_ptr , height_ptr , str );
2001-07-22 14:18:56 +00:00
}
2007-06-12 08:06:54 +00:00
int parse_frame_rate ( int * frame_rate_num , int * frame_rate_den , const char * arg )
2003-07-12 07:37:05 +00:00
{
2007-06-12 08:06:54 +00: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 07:37:05 +00:00
}
2007-07-16 20:28:43 +00:00
/**
2008-01-16 22:14:26 +00:00
* Gets the current time in microseconds.
2007-07-16 20:28:43 +00: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 16:35:48 +00:00
int64_t parse_date ( const char * datestr , int duration )
2001-07-22 14:18:56 +00:00
{
const char * p ;
2003-02-11 16:35:48 +00:00
int64_t t ;
2002-06-14 03:38:00 +00:00
struct tm dt ;
2002-07-27 02:54:10 +00: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 15:54:49 +00:00
int is_utc , len ;
2002-07-27 02:54:10 +00:00
char lastch ;
2004-06-11 22:03:16 +00:00
int negative = 0 ;
2004-04-04 14:39:20 +00:00
#undef time
2002-07-27 02:54:10 +00:00
time_t now = time ( 0 );
2002-10-21 15:54:49 +00:00
len = strlen ( datestr );
if ( len > 0 )
lastch = datestr [ len - 1 ];
else
lastch = '\0' ;
2002-07-27 02:54:10 +00:00
is_utc = ( lastch == 'z' || lastch == 'Z' );
2002-06-14 03:38:00 +00:00
memset ( & dt , 0 , sizeof ( dt ));
2001-07-22 14:18:56 +00:00
p = datestr ;
2002-10-21 15:54:49 +00:00
q = NULL ;
2001-07-22 14:18:56 +00:00
if ( ! duration ) {
2007-09-18 08:26:10 +00:00
/* parse the year-month-day part */
2002-07-27 02:54:10 +00:00
for ( i = 0 ; i < sizeof ( date_fmt ) / sizeof ( date_fmt [ 0 ]); i ++ ) {
2003-09-08 21:20:55 +00:00
q = small_strptime ( p , date_fmt [ i ], & dt );
2002-07-27 02:54:10 +00:00
if ( q ) {
break ;
}
}
2007-09-18 08:26:10 +00:00
/* if the year-month-day part is missing, then take the
* current year-month-day time */
2002-07-27 02:54:10 +00: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 14:18:56 +00:00
} else {
2002-07-27 02:54:10 +00:00
p = q ;
}
if ( * p == 'T' || * p == 't' || * p == ' ' )
p ++ ;
2007-09-18 08:26:10 +00:00
/* parse the hour-minute-second part */
2002-10-21 15:54:49 +00:00
for ( i = 0 ; i < sizeof ( time_fmt ) / sizeof ( time_fmt [ 0 ]); i ++ ) {
2003-09-08 21:20:55 +00:00
q = small_strptime ( p , time_fmt [ i ], & dt );
2002-10-21 15:54:49 +00:00
if ( q ) {
break ;
}
}
} else {
2007-09-18 08:26:10 +00:00
/* parse datestr as a duration */
2005-12-22 01:10:11 +00:00
if ( p [ 0 ] == '-' ) {
negative = 1 ;
++ p ;
}
2007-09-18 08:26:10 +00:00
/* parse datestr as HH:MM:SS */
2003-09-08 21:20:55 +00:00
q = small_strptime ( p , time_fmt [ 0 ], & dt );
2002-10-21 15:54:49 +00:00
if ( ! q ) {
2007-09-18 08:26:10 +00:00
/* parse datestr as S+ */
2002-10-21 15:54:49 +00:00
dt . tm_sec = strtol ( p , ( char ** ) & q , 10 );
2007-09-19 12:38:07 +00:00
if ( q == p )
/* the parsing didn't succeed */
return INT64_MIN ;
2002-10-21 15:54:49 +00:00
dt . tm_min = 0 ;
dt . tm_hour = 0 ;
2001-07-22 14:18:56 +00:00
}
}
2002-06-14 03:38:00 +00:00
2002-07-27 02:54:10 +00:00
/* Now we have all the fields that we can get */
if ( ! q ) {
2007-09-19 12:38:07 +00:00
return INT64_MIN ;
2001-07-22 14:18:56 +00:00
}
2002-06-14 03:38:00 +00:00
2002-07-27 02:54:10 +00:00
if ( duration ) {
t = dt . tm_hour * 3600 + dt . tm_min * 60 + dt . tm_sec ;
} else {
dt . tm_isdst = - 1 ; /* unknown */
if ( is_utc ) {
t = mktimegm ( & dt );
} else {
t = mktime ( & dt );
}
}
t *= 1000000 ;
2007-09-18 08:26:10 +00:00
/* parse the .m... part */
2002-07-27 02:54:10 +00:00
if ( * q == '.' ) {
2001-07-22 14:18:56 +00:00
int val , n ;
2002-07-27 02:54:10 +00:00
q ++ ;
for ( val = 0 , n = 100000 ; n >= 1 ; n /= 10 , q ++ ) {
2005-12-17 18:14:38 +00:00
if ( ! isdigit ( * q ))
2002-07-27 02:54:10 +00:00
break ;
val += n * ( * q - '0' );
2001-07-22 14:18:56 +00:00
}
t += val ;
}
2004-06-11 22:03:16 +00:00
return negative ? - t : t ;
2001-07-22 14:18:56 +00: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 03:38:00 +00:00
if (( q - arg ) < arg_size - 1 ) {
if ( * p == '+' )
* q ++ = ' ' ;
else
* q ++ = * p ;
}
2001-07-22 14:18:56 +00:00
p ++ ;
}
* q = '\0' ;
}
2005-12-17 18:14:38 +00:00
if ( ! strcmp ( tag , tag1 ))
2001-07-22 14:18:56 +00:00
return 1 ;
if ( * p != '&' )
break ;
2002-05-10 02:17:41 +00:00
p ++ ;
2001-07-22 14:18:56 +00:00
}
return 0 ;
}
2006-09-04 09:57:47 +00:00
int av_get_frame_filename ( char * buf , int buf_size ,
const char * path , int number )
2001-09-16 21:50:48 +00:00
{
const char * p ;
2003-10-26 10:49:49 +00:00
char * q , buf1 [ 20 ], c ;
int nd , len , percentd_found ;
2001-09-16 21:50:48 +00:00
q = buf ;
p = path ;
percentd_found = 0 ;
for (;;) {
c = * p ++ ;
if ( c == '\0' )
break ;
if ( c == '%' ) {
2002-12-11 03:20:05 +00:00
do {
nd = 0 ;
while ( isdigit ( * p )) {
nd = nd * 10 + * p ++ - '0' ;
}
c = * p ++ ;
} while ( isdigit ( c ));
2001-09-16 21:50:48 +00: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 14:17:26 +00:00
static void hex_dump_internal ( void * avcl , FILE * f , int level , uint8_t * buf , int size )
2002-05-20 16:28:47 +00:00
{
int len , i , j , c ;
2007-03-12 14:17:26 +00:00
#define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0)
2002-05-20 16:28:47 +00:00
for ( i = 0 ; i < size ; i += 16 ) {
len = size - i ;
if ( len > 16 )
len = 16 ;
2007-03-12 14:17:26 +00:00
PRINT ( "%08x " , i );
2002-05-20 16:28:47 +00:00
for ( j = 0 ; j < 16 ; j ++ ) {
if ( j < len )
2007-03-12 14:17:26 +00:00
PRINT ( " %02x" , buf [ i + j ]);
2002-05-20 16:28:47 +00:00
else
2007-03-12 14:17:26 +00:00
PRINT ( " " );
2002-05-20 16:28:47 +00:00
}
2007-03-12 14:17:26 +00:00
PRINT ( " " );
2002-05-20 16:28:47 +00:00
for ( j = 0 ; j < len ; j ++ ) {
c = buf [ i + j ];
if ( c < ' ' || c > '~' )
c = '.' ;
2007-03-12 14:17:26 +00:00
PRINT ( "%c" , c );
2002-05-20 16:28:47 +00:00
}
2007-03-12 14:17:26 +00:00
PRINT ( " \n " );
2002-05-20 16:28:47 +00:00
}
2007-03-12 14:17:26 +00: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 16:28:47 +00:00
}
2005-04-30 21:43:59 +00:00
//FIXME needs to know the time_base
2007-03-12 14:17:26 +00:00
static void pkt_dump_internal ( void * avcl , FILE * f , int level , AVPacket * pkt , int dump_payload )
2003-11-10 18:37:55 +00:00
{
2007-03-12 14:17:26 +00: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 14:45:37 +00:00
/* DTS is _always_ valid after av_read_frame() */
2007-03-12 14:17:26 +00:00
PRINT ( " dts=" );
2003-12-15 14:45:37 +00:00
if ( pkt -> dts == AV_NOPTS_VALUE )
2007-03-12 14:17:26 +00:00
PRINT ( "N/A" );
2003-12-15 14:45:37 +00:00
else
2007-03-12 14:17:26 +00:00
PRINT ( "%0.3f" , ( double ) pkt -> dts / AV_TIME_BASE );
2008-01-16 22:14:26 +00:00
/* PTS may not be known if B-frames are present. */
2007-03-12 14:17:26 +00:00
PRINT ( " pts=" );
2003-11-10 18:37:55 +00:00
if ( pkt -> pts == AV_NOPTS_VALUE )
2007-03-12 14:17:26 +00:00
PRINT ( "N/A" );
2003-11-10 18:37:55 +00:00
else
2007-03-12 14:17:26 +00:00
PRINT ( "%0.3f" , ( double ) pkt -> pts / AV_TIME_BASE );
PRINT ( " \n " );
PRINT ( " size=%d \n " , pkt -> size );
#undef PRINT
2003-11-10 18:37:55 +00:00
if ( dump_payload )
av_hex_dump ( f , pkt -> data , pkt -> size );
}
2007-03-12 14:17:26 +00: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 18:04:50 +00:00
void url_split ( char * proto , int proto_size ,
2004-08-12 00:09:32 +00:00
char * authorization , int authorization_size ,
2002-07-24 18:04:50 +00:00
char * hostname , int hostname_size ,
int * port_ptr ,
char * path , int path_size ,
const char * url )
{
2007-12-29 16:13:03 +00:00
const char * p , * ls , * at , * col , * brk ;
2002-07-24 18:04:50 +00:00
2007-09-27 19:18:07 +00: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 ;
2002-07-24 18:04:50 +00:00
2007-09-27 19:18:07 +00:00
/* 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 18:04:50 +00:00
} else {
2007-09-27 19:18:07 +00:00
/* no protocol means plain filename */
av_strlcpy ( path , url , path_size );
return ;
}
2004-08-12 00:09:32 +00:00
2007-09-27 19:18:07 +00:00
/* separate path from hostname */
2007-12-29 16:13:03 +00:00
ls = strchr ( p , '/' );
if ( ! ls )
ls = strchr ( p , '?' );
if ( ls )
2007-12-29 16:34:51 +00:00
av_strlcpy ( path , ls , path_size );
2007-12-29 16:13:03 +00:00
else
2007-09-27 19:18:07 +00:00
ls = & p [ strlen ( p )]; // XXX
2004-08-12 00:09:32 +00:00
2007-09-27 19:18:07 +00:00
/* 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 '@' */
}
2004-08-12 00:09:32 +00:00
2007-09-29 14:35:52 +00: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 18:04:50 +00:00
}
}
2004-05-21 20:43:21 +00:00
void av_set_pts_info ( AVStream * s , int pts_wrap_bits ,
2002-10-21 15:54:49 +00:00
int pts_num , int pts_den )
{
s -> pts_wrap_bits = pts_wrap_bits ;
2004-05-21 20:43:21 +00:00
s -> time_base . num = pts_num ;
s -> time_base . den = pts_den ;
2002-10-21 15:54:49 +00:00
}
/* fraction handling */
/**
2005-06-28 12:55:08 +00:00
* f = val + (num / den) + 0.5.
*
* 'num' is normalized so that it is such as 0 <= num < den.
2002-10-21 15:54:49 +00:00
*
* @param f fractional number
* @param val integer value
* @param num must be >= 0
2005-12-17 18:14:38 +00:00
* @param den must be >= 1
2002-10-21 15:54:49 +00:00
*/
2006-06-25 17:37:12 +00:00
static void av_frac_init ( AVFrac * f , int64_t val , int64_t num , int64_t den )
2002-10-21 15:54:49 +00:00
{
num += ( den >> 1 );
if ( num >= den ) {
val += num / den ;
num = num % den ;
}
f -> val = val ;
f -> num = num ;
f -> den = den ;
}
/**
2008-01-16 22:14:26 +00:00
* Fractional addition to f: f = f + (incr / f->den).
2002-10-21 15:54:49 +00:00
*
* @param f fractional number
* @param incr increment, can be positive or negative
*/
2006-06-25 17:37:12 +00:00
static void av_frac_add ( AVFrac * f , int64_t incr )
2002-10-21 15:54:49 +00:00
{
2003-02-11 16:35:48 +00:00
int64_t num , den ;
2002-10-21 15:54:49 +00: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 ;
}